]> git.proxmox.com Git - mirror_frr.git/commitdiff
Initial revision
authorpaul <paul>
Fri, 13 Dec 2002 20:15:29 +0000 (20:15 +0000)
committerpaul <paul>
Fri, 13 Dec 2002 20:15:29 +0000 (20:15 +0000)
420 files changed:
.cvsignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
COPYING.LIB [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
REPORTING-BUGS [new file with mode: 0644]
SERVICES [new file with mode: 0644]
TODO [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
bgpd/.cvsignore [new file with mode: 0644]
bgpd/BGP4-MIB.txt [new file with mode: 0644]
bgpd/ChangeLog [new file with mode: 0644]
bgpd/Makefile.am [new file with mode: 0644]
bgpd/Makefile.in [new file with mode: 0644]
bgpd/bgp_advertise.c [new file with mode: 0644]
bgpd/bgp_advertise.h [new file with mode: 0644]
bgpd/bgp_aspath.c [new file with mode: 0644]
bgpd/bgp_aspath.h [new file with mode: 0644]
bgpd/bgp_attr.c [new file with mode: 0644]
bgpd/bgp_attr.h [new file with mode: 0644]
bgpd/bgp_btoa.c [new file with mode: 0644]
bgpd/bgp_clist.c [new file with mode: 0644]
bgpd/bgp_clist.h [new file with mode: 0644]
bgpd/bgp_community.c [new file with mode: 0644]
bgpd/bgp_community.h [new file with mode: 0644]
bgpd/bgp_damp.c [new file with mode: 0644]
bgpd/bgp_damp.h [new file with mode: 0644]
bgpd/bgp_debug.c [new file with mode: 0644]
bgpd/bgp_debug.h [new file with mode: 0644]
bgpd/bgp_dump.c [new file with mode: 0644]
bgpd/bgp_dump.h [new file with mode: 0644]
bgpd/bgp_ecommunity.c [new file with mode: 0644]
bgpd/bgp_ecommunity.h [new file with mode: 0644]
bgpd/bgp_filter.c [new file with mode: 0644]
bgpd/bgp_filter.h [new file with mode: 0644]
bgpd/bgp_fsm.c [new file with mode: 0644]
bgpd/bgp_fsm.h [new file with mode: 0644]
bgpd/bgp_main.c [new file with mode: 0644]
bgpd/bgp_mplsvpn.c [new file with mode: 0644]
bgpd/bgp_mplsvpn.h [new file with mode: 0644]
bgpd/bgp_network.c [new file with mode: 0644]
bgpd/bgp_network.h [new file with mode: 0644]
bgpd/bgp_nexthop.c [new file with mode: 0644]
bgpd/bgp_nexthop.h [new file with mode: 0644]
bgpd/bgp_open.c [new file with mode: 0644]
bgpd/bgp_open.h [new file with mode: 0644]
bgpd/bgp_packet.c [new file with mode: 0644]
bgpd/bgp_packet.h [new file with mode: 0644]
bgpd/bgp_regex.c [new file with mode: 0644]
bgpd/bgp_regex.h [new file with mode: 0644]
bgpd/bgp_route.c [new file with mode: 0644]
bgpd/bgp_route.h [new file with mode: 0644]
bgpd/bgp_routemap.c [new file with mode: 0644]
bgpd/bgp_snmp.c [new file with mode: 0644]
bgpd/bgp_snmp.h [new file with mode: 0644]
bgpd/bgp_table.c [new file with mode: 0644]
bgpd/bgp_table.h [new file with mode: 0644]
bgpd/bgp_view.c [new file with mode: 0644]
bgpd/bgp_vty.c [new file with mode: 0644]
bgpd/bgp_vty.h [new file with mode: 0644]
bgpd/bgp_zebra.c [new file with mode: 0644]
bgpd/bgp_zebra.h [new file with mode: 0644]
bgpd/bgpd.c [new file with mode: 0644]
bgpd/bgpd.conf.sample [new file with mode: 0644]
bgpd/bgpd.conf.sample2 [new file with mode: 0644]
bgpd/bgpd.h [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.h.in [new file with mode: 0644]
config.sub [new file with mode: 0755]
configure [new file with mode: 0755]
configure.in [new file with mode: 0755]
depcomp [new file with mode: 0755]
doc/.cvsignore [new file with mode: 0644]
doc/BGP-TypeCode [new file with mode: 0644]
doc/ChangeLog [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/Makefile.in [new file with mode: 0644]
doc/appendix.texi [new file with mode: 0644]
doc/basic.texi [new file with mode: 0644]
doc/bgpd.8 [new file with mode: 0644]
doc/bgpd.texi [new file with mode: 0644]
doc/draft-zebra-00.ms [new file with mode: 0644]
doc/filter.texi [new file with mode: 0644]
doc/install.texi [new file with mode: 0644]
doc/ipv6.texi [new file with mode: 0644]
doc/kernel.texi [new file with mode: 0644]
doc/main.texi [new file with mode: 0644]
doc/ospf6d.8 [new file with mode: 0644]
doc/ospf6d.texi [new file with mode: 0644]
doc/ospfd.8 [new file with mode: 0644]
doc/ospfd.texi [new file with mode: 0644]
doc/overview.texi [new file with mode: 0644]
doc/protocol.texi [new file with mode: 0644]
doc/ripd.8 [new file with mode: 0644]
doc/ripd.texi [new file with mode: 0644]
doc/ripngd.8 [new file with mode: 0644]
doc/ripngd.texi [new file with mode: 0644]
doc/routemap.texi [new file with mode: 0644]
doc/snmp.texi [new file with mode: 0644]
doc/texinfo.tex [new file with mode: 0644]
doc/vtysh.1 [new file with mode: 0644]
doc/vtysh.texi [new file with mode: 0644]
doc/zebra.8 [new file with mode: 0644]
doc/zebra.info [new file with mode: 0644]
doc/zebra.texi [new file with mode: 0644]
guile/.cvsignore [new file with mode: 0644]
guile/ChangeLog [new file with mode: 0644]
guile/Makefile.am [new file with mode: 0644]
guile/Makefile.in [new file with mode: 0644]
guile/README [new file with mode: 0644]
guile/guile-bgp.c [new file with mode: 0644]
guile/zebra-guile.c [new file with mode: 0644]
guile/zebra-guile.h [new file with mode: 0644]
guile/zebra-support.c [new file with mode: 0644]
init/.cvsignore [new file with mode: 0644]
init/ChangeLog [new file with mode: 0644]
init/redhat/bgpd.init [new file with mode: 0644]
init/redhat/ospf6d.init [new file with mode: 0644]
init/redhat/ospfd.init [new file with mode: 0644]
init/redhat/ripd.init [new file with mode: 0644]
init/redhat/ripngd.init [new file with mode: 0644]
init/redhat/zebra.init [new file with mode: 0644]
init/redhat/zebra.logrotate [new file with mode: 0644]
init/redhat/zebra.spec.in [new file with mode: 0644]
install-sh [new file with mode: 0755]
lib/.cvsignore [new file with mode: 0644]
lib/ChangeLog [new file with mode: 0644]
lib/Makefile.am [new file with mode: 0644]
lib/Makefile.in [new file with mode: 0644]
lib/buffer.c [new file with mode: 0644]
lib/buffer.h [new file with mode: 0644]
lib/checksum.c [new file with mode: 0644]
lib/command.c [new file with mode: 0644]
lib/command.h [new file with mode: 0644]
lib/daemon.c [new file with mode: 0644]
lib/distribute.c [new file with mode: 0644]
lib/distribute.h [new file with mode: 0644]
lib/filter.c [new file with mode: 0644]
lib/filter.h [new file with mode: 0644]
lib/getopt.c [new file with mode: 0644]
lib/getopt.h [new file with mode: 0644]
lib/getopt1.c [new file with mode: 0644]
lib/hash.c [new file with mode: 0644]
lib/hash.h [new file with mode: 0644]
lib/if.c [new file with mode: 0644]
lib/if.h [new file with mode: 0644]
lib/if_rmap.c [new file with mode: 0644]
lib/if_rmap.h [new file with mode: 0644]
lib/keychain.c [new file with mode: 0644]
lib/keychain.h [new file with mode: 0644]
lib/linklist.c [new file with mode: 0644]
lib/linklist.h [new file with mode: 0644]
lib/log.c [new file with mode: 0644]
lib/log.h [new file with mode: 0644]
lib/md5-gnu.h [new file with mode: 0644]
lib/md5.c [new file with mode: 0644]
lib/memory.c [new file with mode: 0644]
lib/memory.h [new file with mode: 0644]
lib/network.c [new file with mode: 0644]
lib/network.h [new file with mode: 0644]
lib/pid_output.c [new file with mode: 0644]
lib/plist.c [new file with mode: 0644]
lib/plist.h [new file with mode: 0644]
lib/prefix.c [new file with mode: 0644]
lib/prefix.h [new file with mode: 0644]
lib/print_version.c [new file with mode: 0644]
lib/regex-gnu.h [new file with mode: 0644]
lib/regex.c [new file with mode: 0644]
lib/routemap.c [new file with mode: 0644]
lib/routemap.h [new file with mode: 0644]
lib/smux.c [new file with mode: 0644]
lib/smux.h [new file with mode: 0644]
lib/sockopt.c [new file with mode: 0644]
lib/sockopt.h [new file with mode: 0644]
lib/sockunion.c [new file with mode: 0644]
lib/sockunion.h [new file with mode: 0644]
lib/str.c [new file with mode: 0644]
lib/str.h [new file with mode: 0644]
lib/stream.c [new file with mode: 0644]
lib/stream.h [new file with mode: 0644]
lib/table.c [new file with mode: 0644]
lib/table.h [new file with mode: 0644]
lib/tcpfilter.c [new file with mode: 0644]
lib/tcpfilter.h [new file with mode: 0644]
lib/thread.c [new file with mode: 0644]
lib/thread.h [new file with mode: 0644]
lib/vector.c [new file with mode: 0644]
lib/vector.h [new file with mode: 0644]
lib/version.h [new file with mode: 0644]
lib/vty.c [new file with mode: 0644]
lib/vty.h [new file with mode: 0644]
lib/zclient.c [new file with mode: 0644]
lib/zclient.h [new file with mode: 0644]
lib/zebra.h [new file with mode: 0644]
missing [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
ospf6d/.cvsignore [new file with mode: 0644]
ospf6d/ChangeLog [new file with mode: 0644]
ospf6d/Makefile.am [new file with mode: 0644]
ospf6d/Makefile.in [new file with mode: 0644]
ospf6d/README [new file with mode: 0644]
ospf6d/ospf6_abr.c [new file with mode: 0644]
ospf6d/ospf6_abr.h [new file with mode: 0644]
ospf6d/ospf6_area.c [new file with mode: 0644]
ospf6d/ospf6_area.h [new file with mode: 0644]
ospf6d/ospf6_asbr.c [new file with mode: 0644]
ospf6d/ospf6_asbr.h [new file with mode: 0644]
ospf6d/ospf6_bintree.c [new file with mode: 0644]
ospf6d/ospf6_bintree.h [new file with mode: 0644]
ospf6d/ospf6_damp.c [new file with mode: 0644]
ospf6d/ospf6_damp.h [new file with mode: 0644]
ospf6d/ospf6_dbex.c [new file with mode: 0644]
ospf6d/ospf6_dbex.h [new file with mode: 0644]
ospf6d/ospf6_dump.c [new file with mode: 0644]
ospf6d/ospf6_dump.h [new file with mode: 0644]
ospf6d/ospf6_hook.c [new file with mode: 0644]
ospf6d/ospf6_hook.h [new file with mode: 0644]
ospf6d/ospf6_interface.c [new file with mode: 0644]
ospf6d/ospf6_interface.h [new file with mode: 0644]
ospf6d/ospf6_intra.c [new file with mode: 0644]
ospf6d/ospf6_intra.h [new file with mode: 0644]
ospf6d/ospf6_ism.c [new file with mode: 0644]
ospf6d/ospf6_ism.h [new file with mode: 0644]
ospf6d/ospf6_linklist.c [new file with mode: 0644]
ospf6d/ospf6_linklist.h [new file with mode: 0644]
ospf6d/ospf6_lsa.c [new file with mode: 0644]
ospf6d/ospf6_lsa.h [new file with mode: 0644]
ospf6d/ospf6_lsdb.c [new file with mode: 0644]
ospf6d/ospf6_lsdb.h [new file with mode: 0644]
ospf6d/ospf6_main.c [new file with mode: 0644]
ospf6d/ospf6_message.c [new file with mode: 0644]
ospf6d/ospf6_message.h [new file with mode: 0644]
ospf6d/ospf6_neighbor.c [new file with mode: 0644]
ospf6d/ospf6_neighbor.h [new file with mode: 0644]
ospf6d/ospf6_network.c [new file with mode: 0644]
ospf6d/ospf6_network.h [new file with mode: 0644]
ospf6d/ospf6_nsm.c [new file with mode: 0644]
ospf6d/ospf6_nsm.h [new file with mode: 0644]
ospf6d/ospf6_prefix.c [new file with mode: 0644]
ospf6d/ospf6_prefix.h [new file with mode: 0644]
ospf6d/ospf6_proto.c [new file with mode: 0644]
ospf6d/ospf6_proto.h [new file with mode: 0644]
ospf6d/ospf6_route.c [new file with mode: 0644]
ospf6d/ospf6_route.h [new file with mode: 0644]
ospf6d/ospf6_routemap.c [new file with mode: 0644]
ospf6d/ospf6_routemap.h [new file with mode: 0644]
ospf6d/ospf6_spf.c [new file with mode: 0644]
ospf6d/ospf6_spf.h [new file with mode: 0644]
ospf6d/ospf6_top.c [new file with mode: 0644]
ospf6d/ospf6_top.h [new file with mode: 0644]
ospf6d/ospf6_types.h [new file with mode: 0644]
ospf6d/ospf6_zebra.c [new file with mode: 0644]
ospf6d/ospf6_zebra.h [new file with mode: 0644]
ospf6d/ospf6d.c [new file with mode: 0644]
ospf6d/ospf6d.conf.sample [new file with mode: 0644]
ospf6d/ospf6d.h [new file with mode: 0644]
ospfd/.cvsignore [new file with mode: 0644]
ospfd/ChangeLog [new file with mode: 0644]
ospfd/Makefile.am [new file with mode: 0644]
ospfd/Makefile.in [new file with mode: 0644]
ospfd/OSPF-MIB.txt [new file with mode: 0644]
ospfd/OSPF-TRAP-MIB.txt [new file with mode: 0644]
ospfd/ospf_abr.c [new file with mode: 0644]
ospfd/ospf_abr.h [new file with mode: 0644]
ospfd/ospf_asbr.c [new file with mode: 0644]
ospfd/ospf_asbr.h [new file with mode: 0644]
ospfd/ospf_ase.c [new file with mode: 0644]
ospfd/ospf_ase.h [new file with mode: 0644]
ospfd/ospf_dump.c [new file with mode: 0644]
ospfd/ospf_dump.h [new file with mode: 0644]
ospfd/ospf_flood.c [new file with mode: 0644]
ospfd/ospf_flood.h [new file with mode: 0644]
ospfd/ospf_ia.c [new file with mode: 0644]
ospfd/ospf_ia.h [new file with mode: 0644]
ospfd/ospf_interface.c [new file with mode: 0644]
ospfd/ospf_interface.h [new file with mode: 0644]
ospfd/ospf_ism.h [new file with mode: 0644]
ospfd/ospf_lsa.c [new file with mode: 0644]
ospfd/ospf_lsa.h [new file with mode: 0644]
ospfd/ospf_lsdb.c [new file with mode: 0644]
ospfd/ospf_lsdb.h [new file with mode: 0644]
ospfd/ospf_main.c [new file with mode: 0644]
ospfd/ospf_neighbor.h [new file with mode: 0644]
ospfd/ospf_network.c [new file with mode: 0644]
ospfd/ospf_network.h [new file with mode: 0644]
ospfd/ospf_nsm.h [new file with mode: 0644]
ospfd/ospf_opaque.c [new file with mode: 0644]
ospfd/ospf_opaque.h [new file with mode: 0644]
ospfd/ospf_packet.c [new file with mode: 0644]
ospfd/ospf_packet.h [new file with mode: 0644]
ospfd/ospf_route.c [new file with mode: 0644]
ospfd/ospf_route.h [new file with mode: 0644]
ospfd/ospf_routemap.c [new file with mode: 0644]
ospfd/ospf_snmp.c [new file with mode: 0644]
ospfd/ospf_snmp.h [new file with mode: 0644]
ospfd/ospf_spf.c [new file with mode: 0644]
ospfd/ospf_spf.h [new file with mode: 0644]
ospfd/ospf_te.c [new file with mode: 0644]
ospfd/ospf_te.h [new file with mode: 0644]
ospfd/ospf_vty.c [new file with mode: 0644]
ospfd/ospf_vty.h [new file with mode: 0644]
ospfd/ospf_zebra.c [new file with mode: 0644]
ospfd/ospf_zebra.h [new file with mode: 0644]
ospfd/ospfd.c [new file with mode: 0644]
ospfd/ospfd.conf.sample [new file with mode: 0644]
ospfd/ospfd.h [new file with mode: 0644]
ports/Makefile [new file with mode: 0644]
ports/README [new file with mode: 0644]
ports/files/md5 [new file with mode: 0644]
ports/pkg/COMMENT [new file with mode: 0644]
ports/pkg/DESCR [new file with mode: 0644]
ports/pkg/PLIST [new file with mode: 0644]
ripd/.cvsignore [new file with mode: 0644]
ripd/ChangeLog [new file with mode: 0644]
ripd/Makefile.am [new file with mode: 0644]
ripd/Makefile.in [new file with mode: 0644]
ripd/RIPv2-MIB.txt [new file with mode: 0644]
ripd/rip_debug.c [new file with mode: 0644]
ripd/rip_debug.h [new file with mode: 0644]
ripd/rip_interface.c [new file with mode: 0644]
ripd/rip_main.c [new file with mode: 0644]
ripd/rip_offset.c [new file with mode: 0644]
ripd/rip_peer.c [new file with mode: 0644]
ripd/rip_routemap.c [new file with mode: 0644]
ripd/rip_snmp.c [new file with mode: 0644]
ripd/rip_zebra.c [new file with mode: 0644]
ripd/ripd.c [new file with mode: 0644]
ripd/ripd.conf.sample [new file with mode: 0644]
ripd/ripd.h [new file with mode: 0644]
ripngd/.cvsignore [new file with mode: 0644]
ripngd/ChangeLog [new file with mode: 0644]
ripngd/Makefile.am [new file with mode: 0644]
ripngd/Makefile.in [new file with mode: 0644]
ripngd/ripng_debug.c [new file with mode: 0644]
ripngd/ripng_debug.h [new file with mode: 0644]
ripngd/ripng_interface.c [new file with mode: 0644]
ripngd/ripng_main.c [new file with mode: 0644]
ripngd/ripng_route.c [new file with mode: 0644]
ripngd/ripng_route.h [new file with mode: 0644]
ripngd/ripng_routemap.c [new file with mode: 0644]
ripngd/ripng_zebra.c [new file with mode: 0644]
ripngd/ripngd.c [new file with mode: 0644]
ripngd/ripngd.conf.sample [new file with mode: 0644]
ripngd/ripngd.h [new file with mode: 0644]
stamp-h.in [new file with mode: 0644]
tools/mrlg.cgi [new file with mode: 0755]
tools/rrcheck.pl [new file with mode: 0644]
tools/rrlookup.pl [new file with mode: 0644]
tools/zc.pl [new file with mode: 0755]
tools/zebra.el [new file with mode: 0644]
update-autotools [new file with mode: 0755]
vtysh/.cvsignore [new file with mode: 0644]
vtysh/ChangeLog [new file with mode: 0644]
vtysh/Makefile.am [new file with mode: 0644]
vtysh/Makefile.in [new file with mode: 0644]
vtysh/extract.pl [new file with mode: 0755]
vtysh/vtysh.c [new file with mode: 0644]
vtysh/vtysh.conf.sample [new file with mode: 0644]
vtysh/vtysh.h [new file with mode: 0644]
vtysh/vtysh_cmd.c [new file with mode: 0644]
vtysh/vtysh_config.c [new file with mode: 0644]
vtysh/vtysh_main.c [new file with mode: 0644]
vtysh/vtysh_user.c [new file with mode: 0644]
vtysh/vtysh_user.h [new file with mode: 0644]
zebra/.cvsignore [new file with mode: 0644]
zebra/ChangeLog [new file with mode: 0644]
zebra/GNOME-PRODUCT-ZEBRA-MIB [new file with mode: 0644]
zebra/GNOME-SMI [new file with mode: 0644]
zebra/Makefile.am [new file with mode: 0644]
zebra/Makefile.in [new file with mode: 0644]
zebra/client_main.c [new file with mode: 0644]
zebra/connected.c [new file with mode: 0644]
zebra/connected.h [new file with mode: 0644]
zebra/debug.c [new file with mode: 0644]
zebra/debug.h [new file with mode: 0644]
zebra/if_ioctl.c [new file with mode: 0644]
zebra/if_netlink.c [new file with mode: 0644]
zebra/if_proc.c [new file with mode: 0644]
zebra/if_sysctl.c [new file with mode: 0644]
zebra/interface.c [new file with mode: 0644]
zebra/interface.h [new file with mode: 0644]
zebra/ioctl.c [new file with mode: 0644]
zebra/ioctl.h [new file with mode: 0644]
zebra/ipforward.h [new file with mode: 0644]
zebra/ipforward_aix.c [new file with mode: 0644]
zebra/ipforward_ews.c [new file with mode: 0644]
zebra/ipforward_proc.c [new file with mode: 0644]
zebra/ipforward_solaris.c [new file with mode: 0644]
zebra/ipforward_sysctl.c [new file with mode: 0644]
zebra/irdp.c [new file with mode: 0644]
zebra/irdp.h [new file with mode: 0644]
zebra/kernel_netlink.c [new file with mode: 0644]
zebra/kernel_socket.c [new file with mode: 0644]
zebra/main.c [new file with mode: 0644]
zebra/mtu_kvm.c [new file with mode: 0644]
zebra/redistribute.c [new file with mode: 0644]
zebra/redistribute.h [new file with mode: 0644]
zebra/rib.h [new file with mode: 0644]
zebra/rt.h [new file with mode: 0644]
zebra/rt_ioctl.c [new file with mode: 0644]
zebra/rt_netlink.c [new file with mode: 0644]
zebra/rt_socket.c [new file with mode: 0644]
zebra/rtadv.c [new file with mode: 0644]
zebra/rtadv.h [new file with mode: 0644]
zebra/rtread_getmsg.c [new file with mode: 0644]
zebra/rtread_netlink.c [new file with mode: 0644]
zebra/rtread_proc.c [new file with mode: 0644]
zebra/rtread_sysctl.c [new file with mode: 0644]
zebra/zebra.conf.sample [new file with mode: 0644]
zebra/zebra_rib.c [new file with mode: 0644]
zebra/zebra_snmp.c [new file with mode: 0644]
zebra/zebra_vty.c [new file with mode: 0644]
zebra/zserv.c [new file with mode: 0644]
zebra/zserv.h [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..0e2c5b6
--- /dev/null
@@ -0,0 +1,10 @@
+config.log
+config.h
+config.cache
+config.status
+stamp-h
+stamp-h[0-9]*
+Makefile
+.deps
+autom4te.cache
+configure.lineno
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..61867a8
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+Kunihiro Ishiguro <kunihiro@zebra.org>
+Toshiaki Takada <takada@zebra.org>
+Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+Alex D. Zinin <azinin@hotmail.com>
+Gleb Natapov <gleb@nbase.co.il>
+Akihiro Mizutani <mizutani@dml.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       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/COPYING.LIB b/COPYING.LIB
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..7448bfe
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,674 @@
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2002-06-28  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * update-autotools: Change file name from update-auto-tools.sh.
+
+2002-06-21  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * update-auto-tools.sh: Add a new script to clean up build
+       environment.
+
+2002-06-18  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * Shift to the latest build environment autoconf-2.53 and
+       automake-1.6.2.
+
+2001-10-22  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * Integrate Glen Turner <glen.turner@aarnet.edu.au>'s pid option.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-19  "Peter Galbavy" <peter.galbavy@knowtion.net>
+
+       * configure.in: SNMP library check problem fix when the library is
+       installed under /usr/local/lib.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-04-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (LIBPAM): Use ZEBRA_AC_C_BIGENDIAN to avoid a
+       warning.
+       (IF_METHOD): Use test -r instead of AC_CHECK_FILE to avoid
+       warnings.
+
+       * config.guess: Update to 2000-11-10 version.
+
+2001-04-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Use AC_TRY_COMPILE instead of AC_EGREP_HEADER to
+       detect in_pktinfo structure.  Suggested by: Vlad Lungu
+       <vlad@rls.roknet.ro>.
+
+2001-03-07  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * configure.in: Add check for structure in_pktinfo.
+
+2001-02-07  "Bjoern A. Zeeb" <bzeeb+zebra@zabbadoz.net>
+
+       * configure.in (USE_PAM): Fix PAM library detection code.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Remove guile related definition.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (ac_cv_htonl_works): HAVE_REPAIRABLE_HTONL is
+       removed.  htonl should work fine on any platform.
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Remove --enable-oldrib option.
+
+       * acconfig.h: OLD_RIB definition is removed.
+
+       * zebra-0.90 is released.
+
+       * configure.in (LIBS): Add check for sun_len field in struct
+       sun_len.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: Include init/redhat files to distribution.
+
+2001-01-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * configure.in: check libm.a for BGPd compile error.
+       AC_CHECK_LIB(m, main) was added.
+
+2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: --enable-unixdomain becomes default.  Add
+       --enable-tcp-zebra for TCP/IP communication between protocol
+       daemon and zebra.
+
+       * COPYING.LIB: Added for lib/getopt.c, lib/getopt.h,
+       lib/getopt1.c, lib/md5-gnu.h, lib/md5.c, lib/regex-gnu.h,
+       lib/regex.c.
+
+       * Makefile.am (dist-hook): Include tools/*.cgi to distribution.
+
+2000-12-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (MULTIPATH_NUM): --enable-multipath=ARG specify
+       multipath number.  ARG must be digit.
+
+2000-12-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --enable-newrib for test new RIB code.
+
+2000-11-25  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * configure.in, config.h.in: Add check for libutil.h and
+       setproctitle().
+
+2000-10-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --enable-nssa for OSPF NSSA option.
+
+       * acconfig.h: Define HAVE_NSSA.
+
+2000-10-25  "Bjoern A. Zeeb" <bzeeb+zebra@zabbadoz.net>
+
+       * configure.in: pam_misc is only linked when the platform is
+       GNU/Linux.
+
+2000-10-24  Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+       * configure.in (LIBS): Add check for crypto library.  test x`ls
+       ${ac_snmp}` is replaced with sipmle test -f.
+
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --enable-unixdomain option.  This will be
+       default behavior in zebra-0.90.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-09-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add check for Intel CPU for Solaris on x86 check.
+
+2000-09-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add check for getifaddrs().
+       Set AM_INIT_AUTOMAKE version to 0.89.
+
+2000-09-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * config.guess: Update to the latest version.
+
+       * config.sub: Likewise
+
+2000-09-14  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+       * REPORTING-BUGS: New file is added.
+
+2000-08-27  itojun@iijlab.net
+
+       * configure.in: Add ncurses library check when --enable-vtysh is
+       specified.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add check for readline/history.h.
+
+       * acconfig.h: Remove pthread related variables.
+
+       * configure.in: Add --with-libpam option for vtysh PAM
+       authentication.  Remove --disable-pthread because we don't support
+       pthread.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+       * configure.in: Add Solaris -lcurses for vtysh.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add check for ncurses for compiling on Solaris.
+
+2000-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add check for libreadline when --enable-vtysh is
+       specified.
+
+2000-07-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add AC_DEFINE(OPEN_BSD). When OS is OpenBSD
+       interface method is if_ioctl.o
+
+2000-07-09  Chris Dunlop <chris@onthe.net.au>
+
+       * acconfig.h: Add HAVE_BROKEN_ALIASES.
+       
+       * configure.in: Add --enable-broken-aliases.
+
+2000-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to zebra-0.87.
+
+2000-06-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Remove --enable-mpls-vpn.  Now MPLS-VPN support is
+       default.
+
+       * Set version to zebra-0.87-pre
+
+       * Makefile.am: Likewise.
+
+2000-04-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.86.
+
+2000-03-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.85b for ospfd test.
+
+2000-03-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.85a for ospfd test.
+
+2000-03-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.85.
+
+2000-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.in: Regenerated by patched automake for fixing "make
+       clean" problem on FreeBSD.
+
+1999-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.83a.  This is for *BSD static route lookup
+       problem.
+
+1999-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.83.
+
+1999-11-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.82.
+
+1999-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * aczebra.m4: New file added.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+       * configure.in (LIBS): Add sa_len check of sockaddr.
+
+       * acconfig.h: Add HAVE_SA_LEN.
+
+1999-11-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Update version to zebra-0.81b for bgpd test.
+
+1999-11-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --enable-mbgp.
+
+1999-11-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (EXTRA_DIST): Add TODO to the distribution.
+
+1999-11-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * TODO: New file is added.
+
+1999-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Update version to zebra-0.81a for ospfd test.
+
+1999-10-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: New option --enable-snmp is added.
+
+1999-10-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Update version to zebra-0.80.
+
+1999-10-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Update version to zebra-0.80-pre3
+
+1999-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (LIBS): SNMP check is done by ucd-snmp/asn1.h.
+
+1999-10-10  Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+       * configure.in: Add support of OpenBSD.
+
+1999-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Update version to zebra-0.80-pre2.
+
+1999-09-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Update version to zebra-0.80-pre.  From this version,
+       access-list and prefix-list's name space is divided into IPv4 and
+       IPv6.
+
+1999-09-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: For test recent fixes Set version to zebra-0.79a.
+
+1999-09-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: zebra-0.79 is out.
+
+1999-09-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: For ospfd's virtual link test.  Set version to 0.78h.
+
+1999-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: For ospfd test.  Set version to 0.78g.
+
+1999-09-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: For internal test of ospfd. Set version to 0.78f.
+
+1999-09-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: To test ospfd's fix, set version to 0.78e.
+
+1999-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: To test ospfd's area related bug fix, set version 
+       to 0.78d.
+
+1999-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: To test ospfd, set version to 0.78c.
+
+1999-08-31  Janos Farkas <chexum@shadow.banki.hu>
+
+       * Many misspelling correction.
+
+1999-08-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: To test ospfd, set version to 0.78b.
+
+1999-08-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (LIBS): Add UCD-SNMP include path check.
+
+1999-08-31  Lars Fenneberg  <lf@elemental.net>
+
+       * configure.in: The logic which detects the UCD-SNMP library
+       should first check in the default system locations for the library
+       and then in /usr/local.
+
+1999-08-27  itojun@iijlab.net
+
+       * configure.in (LIBS): Fix problem about libsnmp.a check.
+
+1999-08-26  kay <kay@v6.access.co.jp>
+
+       * configure.in (CFLAGS): Add <sys/socket.h> to check socklen_t.
+
+1999-08-24  VOP <vop@unity.net>
+
+       * filter.c: Include "sockunion.h".
+       plist.c: Likewise.
+       table.c: Likewise.
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add netinet6/in6.h check.
+
+1999-08-21  Masaki Minami <masaki@minami.org>
+
+       * BSD/OS 4.0 porting.
+
+1999-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --enable-netlink option to force to use Linux
+       netlink interface.
+       (CFLAGS): Add ucd-snmp library check.
+
+       * acconfig.h: If socklen_t is not defined, typedef int to
+       socklen_t.
+
+1999-08-15  Arkadiusz Miskiewicz <misiek@misiek.eu.org>
+
+       * configure.in: When --enable-ipv6 specified, then only kernel
+       version is checked.
+
+1999-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add GNU libc 2.1 check.
+
+1999-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Fix privious Linux IPv6 check changes.
+
+1999-08-02  Arkadiusz Miskiewicz <misiek@misiek.eu.org>
+
+       * configure.in: Improve Linux IPv6 feature check.
+
+1999-07-29  Rick Payne <rickp@rossfell.co.uk>
+
+       * Changed route-maps to behave in a more cisco-like fashion
+
+1999-07-27  Gerhard Poul <gpoul@gnu.org>
+
+       * SERVICES: New file added.
+
+1999-07-12  itojun@iijlab.net
+
+       * configure.in: Add check for getaddrinfo.  Improve Kame related
+       library check.
+
+1999-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * configure.in, acconfig.h: Add check for FreeBSD 3.2.
+
+1999-07-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Delete check for netinet/ip6.h.
+
+1999-06-30  Gerhard Poul  <gpoul@gnu.org>
+
+       * README: remixed the old files and added some new parts.
+       moved some INSTALL stuff into INSTALL file.
+       moved some other stuff to doc/zebra.texi
+
+1999-06-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (LIBS): Add libresolv check.
+       Change --enabe-all-in-one option to --enable-one-vty.
+
+1999-06-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --enabe-all-in-one option.
+
+1999-06-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add socklen_t check.
+
+1999-06-16  Gerhard Poul <gpoul@gnu.org>
+
+       * Many compile warnings fixed.
+
+1999-05-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Change message from Linux 2.2.X IPv6 to Linux IPv6.
+       OpenBSD (NRL) check is enabled.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (LIBS): Add crypt library check.
+
+1999-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add sin6_scope_id in struct sockaddr_in6 check.
+
+1999-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.63 for first beta package.
+
+1999-04-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * guile.m4: Added from guile package.
+
+1999-04-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.60 for beta package preparation.
+
+1999-04-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: Add noninst_LIBRARIES each directory's Makefile.am.
+       This change is for linking these libraries to guile.
+
+1999-04-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (LIBS): Add struct rt_addrinfo check.
+
+1999-04-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: AC_STDC_HEADERS added.
+
+1999-03-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Add dependencies to each directory's Makefile.am.
+
+1999-03-02  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * reworked include file structure, and configure so that all
+       source files get all system-dependent include files by including
+       <zebra.h> which is really lib/zebra.h. This means that the
+       different programs include files are now available as #include
+       "zebra/zebra.h" - note the use of quotes, not <> as delimiters.
+
+       In practical terms, if I haven't really screwed up, the main file
+       that maintainers for other OSes have to change is lib/zebra.h for
+       all the conditional includes etc.
+
+       * added --disable-pthread for those systems that seem to have
+       POSIX threads, but do not work. OpenBSD 2.4+ is like that just
+       now. Changed all occurance of #ifdef PTHREAD to use HAVE_PTHREAD
+       instead.
+
+1999-02-24    <kunihiro@zebra.org>
+
+       * configure.in: update to AC_PREREQ(1.13).
+       Change message from Linux 2.1.x to Linux 2.2.x.
+       * Added ospf6d directory support.
+
+1999-02-22  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * added a "log" element to the BGPd peer structure, enabling us to
+       start thinging about a log stream per peer. This is currently
+       ignored by the wrapper code, but developers should try to use the
+       "appropriate" ZLOG stream. Documentation will follow, when the
+       real routines start to exist.
+
+       The current plan is to use a copy of the BSD syslog() routines and
+       replace the syslog library function with our own. I will need
+       feedback from users of other platforms as this work is done to see
+       if all is well elsewhere.
+       
+       * preliminary work on zlog() library. directly replaces syslog()
+       currently with zlog(ZLOG *, ...) where the new first argument
+       is a pointer to a ZLOG structure (defined in lib/log.h) and will
+       encapsulate all the information necessary to maintain multiple
+       logging streams.
+
+1999-02-19  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * added vsnprintf() macro to lib/str.h if required and removed
+       #ifdef SUNOS_5 dependency on it
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * syslog support added
+
+1999-02-18  Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+       * configure.in: Add daemon function check.
+
+1999-01-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Add --disable-ipv6, --disable-zebra,
+       --disable-bgpd, --disable-ripd, --disable-ripngd, --disable-ospfd
+       options to configure.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Check /usr/inet6/lib/libinet6.a exists or not.
+
+1998-10-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Comment out FreeBSD's libc_r detect section. At
+       this moment it doesn't work correctly with zebra.
+
+       Netlink interface is only enabled when Linux kernel version is
+       upper than 2.1.0.
+
+1998-09-15  HEO SeonMeyong <seirios@matrix.iri.co.jp>
+
+       * Hydrangea is now called KAME, so change all defines.
+
+1998-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: ifaliasreq check added.
+
+1998-08-12  Katsuhiro Kondou <kondou@nec.co.jp>
+
+       * Patch is applied for compile under EWS4800
+
+1998-06-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: delete old mtu_method check.
+
+       * doc/zebra.texi (Kernel interface): chapter `Kernel interface' added
+
+1998-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: add new netlink check for GNU/Linux
+
+1998-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * doc/zebra.texi: Update Linux netlink chapter.
+
+1998-05-18  Yamashita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * config.h.in: define PTHREAD if work on Solaris 2.6
+               why delete the definition? I miss?
+
+1998-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: add net/if.h header check.
+
+1998-05-02  SeonMeyong HEO <seirios@Matrix.iri.co.jp>
+
+        * zebra.tex,archfig.tex,zebra.sty: Manual file is added.
+       * zebra.texi: Modify Introduction text.
+       * RIPngd.c: Patch Hydrangea code.
+
+1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * .cvsignore: added.
+
+       * Makerule.in: is gone.
+       * Makefile.am: Now we use automake to generate Makefile.in
+
+1998-03-19  Yamashita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * lib/vty.c: modified the definition of *master
+       * lib/sockunion.c (inet_aton): add, but don't work. uum...
+
+
+1998-03-15  Yamashita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * configure.in: define PTHREAD if work on Solaris 2.6
+       * config.h.in: likewise
+       * lib/thread.c: likewise
+       * lib/vty.c: likewise
+       
+1998-03-15  SeonMeyong HEO  <seirios@Matrix.iri.co.jp>
+
+       * config.h.in: define INET6 if defined HAVE_IPV6 & HYDRANGEA
+       * bgpd/: remove include <netinet6/in6.h> line.
+       * lib/: remove include <netinet6/in6.h> line.
+       * ripbgd/: remove include <netinet6/in6.h> line.
+       * zebra/: remove include <netinet6/in6.h> line.
+       * ripd/*.c: remove include <netinet6/in6.h> line.
+       undefine IPV6 difinitions because RIPd is not worked for
+       IPv6 protocol.
+
+       
+1998-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: Change routing socket check method from
+       AC_TRY_COMPILE to AC_TRY_RUN because GNU libc version 2 has
+       AF_ROUTE but over linux it's meenigless.
+
+1998-01-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * config.h.in: remove err_t define.
+
+1997-11-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in (canonical): add check of IF_METHOD
+
+1997-09-27  Kunihiro Ishiguro  <kunihiro@note.digital-magic.co.jp>
+
+       * configure.in: add INRIA check
+
+1997-09-25  Kunihiro Ishiguro  <kunihiro@note.digital-magic.co.jp>
+
+       * configure.in (canonical): change ipforward_snmp.o to ipforward_proc.o
+
+1997-09-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * configure.in: change IRDPD to NDPD
+
+1997-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * INSTALL: new file
+
+1997-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * config.h: add XCALLOC()
+
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..a2c8722
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,181 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..72a09dc
--- /dev/null
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in.
+
+SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @VTYSH@ doc
+
+EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \
+       vtysh/Makefile.am update-autotools
+
+dist-hook:
+       mkdir $(distdir)/tools
+       cp -p $(srcdir)/tools/*.pl $(distdir)/tools
+       cp -p $(srcdir)/tools/*.el $(distdir)/tools
+       cp -p $(srcdir)/tools/*.cgi $(distdir)/tools
+       mkdir $(distdir)/init
+       mkdir $(distdir)/init/redhat
+       cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat
+       cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..6654f41
--- /dev/null
@@ -0,0 +1,548 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = .
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+INCLUDES = @INCLUDES@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+
+SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @VTYSH@ doc
+
+EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \
+       vtysh/Makefile.am update-autotools
+
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+DIST_SOURCES =
+
+RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \
+       ps-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 \
+ configure.lineno
+$(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
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+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
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+
+distdir: $(DISTFILES)
+       $(am__remove_distdir)
+       mkdir $(distdir)
+       $(mkinstalldirs) $(distdir)/vtysh
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         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` \
+         && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+         && $(mkinstalldirs) $$dc_destdir \
+         && 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 \
+         && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+               distuninstallcheck \
+         && chmod -R a-w "$$dc_install_base" \
+         && ({   $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+                   distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+             } || { rm -rf "$$dc_destdir"; exit 1; }) \
+         && rm -rf "$$dc_destdir" \
+         && $(MAKE) $(AM_MAKEFLAGS) dist-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'
+distuninstallcheck:
+       cd $(distuninstallcheck_dir) \
+       && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+          || { echo "ERROR: files left after uninstall:" ; \
+               if test -n "$(DESTDIR)"; then \
+                 echo "  (check DESTDIR support)"; \
+               fi ; \
+               $(distuninstallcheck_listfiles) ; \
+               exit 1; } >&2
+distcleancheck: distclean
+       if test '$(srcdir)' = . ; then \
+         echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+         exit 1 ; \
+       fi
+       test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+         || { echo "ERROR: files left in build directory after distclean:" ; \
+              $(distcleancheck_listfiles) ; \
+              exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       $(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
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \
+       clean-generic clean-recursive ctags ctags-recursive dist \
+       dist-all dist-gzip distcheck distclean distclean-generic \
+       distclean-hdr distclean-recursive distclean-tags distcleancheck \
+       distdir distuninstallcheck 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 pdf pdf-am pdf-recursive ps ps-am \
+       ps-recursive tags tags-recursive uninstall uninstall-am \
+       uninstall-info-am uninstall-info-recursive uninstall-recursive
+
+
+dist-hook:
+       mkdir $(distdir)/tools
+       cp -p $(srcdir)/tools/*.pl $(distdir)/tools
+       cp -p $(srcdir)/tools/*.el $(distdir)/tools
+       cp -p $(srcdir)/tools/*.cgi $(distdir)/tools
+       mkdir $(distdir)/init
+       mkdir $(distdir)/init/redhat
+       cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat
+       cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..24248c7
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,2338 @@
+GNU Zebra is not yet released, so this NEWS is about beta version.
+
+* Changes in zebra-0.93
+
+* Changes in bgpd
+
+** Configuration is changed to new format.
+
+* Changes in ospfd
+
+** Crush bugs which reported on Zebra ML is fixed.
+
+** Opaque LSA and TE LSA support is added by KDD R&D Laboratories,
+   Inc.
+
+* Chages in ospf6d
+
+** Many bugs are fixed.
+\f
+* Changes in zebra-0.92a
+
+* Changes in bgpd
+
+** Fix "^$" community list bug.
+
+** Below command's Address Family specific configurations are added
+
+  nexthop-self
+  route-reflector-client
+  route-server-client
+  soft-reconfiguration inbound
+
+* Changes in zebra
+
+** Treat kernel type routes as EGP routes.
+\f
+* Changes in zebra-0.92
+
+** Overall security is improved.  Default umask is 0077.
+
+* Changes in ripd
+
+** If output interface is in simple password authentication mode,
+substruct one from rtemax.
+
+* Changes in bgpd
+
+** IPv4 multicast and IPv6 unicast configuration is changed to so
+called new config.  All of AFI and SAFI specific configuration is
+moved to "address-family" node.  When you have many IPv6 only
+configuration, you will see many "no neighbor X:X::X:X activate" line
+in your configuration to disable IPv4 unicast NLRI exchange.  In that
+case please use "no bgp default ipv4-unicast" command to suppress the
+output.  Until zebra-0.93, old config is still left for compatibility.
+
+Old config
+==========
+router bgp 7675
+ bgp router-id 10.0.0.1
+ redistribute connected
+ network 192.168.0.0/24
+ neighbor 10.0.0.2 remote-as 7675
+ ipv6 bgp network 3ffe:506::/33
+ ipv6 bgp network 3ffe:1800:e800::/40
+ ipv6 bgp aggregate-address 3ffe:506::/32
+ ipv6 bgp redistribute connected
+ ipv6 bgp neighbor 3ffe:506:1000::2 remote-as 1
+
+New config
+==========
+router bgp 7675
+ bgp router-id 10.0.0.1
+ network 192.168.0.0/24
+ redistribute connected
+ neighbor 10.0.0.2 remote-as 7675
+ neighbor 3ffe:506:1000::2 remote-as 1
+ no neighbor 3ffe:506:1000::2 activate
+!
+ address-family ipv6
+  network 3ffe:506::/33
+  network 3ffe:1800:e800::/40
+  aggregate-address 3ffe:506::/32
+  redistribute connected
+  neighbor 3ffe:506:1000::2 activate
+ exit-address-family
+
+* Changes in ospfd
+
+** Internal interface treatment is changed.  Now ospfd can handle
+multiple IP address for an interface.
+
+** Redistribution of loopback interface's address works fine.
+\f
+* Changes in zebra-0.91
+
+** --enable-oldrib configure option is removed.
+
+** HAVE_IF_PSEUDO part is removed.  Same feature is now supported by
+default.
+
+* Changes in ripd
+
+** When redistributed route is withdrawn, perform poisoned reverse.
+
+* Changes in zebra
+
+** When interface's address is removed, kernel route pointing out to
+the address is removed.
+
+** IPv6 RIB is now based upon new RIB code.
+
+** zebra can handle same connected route to one interface.
+
+** New command for interface address.  Currently this commands are
+only supported on GNU/Linux with netlink interface.
+
+"ip address A.B.C.D secondary"
+"ip address A.B.C.D label LABEL"
+
+* Changes in bgpd
+
+** BGP flap dampening bugs are fixed.
+
+** BGP non-blocking TCP connection bug is fixed.
+
+** "show ip bgp summary" shows AS path and community entry number.
+
+** New commands have been added.
+  "show ip bgp cidr-only"
+  "show ip bgp ipv4 (unicast|multicast) cidr-only"
+  "show ip bgp A.B.C.D/M longer-prefixes"
+  "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes"
+  "show ipv6 bgp X:X::X:X/M longer-prefixes"
+  "show ipv6 mbgp X:X::X:X/M longer-prefixes"
+
+** IPv6 IBGP nexthop change is monitored.
+
+** Unknown transitive attribute is passed with partial flag bit on.
+
+* Changes in ospfd
+
+** Fix bug of LSA MaxAge flood.
+
+** Fix bug of NSSA codes.
+\f
+* Changes in zebra-0.90
+
+** From this beta release, --enable-unixdomain and --enable-newrib
+becomes default.  So both options are removed from configure.in.  To
+revert old behavior please specify below option.
+
+--enable-tcp-zebra # TCP/IP socket is used for protocol daemon and zebra.
+--enable-oldrib    # Turn on old RIB implementation.
+
+Old RIB implementation will be removed in zebra-0.91.
+
+** From this beta release --enable-multipath is supported.  This
+option is only effective on GNU/Linux kernel with
+CONFIG_IP_ADVANCED_ROUTER and CONFIG_IP_ROUTE_MULTIPATH is set.
+
+--enable-multipath=ARG  # ARG must be digit.  When ARG is 0 unlimit multipath number.
+
+** From this release we do not include guile files.
+
+* Changes in lib
+
+** newlist.[ch] is merged with linklist.[ch].
+
+** Now Zebra works on MacOS X public beta.
+
+** Access-list can have remark.  "access-list WORD remark LINE" define
+remark for specified access-list.
+
+** Key of key-chain is sorted by it's idetifier value.
+
+** prefix-list rule is slightly changed.  The rule of "len <= ge-value
+<= le-value" is changed to "len < ge-value <= le-value".
+
+** According to above prefix-list rule change, add automatic
+conversion function of an old rule. ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8
+le 32
+
+** SMUX can handle SNMP trap.
+
+** In our event library, event thread is executed before any other
+thread like timer, read and write event.
+
+** Robust method for writing configuration file and recover from
+backing up config file.
+
+** Display "end" at the end of configuration.
+
+** Fix memory leak in vtysh_read().
+
+** Fix memroy leak about access-list and prefix-list name.
+
+* Changes in zebra
+
+** UNIX domain socket server of zebra protocol is added.
+
+** Fix PointoPoint interface network bug.  The destination network
+should be installed into routing table instead of local network.
+
+** Metric value is reflected to kernel routing table.
+
+** "show ip route" display uptime of RIP,OSPF,BGP routes.
+
+** New RIB implementation is added.
+
+Now we have enhanced RIB (routing information base) implementation in
+zebra.  New RIB has many new features and fixed some bugs which exist
+in old RIB code.
+
+*** Static route with distance value
+
+    Static route can be specified with administrative distance.  The
+  distance value 255 means it is not installed into the kernel.
+  Default value of distance for static route is 1.
+  
+    ip route A.B.C.D/M A.B.C.D <1-255>
+    ip route A.B.C.D/M IFNAME <1-255>
+  
+    If the least distance value's route's nexthop are unreachable,
+  select the least distance value route which has reachable nexthop is
+  selected.
+  
+    ip route 0.0.0.0/0 10.0.0.1
+    ip route 0.0.0.0/0 11.0.0.1 2
+  
+    In this case, when 10.0.0.1 is unreachable and 11.0.0.1 is
+  reachable.  The route with nexthop 11.0.0.1 will be installed into
+  forwarding table.
+  
+    zebra> show ip route
+    S>* 0.0.0.0/0 [2/0] via 11.0.0.1
+    S   0.0.0.0/0 [1/0] via 10.0.0.1 inactive
+  
+    If the nexthop is unreachable "inactive" is displayed.  You can
+  specify any string to IFNAME.  There is no need of the interface is
+  there when you configure the route.
+  
+    ip route 1.1.1.1/32 ppp0
+  
+  When ppp0 comes up, the route is installed properly.
+
+*** Multiple nexthop routes for one prefix
+
+    Multiple nexthop routes can be specified for one prefix.  Even the
+  kernel support only one nexthop for one prefix user can configure
+  multiple nexthop.
+  
+    When you configure routes like below, prefix 10.0.0.1 has three
+  nexthop.
+  
+    ip route 10.0.0.1/32 10.0.0.2
+    ip route 10.0.0.1/32 10.0.0.3
+    ip route 10.0.0.1/32 eth0
+  
+    If there is no route to 10.0.0.2 and 10.0.0.3.  And interface eth0
+    is reachable, then the last route is installed into the kernel.
+  
+    zebra> show ip route
+    S>  10.0.0.1/32 [1/0] via 10.0.0.2 inactive
+                          via 10.0.0.3 inactive
+      *                   is directly connected, eth0
+  
+    '*' means this nexthop is installed into the kernel. 
+
+*** Multipath (more than one nexthop for one prefix) can be installed into the kernel.
+
+    When the kernel support multipath, zebra can install multipath
+  routes into the kernel.  Before doing that please make it sure that
+  setting --enable-multipath=ARG to configure script.  ARG must be digit
+  value.  When specify 0 to ARG, there is no limitation of the number
+  of the multipath.  Currently only GNU/Linux with netlink interface is
+  supported.
+  
+    ip route 10.0.0.1/32 10.0.0.2
+    ip route 10.0.0.1/32 10.0.0.3
+    ip route 10.0.0.1/32 eth0
+  
+    zebra> show ip route
+    S>* 10.0.0.1/32 [1/0] via 10.0.0.2
+      *                   via 10.0.0.3
+                          is directly connected, eth0
+
+*** Kernel message delete installed route.
+
+    After zebra install static or dynamic route into the kernel.
+  
+    R>* 0.0.0.0/0 [120/3] via 10.0.0.1
+  
+    If you delete this route outside zebra, old zebra does not reinstall
+  route again.  Now the route is re-processed and properly reinstall the
+  static or dynamic route into the kernel.
+
+** GNU/Linux netlink socket handling is improved to fix race condition
+between kernel message and user command responce.
+
+* Changes in bgpd
+
+** Add show neighbor's routes command.
+
+  "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes"
+  "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes"
+  "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes"
+  "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes"
+
+** BGP passive peer support problem is fixed.
+
+** Redistributed IGP nexthop is passed to BGP nexthop.
+
+** On multiaccess media, if the nexthop is reachable nexthop is passed
+as it is.
+
+** Remove zebra-0.88 compatibility commands.
+
+  "match ip prefix-list WORD"
+  "match ipv6 prefix-list WORD"
+
+  Instead of above please use below commands.
+
+  "match ip address prefix-list WORD"
+  "match ipv6 address prefix-list WORD"
+
+** Fix bug of holdtimer is not reset when bgp cleared.
+
+** "show ip bgp summary" display peer establish/drop count.
+
+** Change "match ip next-hop" argument from IP address to access-list
+name.
+
+** When "bgp enforce-first-as" is enabled, check EBGP peer's update
+has it's AS number in the first AS number in AS sequence.
+
+** New route-map command "set community-delete COMMUNITY-LIST" is
+added.  Community matched the CoMMUNITY-LIST is removed from the
+community.
+
+** BGP-MIB implementation is finished.
+
+** When BGP connection comes from unconfigured IP address, close
+socket immediately.
+
+** Do not compare router ID when the routes comes from EBGP peer.
+When originator ID is same, take shorter cluster-list route.  If
+cluster-list is same take smaller IP address neighbor's route.
+
+** Add "bgp bestpath as-path ignore" command.  When this option is
+set, do not concider AS path length when route selection.
+
+** Add "bgp bestpath compare-routerid".  When this option is set,
+compare router ID when the routes comes from EBGP peer.
+
+** Add "bgp deterministic-med" process.
+
+** BGP flap dampening feature is added.
+
+** When IBGP nexthop is changed, it is reflected to RIB.
+
+** Change "neighbor route-refresh" command to "neighbor capability
+route-refresh".
+
+* Changes in ripd
+
+** Change "match ip next-hop" argument from IP address to access-list
+name.
+
+** "no ip rip (send|receive)" command accept version number argument.
+
+** Memory leak related classfull network generation is fixed.
+
+** When a route is in garbage collection process (invalid with metric
+16) and a router receives the same route with valid metric then route
+was not installed into zebra rib, but only into ripd rib. Moreover ,
+it will never get into zebra rib, because ripd wrongly assumes it's
+already there.
+
+* Change in ospfd
+
+** Fix bug of refreshing default route.
+
+** --enable-nssa turn on undergoing NSSA feature.
+
+** Fix bug of Hello packet's option is not properly set when interface
+comes up.
+
+** Reduce unconditional logging.
+
+** Add nexthop to OSPF path only when it is not there.
+
+** When there is no DR on network (suppose you have only one router
+with interface priority 0). It's router LSA does not contain the link
+information about this network.
+
+** When you change a priority of interface from/to 0
+ISM_NeighborChange event should be scheduled in order to elect new
+DR/BDR on the network.
+
+** When we add some LSA into retransmit list we need to check whether
+the present old LSA in retransmit list is not more recent than the new
+one.
+
+** In states Loading and Full the slave must resend its last Database
+Description packet in response to duplicate Database Description
+packets received from the master.  For this reason the slave must wait
+RouterDeadInterval seconds before freeing the last Database
+Description packet. Reception of a Database Description packet from
+the master after this interval will generate a SeqNumberMismatch
+neighbor event. RFC2328 Section 10.8
+
+** Virtual link can not configured in stub area.
+
+** Clear a ls_upd_queue queue of the interface when interface goes
+down.
+
+** "no router ospf" unregister redistribution requests from zebra.
+
+** New command for virtual-link configuration is added.
+
+  "area A.B.C.D virtual-link A.B.C.D"
+  "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>"
+  "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY"
+  "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY"
+  "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY"
+  "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY"
+
+** Clear cryptographic sequence number when neighbor status is changed
+to NSM down.
+
+** Make Summary LSA's origination and refreshment as same as other
+type of LSA.
+
+** New OSPF pakcet read method. Now maximum packet length may be 65535
+bytes (maximum IP packet length).
+
+** Checking the age of the found LSA and if the LSA is MAXAGE we
+should call refresh instead of originate.
+
+** Install multipath information to zebra.
+
+** Fix socket descriptor leak when system call failed.
+
+* Changes in ospf6d
+
+** Whole functionality has been rewritten as new code. new command
+"show ipv6 ospf6 spf node", "show ipv6 ospf6 spf tree", "show ipv6
+ospf6 spf table" has been added.
+
+** Change to do not send garbage route whose nexthop is not linklocal
+address.
+
+** "redistribute ospf6" was generated in "router ospf6" in config
+file. It is fixed.
+
+** LSDB sync bug is fixed.
+
+** Fix bug of using unavailable route.
+
+* Changes in vtysh
+
+** route-map and access-list configuration is merged into one
+configuration.
+
+** /usr/local/etc/Zebra.conf is integrated configuration file.  "write
+memory" in vtysh will write whole configuration to this file.
+
+** When -b option is specified to vtysh, vtysh read
+/usr/local/etc/Zebra.conf file then pass the confuguration to proper
+protocol daemon.  So make all protocol daemon's configuration file
+empty then invoke all daemon.  After that vtysh -b will setup saved
+configuration.
+
+zebrastart.sh
+=============
+/usr/local/sbin/zebra -d
+/usr/local/sbin/ripd -d
+/usr/local/sbin/ospfd -d
+/usr/local/sbin/bgpd -d
+/usr/local/bin/vtysh -b
+\f
+* Changes in zebra-0.89
+
+* Changes in lib
+
+** distribute-list can set all interface's access-list and prefix-list
+configuration.
+
+* Changes in ripd
+
+** "show ip protocols" display proper distribute-list settings and
+distance settings.
+
+** When metric infinity route received withdraw the route from kernel
+immediately it used to be wait garbage collection.
+
+** key-chain can be used for simple password authentication.
+
+** RIPv2 MIB getnext interface bug is fixed.
+
+* Changes in vtysh
+
+** --with-libpam enable PAM authentication for vtysh.
+
+** Now vtysh read vtysh.conf.  This file should be
+${SYSCONFDIR}/etc/vtysh.conf for security reason.  Usually it is
+/usr/local/etc/vtysh.conf.
+
+** "username WORD nopassword" command is added to vtysh.
+
+* Chagees in ospfd
+
+** NBMA interface support is added.
+
+** OSPF area is sorted by area ID.
+
+** New implementation of OSPF refreesh.
+
+** OSPF-MIB read function is partly added.
+
+* Changes in bgpd
+
+** When the peering is done by ebgp-multihop, nexthop is looked up
+like IBGP routes.
+
+** "show ip mbgp" commands are changed to "show ip bgp ipv4
+multicast".
+
+** New terminal commands are added.
+  "show ip bgp ipv4 (unicast|multicast) filter-list WORD"
+  "show ip bgp ipv4 (unicast|multicast) community"
+  "show ip bgp ipv4 (unicast|multicast) community-list WORD"
+  "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match"
+
+** MBGP soft-reconfiguration command is added.
+  "clear ip bgp x.x.x.x ipv4 (unicast|multicast) in"
+  "clear ip bgp x.x.x.x ipv4 (unicast|multicast) out"
+  "clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft"
+  "clear ip bgp <1-65535> ipv4 (unicast|multicast) in"
+  "clear ip bgp <1-65535> ipv4 (unicast|multicast) out"
+  "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft"
+  "clear ip bgp * ipv4 (unicast|multicast) in"
+  "clear ip bgp * ipv4 (unicast|multicast) out"
+  "clear ip bgp * ipv4 (unicast|multicast) soft"
+
+** MED related commands are added.
+  "bgp deterministic-med"
+  "bgp bestpath med confed"
+  "bgp bestpath med missing-as-worst"
+
+** "bgp default local-preference" command is added.
+
+** BGP confederation peer's routes are passed to zebra like IBGP route.
+
+** Community match command is added.
+  "show ip bgp community <val>"
+  "show ip bgp community <val> exact-match"
+
+** EBGP multihop route treatment bug is fixed.  Now nexthop is
+resolved by IGP routes.
+
+** Some commands are added to show routes by filter-list and community
+value.
+  "show ip bgp ipv4 (unicast|multicast) filter-list WORD"
+  "show ip bgp ipv4 (unicast|multicast) community"
+  "show ip bgp ipv4 (unicast|multicast) community-list WORD"
+  "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match"
+
+* Changes in zebra
+
+** zebra read interface's address information using getifaddrs() when
+it is available.
+
+** Reflect IPv6 interface's address change to protocol daemons.
+\f
+* Changes in zebra-0.88
+
+* Changes in lib
+
+** "exact-match" option is added to "access-list" and "ipv6
+access-list" command.  If this option is specified, the prefix and
+prefix length is compared as exact match mode.
+
+* Changes in zebra
+
+** New Zebra message ZEBRA_REDISTRIBUTE_DEFAULT_ADD and
+ZEBRA_REDISTRIBUTE_DEFAULT_DELTE are added.
+
+** Default administrative distance value is changed.
+
+            Old         New
+------------------------------------------
+system      10           0
+kernel      20           0
+connected   30           0
+static      40           1
+rip         50         120
+ripng       50         120
+ospf        60         110
+ospf6       49         110
+bgp         70         200(iBGP)  20(eBGP)
+------------------------------------------
+
+** Distance value can be passed from protocol daemon to zebra.
+
+** "show ip route" shows [metric/distance] value pair.
+
+** Zebra Protocol is changed to support multi-path route and distance
+value.
+
+* Changes in ospfd
+
+** "default-information originate [always]" command is added.
+
+** "default-metric <0-16777214>" command is added.
+
+** "show ip ospf database" command is integrated.  LS-ID and AdvRouter can
+   be specifed.  The commands are
+
+   show ip ospf database TYPE LS-ID
+   show ip ospf database TYPE LS-ID ADV-ROUTER
+   show ip ospf database TYPE LS-ID self-originate
+   show ip ospf database TYPE self-originate
+
+** route-map support for `redistribute' command are added.
+   Supported `match' statements are
+
+   match interface
+   match ip address
+   match next-hop
+
+   Supported `set' statements are
+
+   set metric
+   set metric-type
+
+** Pass OSPF metric value to zebra daemon.
+
+* Changes in ripd
+
+** When specified route-map does not exist, it means all deny.
+
+** "default-metric <1-16>" command is added.
+
+** "offset-list ACCESS-LIST-NAME <0-16>" and "offset-list
+ACCESS-LIST-NAME <0-16> IFNAME" commands are added.
+
+** "redistribute ROUTE-TYPE metric <0-16>" command is added.
+
+** "default-information originate" command is added.
+
+** "ip split-horizon" and "no ip split-horizon" is added to interface
+configuration.
+
+** "no router rip" command is added.
+
+** "ip rip authentication mode (md5|text)" is added to interface
+configuration.
+
+** "ip rip authentication key-chain KEY-CHAIN" is added to interface
+configuration.
+
+** Pass RIP metric value to zebra daemon.
+
+** Distance manipulation functions are added.
+
+* Changes in bgpd
+
+** Fix bug of next hop treatment for MPLS-VPN route exchange.
+
+** BGP peer MIB is updated.
+
+** Aggregated route has origin IGP, atomic-aggregate and proper
+aggregator attribute.
+
+** Suppressed route now installed into BGP table.  It is only
+suppressed from announcement.
+
+** BGP router-id is properly set after "no router bgp ASN" and "router
+bgp ASN".
+
+** Add check for nexthop is accessible or not for IBGP routes.
+
+** Add cehck for nexthop is on connected or not for EBGP routes.
+
+** "dump bgp route" command is changed to "dump bgp route-mrt" for
+generating MRT compatible dump output.
+
+** Soft reconfiguration inbound and outbound is supported.
+
+** Route refresh feature is supported.
+
+* Changes in vtysh
+
+** VTY shell is now included into the distribution.
+\f
+* Changes in zebra-0.87
+
+* Changes in lib
+
+** "show startup-config" command is added.
+
+** "show history" command is added.
+
+** Memory statistics command is changed.  New command
+
+   show memory all
+   show memory lib
+   show memory rip
+   show memory ospf
+   show memory bgp
+
+are added.
+
+** Filters can be removed only specify it's name.  New command
+
+   no access-list NAME
+   no ip community-list NAME
+   no ip as-path access-list NAME
+   no route-map NAME
+
+are added.
+
+** At any node, user can view/save user configuration.
+
+   write terminal
+   write file
+   wirte memory
+
+are added to every node in default.
+
+** LCD completion is added.  For example both "ip" and "ipv6" command
+are exist, "i" then press TAB will be expanded to "ip".
+
+* Changes in bgpd
+
+** "show ip bgp" family shows total number of prefixes.
+
+** "no bgp default ipv4-unicast" command is added.
+
+** Extended Communities support is added.
+
+** "no neighbor PEER send-community extended" command is added.
+
+** MPLS-VPN PE-RR support is added.
+
+ New address family vpnv4 unicast is introduced.
+
+  !
+  address-family vpnv4 unicast
+   neighobr PEER activate
+   network A.B.C.D rd RD tag TAG
+  exit-address-family
+  !
+
+ To make it route-reflector, please configure it under normal router
+bgp ASN.
+
+  !
+  router bgp 7675
+   no bgp default ipv4-unicast
+   bgp router-id 10.0.0.100
+   bgp cluster-id 10.0.0.100
+   neighbor 10.0.0.1 remote-as 65535
+   neighbor 10.0.0.1 route-reflector-client
+   neighbor 10.0.0.2 remote-as 65535
+   neighbor 10.0.0.2 route-reflector-client
+   neighbor 10.0.0.3 remote-as 65535
+   neighbor 10.0.0.3 route-reflector-client
+  !
+  address-family vpnv4 unicast
+   neighbor 10.0.0.1 activate
+   neighbor 10.0.0.2 activate
+   neighbor 10.0.0.3 activate
+  exit-address-family
+  !
+
+* Changes in ospfd
+
+** Many many bugs are fixed.
+
+* Changes in ripd
+
+** Better interface up/down event handle.
+
+* Changes in zebra
+
+** Better interface up/down event handle.
+\f
+* Changes in zebra-0.86
+
+* Changes in lib
+
+** Fix bug of exec-timeout command which may cause crush.
+
+** Multiple same policy for "access-list", "ip prefix-list, "as-path
+access-list", "ip community-list" is not duplicated.
+
+** It used to be "ip prefix-list A.B.C.D/M" match routes which mask >=
+M.  Now default behavior is exact match so it only match routes which
+mask == M.
+
+* Changes in bgpd
+
+** "match ip address prefix-list" is added to route-map.
+
+** A route without local preference is evaluated as 100 local preference.
+
+** Select smaller router-id route when other values are same.
+
+** Compare MED only both routes comes from same neighboring AS.
+
+** "bgp always-compare-med" command is added.
+
+** Now MED value is passed to IBGP peer.
+
+** When neighbor's filter is configured with non-existent access-list,
+as-path access-list, ip prefix-list, route-map.  The behavior is
+changed from all permit to all deny.
+
+* Changes in ospfd
+
+** Fix bug of external route tag byte order.
+
+** OSPF Neighbor deletion bug which cause crush is fixed.
+
+** Some route calculation bug are fixed.
+
+** Add sanity check with router        routing table.
+
+** Fix bug of memory leak about linklist.
+
+** Fix bug of 1-WayReceived in NSM.
+
+** Take care of BIGENDIAN architecture.
+
+** Fix bug of NSM state flapping between ExStart and Exchange.
+
+** Fix bug of Network-LSA originated in stub network.
+
+** Fix bug of MS flag unset.
+
+** Add to schedule router_lsa origination when the interface cost
+changes.
+
+** Increment LS age by configured interface transmit_delay.
+
+** distribute-list is reimplemented.
+
+** Fix bug of refresh never occurs.
+
+** Fix bug of summary-LSAs reorigination.  Correctly copy
+OSPF_LSA_APPROVED flag to new LSA. when summary-LSA is reoriginatd.
+
+** Fix bug of re-origination when a neighbor disappears.
+
+** Fix bug of segmentation fault with DD retransmission.
+
+** Fix network-LSA re-origination problem.
+
+** Fix problem of remaining withdrawn routes on zebra.
+
+* Changes in ripd
+
+** Do not leave from multicast group when interface goes down bug is
+fixed.
+
+* Changes in zebra
+
+** Remove client structure when client dies.
+
+** Take care static route when interface goes up/down.
+\f
+* Changes in zebra-0.85
+
+* Changes in bgpd
+
+** "transparent-nexthop" and "transparenet-as" commands are added.
+
+** Route reflector's originator-id bug is fixed.
+
+* Changes in ospfd
+
+** Fix bug of OSPF LSA memory leak.
+
+** Fix bug of OSPF external route memory leak.
+
+** AS-external-LSA origination bug was fixed.
+
+** LS request treatment is completely rewritten.  Now performance is
+drastically improved.
+
+* Changes in ripd
+
+** RIPv1 update is done by class-full manner.
+\f
+* Changes in zebra-0.84b
+
+* Changes in lib
+
+** Fix bug of inet_pton return value handling
+
+* Changes in bgpd
+
+** Fix bug of BGP-4+ link-local address nexthop check for IBGP peer.
+
+** Don't allocate whole buffer for displaying "show ip bgp".  Now it
+consume only one screen size memory.
+
+* Changes in ripd
+
+** Fix debug output string.
+
+** Add RIP peer handling.  RIP peer are shown by "show ip protocols".
+\f
+* Changes in zebra-0.84a
+
+* Changes in bgpd
+
+** Fix serious bug of BGP-4+ peering under IPv6 link-local address.
+   Due to the bug BGP-4+ peering may not be established.
+\f
+* Changes in zebra-0.84
+
+* Changes in lib
+
+** IPv6 address and prefix parser is added to VTY by Toshiaki Takada
+   <takada@zebra.org>.  DEFUN string is "X:X::X:X" for IPv6 address,
+   "X:X::X:X/M" for IPv6 prefix.  You can use it like this.
+
+   DEFUN (func, cmd, "neighbor (A.B.C.D|X:X::X:X) remote-as <1-65535>")
+
+** VTY configuration is locked during configuration.  This is for
+   avoiding unconditional crush from two terminals modify the
+   configuration at the same time.  "who" command shows which termnal
+   lock the configuration.  VTY which has '*' character at the head of
+   line is locking the configuration.
+
+** Old logging functions are removed.  Functions like
+   log_open,log_close,openlog are deleted.  Instead of that please use
+   zlog_* functions.  zvlog_* used in ospf6d are deleted also.
+
+** "terminal monitor" command is added.  "no terminal monitor" is for
+   disabling.  This command simply display logging information to the
+   VTY.
+
+** dropline.[ch] files are deleted.
+
+* Changes in bgpd
+
+** BGP neighbor configuration are sorted by it's IP address.
+
+** BGP peer configuration and actual peer is separated.  This is
+   preparation for Route Server support.
+
+** "no neighbor PEER" command is added. You can delete neighbor
+   without specifying AS number.
+
+** "no neighbor ebgp-multihop" command is added.
+
+** "no neighbor port PORT" command is added.
+
+** To conform RFC1771, "neighbor PEER send-community" is default
+   behavior.  If you want to disable sending community attribute,
+   please specify "no neighbor PEER send-community" to the peer.
+
+** "neighbor maximum-prefix NUMBER" command is added.
+
+** Multi-protocol extention NLRI is proceeded only when the peer is
+   configured proper Address Family and Subsequent Address Family.  If
+   not, those NLRI are simply ignored.
+
+** Aggregate-address support is improved.  Currently below commands
+   works.
+
+  "aggregate-address"
+  "aggregate-address summary-only"
+  "no aggregate-address"
+  "no aggregate-address summary-only"
+
+  "ipv6 bgp aggregate-address"
+  "ipv6 bgp aggregate-address summary-only"
+  "no ipv6 bgp aggregate-address"
+  "no ipv6 bgp aggregate-address summary-only"
+
+** redistribute route-map bug is fixed.
+
+** MBGP support becomes default.  "configure" option --enable-mbgp is
+   removed.
+
+** New command "neighbor PEER timers connect <1-65535>" is added.
+
+** New command "neighbor PEER override-capability" is added.
+
+** New command "show ip bgp neighbor A.B.C.D advertised-route" is added.
+
+** New command "show ip bgp neighbor A.B.C.D routes" is added.  To use
+   this command, you have to configure neighbor with
+   "neighbor A.B.C.D soft-reconfiguration inbound" beforehand.
+   
+\f
+* Changes in zebra-0.83
+
+* bgpd
+
+** Serious bug fix about fetching global and link-local address at the
+same time.  Due to this bug, corrupted IPv6 prefix is generated.  If
+you uses bgpd for BGP-4+ please update to this version.  The bug is
+introduced in zebra-0.82.
+
+** When bgpd send Notify message, don't use thread manager.  It is now
+send to neighbor immediately.
+\f
+* Changes in zebra-0.82
+
+** Solaris 2.6 support is added by Michael Handler
+<handler@sub-rosa.com>.
+
+** MBGP support is added by Robert Olsson <Robert.Olsson@data.slu.se>.
+Please specify --enable-mbgp to configure script.  This option will be
+removed in the future and MBGP support will be default.
+
+* Changes in zebra
+
+** When interface goes down, withdraw connected routes from routing
+table.  When interface goes up, restore the routes to the routing
+table.
+
+** `show interface' show interface's statistics on Linux and BSD with
+routing socket.
+
+** Now zebra can get MTU value on BSDI/OS.
+
+* Changes in bgpd
+
+** Add capability option support based upon
+draft-ietf-idr-bgp4-cap-neg-04.txt.
+
+** Add `show ipv6 bgp prefix-list' command.
+
+** Check self AS appeared in received routes.
+
+** redistribute route-map support is added.
+
+** BGP packet dump feature compatible with MRT.
+
+* Changes in ripd
+
+** Fix bug of `timers basic' command's argument format.
+
+* Changes in ripngd
+
+** Calculate max RTE using interface's MTU value.
+
+* Changes in ospfd
+
+** Some correction to LSU processing.
+
+** Add check for lsa->refresh_list.
+
+* Changes in ospf6d
+
+** Many debug feature is added.
+\f
+* Changes in zebra-0.81
+
+** SNMP support is disabled in default.--enable-snmp option is added
+to configure script.
+
+* Changes in bgpd
+
+** Fix FSM bug which introduced in zebra-0.80.
+\f
+* Changes in zebra-0.80
+
+* access-list
+
+  New access-list name space `ipv6 access-list' is added.  At the same
+  time, `access-list' statemant only accepts IPv4 prefix.  Please be
+  careful if you use IPv6 filtering.  You will need to change your
+  configuration.  For IPv6 filtering please use `ipv6 access-list'.
+  
+  As of zebra-0.7x, user can use `access-list' for both IPv4 and IPv6
+  filtering.
+  
+  ! zebra-0.7x
+  access-list DML-net permit 203.181.89.0/24
+  access-list DML-net permit 3ffe:506::0/32
+  access-list DML-net deny any
+  !
+  
+  Above configuration is not valid for zebra-08x.  Please add `ipv6'
+  before 'access-list' when you configure IPv6 filtering.
+  
+  ! zebra-0.8x
+  access-list DML-net permit 203.181.89.0/24
+  access-list DML-net deny any
+  !
+  ipv6 access-list DML-net permit 3ffe:506::0/32
+  ipv6 access-list DML-net deny any
+  !
+
+* prefix-list
+
+  And also new prefix-list name space `ipv6 prefix-list' is added.  It
+  is the same as the change of `access-list'. `ip prefix-list' now only
+  accept IPv4 prefix.  It was source of confusion that `ip prefix-list'
+  can be used both IPv4 and IPv6 filtering.  Now name space is separated
+  to clear the meaning of the filter.
+  
+  If you use `ip prefix-list' for IPv6 filtering, please change the
+  stetement.
+  
+  ! zebra-0.7x
+  ip prefix-list 6bone-filter seq 5 permit 3ffe::/17 le 24 ge 24
+  ip prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 le 28 ge 28
+  ip prefix-list 6bone-filter seq 12 deny 3ffe::/16
+  ip prefix-list 6bone-filter seq 15 permit 2000::/3 le 16 ge 16
+  ip prefix-list 6bone-filter seq 20 permit 2001::/16 le 35 ge 35
+  ip prefix-list 6bone-filter seq 30 deny any
+  !
+  
+  Now user can explicitly configure it as IPv6 prefix-list.
+  
+  ! zebra-0.8x
+  ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 le 24 ge 24
+  ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 le 28 ge 28
+  ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16
+  ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 le 16 ge 16
+  ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 le 35 ge 35
+  ipv6 prefix-list 6bone-filter seq 30 deny any
+  !
+
+* RIP configuration
+
+  If you want to filter only default route (0.0.0.0/0) and permit other
+  routes, it was hard to do that.  Now `ip prefix-list' can be used for
+  RIP route filtering.
+  
+  New statement:
+  
+  `distribute-list prefix PLIST_NAME (in|out) IFNAME'
+  
+  is added to ripd.  So you can configure on eth0 interface accept all
+  routes other than default routes.
+  
+  !
+  router rip
+   distribute-list prefix filter-default in eth0
+  !
+  ip prefix-list filter-default deny 0.0.0.0/0 le 0
+  ip prefix-list filter-default permit any
+  !
+
+* RIPng configuration
+
+  Same change is done for ripngd.  You can use `ipv6 prefix-list' for
+  filtering.
+  
+  !
+  router ripng
+   distribute-list prefix filter-default in eth0
+  !
+  ipv6 prefix-list filter-default deny ::/0 le 0
+  ipv6 prefix-list filter-default permit any
+  !
+
+* BGP configuration
+
+  So far, Multiprotocol Extensions for BGP-4 (RFC2283) configuration is
+  done with traditional IPv4 peering statement like blow.
+  
+  !
+  router bgp 7675
+   neighbor 3ffe:506::1 remote-as 2500
+   neighbor 3ffe:506::1 prefix-list 6bone-filter out
+  !
+  
+  For separating configuration IPv4 and IPv6, and for retaining Cisco
+  configuration compatibility, now IPv6 configuration is done by IPv6
+  specific statement.  IPv6 BGP configuration is done by statement which
+  start from `ipv6 bgp'.
+  
+  !
+  router bgp 7675
+  !
+  ipv6 bgp neighbor 3ffe:506::1 remote-as 2500
+  ipv6 bgp neighbor 3ffe:506::1 prefix-list 6bone-filter out
+  !
+  
+  At the same time some IPv6 specific commands are deleted from IPv4
+  configuration.
+  
+  o redistribute ripng
+  o redistribute ospf6
+  o neighbor PEER version BGP_VERSION
+  o neighbor PEER interface IFNAME
+  
+  Those commands are only accepted as like below.
+  
+  o ipv6 bgp redistribute ripng
+  o ipv6 bgp redistribute ospf6
+  o ipv6 bgp neighbor PEER version BGP_VERSION
+  o ipv6 bgp neighbor PEER interface IFNAME
+  
+  And below new commands are added.
+  
+  o ipv6 bgp network IPV6_PREFIX
+  o ipv6 bgp redistribute static
+  o ipv6 bgp redistribute connected
+  o ipv6 bgp neighbor PEER remote-as <1-65535> [passive]
+  o ipv6 bgp neighbor PEER ebgp-multihop [TTL]
+  o ipv6 bgp neighbor PEER description DESCRIPTION
+  o ipv6 bgp neighbor PEER shutdown
+  o ipv6 bgp neighbor PEER route-reflector-client
+  o ipv6 bgp neighbor PEER update-source IFNAME
+  o ipv6 bgp neighbor PEER next-hop-self
+  o ipv6 bgp neighbor PEER timers holdtime <0-65535>
+  o ipv6 bgp neighbor PEER timers keepalive <0-65535>
+  o ipv6 bgp neighbor PEER send-community
+  o ipv6 bgp neighbor PEER weight <0-65535>
+  o ipv6 bgp neighbor PEER default-originate
+  o ipv6 bgp neighbor PEER filter-list FILTER_LIST_NAME (in|out)
+  o ipv6 bgp neighbor PEER prefix-list PREFIX_LIST_NAME (in|out)
+  o ipv6 bgp neighbor PEER distribute-list AS_LIST_NAME (in|out)
+  o ipv6 bgp neighbor PEER route-map ROUTE_MAP_NAME (in|out)
+  
+  And some utility commands are introduced.
+  
+  o clear ipv6 bgp [PEER]
+  o show ipv6 bgp neighbors [PEER]
+  o show ipv6 bgp summary
+  
+  I hope these changes are easy to understand for current Zebra users...
+
+* To restrict connection to VTY interface.
+
+  It used to be both IPv4 and IPv6 filter can be specified with one
+  access-list.  Then the access-list can be appried to VTY interface
+  with `access-class' stetement in `line vty' node.  Below is example in
+  zebra-0.7x.
+  
+  !
+  access-list local-only permit 127.0.0.1/32
+  access-list local-only permit ::1/128
+  access-list local-only deny any
+  !
+  line vty
+   access-class local-only
+  !
+  
+  Now IPv4 and IPv6 filter have each name space.  It is not possible to
+  specify IPv4 and IPv6 filter with one access-list.  For setting IPv6
+  access-list in `line vty', `ipv6 access-class' statement is
+  introduced.  Let me show the configuration in zebra-0.8x.
+  
+  !
+  access-list local-only permit 127.0.0.1/32
+  access-list local-only deny any
+  !
+  ipv6 access-list local-only permit ::1/128
+  ipv6 access-list local-only dny any
+  !
+  line vty
+   access-class local-only
+   ipv6 access-class local-only
+  !
+
+* route-map
+
+  New IPv6 related route-map match commands are added.
+  
+  o match ipv6 address
+  o match ipv6 next-hop
+  
+  Please change your configuration if you use IP match statement for
+  IPv6 route.
+  
+  zebra-0.7x config
+  =================
+  !
+  access-list all permit any
+  !
+  route-map set-nexthop permit 10
+   match ip address all
+   set ipv6 next-hop global 3ffe:506::1
+   set ipv6 next-hop local fe80::cbb5:591a
+  !
+  
+  zebra-0.8x config
+  =================
+  !
+  ipv6 access-list all permit any
+  !
+  route-map set-nexthop permit 10
+   match ipv6 address all
+   set ipv6 next-hop global 3ffe:506::1
+   set ipv6 next-hop local fe80::cbb5:591a
+  !
+
+* zebra connection
+
+  Protocol daemon such as ripd, bgpd, ospfd will reconnect zebra daemon
+  when the connection fail.  Those daemons try to connect zebra every 10
+  seconds first three trial, then the interval changed to 60 seconds.
+  After all, if ten connections are fail, protocol daemon give up the
+  connection to the zebra daemon.
+
+* SNMP support (is not yet finished)
+
+  Zebra uses SMUX protocol (RFC1227) for making communication with SNMP
+  agent.  Currently lib/smux.c can be compiled only with ucd-snmp-4.0.1
+  and http://ucd-snmp.ucdavis.edu/patches/012.patch.  It can not be
+  compiled with ucd-snmp-3.6.2.
+  
+  After applying the patch to ucd-snmp-4.0.1, please configure it with
+  SMUX module.
+  
+  % configure --with-mib-modules=smux
+  
+  After compile & install ucd-snmp-4.0.1, you will need to configure
+  smuxpeer.  I'm now using below configuration.
+  
+  /usr/local/share/snmp/snmpd.conf
+  ================================
+  smuxpeer 1.3.6.1.6.3.1 test
+  
+  Above 1.3.6.1.6.3.1 and test is temporary configuration which is hard
+  coded in lib/smux.c. Yes, I know it is bad, I'll change it ASAP.
+
+* HUP signal treatment
+
+  From zebra-0.80, ripd will reload it's configuration file when ripd
+  receives HUP signal.  Other daemon such as bgpd, ospfd will support
+  HUP signal treatment soon.
+\f
+* Changes in zebra-0.79
+
+* Changes in zebra
+
+** Broadcast address setting on Linux box bug is fixed.
+
+** Protocol daemon can install connected IPv6 route into the kernel.
+
+** Now zebra can handle blackhole route.
+
+* Changes in ripd
+
+** Add route-map feature for RIP protocol.
+
+** In case of RIP version 2 routing table entry has IPv4 address and
+netmask pair which host part bit is on, ignore the entry.
+
+* Changes in ripngd
+
+** Change CMSG_DATA cast from (u_char *) to (int *).  (u_char *) does
+not work for NetBSD-currnet on SparcStation 10.
+
+* Changes in ospfd
+
+** MaxAge LSA treatment is added.
+
+** ABR/ASBR functionality is added.
+
+** Virtual Link funtionality is added.
+
+** ABR behaviors IBM/Cisco/Shortcut is added.
+
+* Changes in ospf6d
+
+** Enclosed KAME specific part with #ifdef #endif
+\f
+* Changes in zebra-0.78
+
+* Changes in lib
+
+** SNMP support is started.
+
+** Now Zebra can work on BSD/OS 4.X.
+
+** Now Zebra can compiled on vanilla OpenBSD 2.5 but not yet working correcltly.
+
+* Changes in zebra
+
+** Interface index detection using ioctl() bug is fixed.
+
+** Interface information protocol is changed.  Now interface
+addition/deletion and interface's address addition/deletion is
+separated.
+
+* Changes in bgpd
+
+** BGP hold timer bug is fixed.
+
+** BGP keepavlie timer becomes configurable.
+
+* Changes in ripd
+
+** When making reply to rip's REQUEST message, fill in
+RIP_METRIC_INFINITY with network byte order using htonl ().
+
+** Pass host byte order address to IN_CLASSC and IN_CLASSB macro.
+
+* Changes in ospfd
+
+** LSA flooding works.
+
+** Fix bug of DD processing.
+
+** Fix bug of originating router-LSA bug is fixed.
+
+** LSA structure is changed to support LSA aging.
+
+* Changes in ospf6d
+
+** `ip6' statement in configuration is changed to `ipv6'.
+\f
+* Changes in zebra-0.77
+
+* Changes in lib
+
+** SIGUSR1 reopen logging file.
+
+** route-map is extended to support multi-protocol routing
+information.
+
+** When compiling under GNU libc 2.1 environment don't use inet6-apps.
+
+* Changes in zebra
+
+** Basic IPv6 router advertisement codes added.  It is not yet usable.
+
+** Fix IPv6 route addition/deletion bug is fixed.
+
+** `show ip route A.B.C.D' works
+
+* Changes in bgpd
+
+** When invalid unfeasible routes length comes, bgpd send notify then
+continue to process the packet.  Now bgpd stop parsing invalid packet
+then return to main loop.
+
+** BGP-4+ withdrawn routes parse bug is fixed.
+
+** When BGP-4+ information passed to non shared network's peer, trim
+link-local next-hop information.
+
+** `no redistribute ROUTE_TYPE' withdraw installed routes from BGP
+routing information.
+
+** `show ipv6 route IPV6ADDR' command added.
+
+** BGP start timer has jitter.
+
+** Holdtimer configuration bug is fixed.  Now configuration does not
+show unconfigured hold time value.
+
+* Changes in ripngd
+
+** Now update timer (default 30 seconds) has +/- 50% jitter value.
+
+** Add timers basic command.
+
+** `network' configuration is dynamically reflected.
+
+** `timers basic <update> <timeout> <garbage>' added.
+
+* Changes in ripd
+
+** Reconstruct almost codes.
+
+** `network' configuration is dynamically reflected.
+
+** RIP timers now conforms to RFC2453.  So user can configure update,
+timeout, garbage timer.
+
+** `timers basic <update> <timeout> <garbage>' works.
+
+* Changes in ospfd
+
+** Bug of originating network LSA is fixed.
+
+** `no router ospf' core dump bug is fixed.
+
+* Changes in ospf6d
+
+** Redistribute route works.
+\f
+* Changes in zebra-0.76
+
+* Changes in lib
+
+** configure.in Linux IPv6 detection problem is fixed.
+
+** Include SERVICES file to the distribution
+
+** Update zebra.texi to zebra-0.76.
+\f
+* Changes in zebra-0.75
+
+* Changes in lib
+
+** `termnal length 0' bug is fixed.
+
+* Changes in zebra
+
+** When zebra starts up, sweep all zebra installed routes.  If -k or
+--keep_kernel option is specified to zebra dameon.  This function is
+not performed.
+
+* Changes in ripngd
+
+** Aggreagte address command supported.  In router ripngd,
+`aggregate-address IPV6PREFIX' works.
+
+* Changes in bgpd
+
+** Input route-map's bug which cause segmentation violation is fixed.
+
+** route-map method improved.
+
+** BGP-4+ nexthop detection improved.
+
+** BGP-4+ route re-selection bug is fixed.
+
+** BGP-4+ iBGP route's nexthop calculation works.
+
+** After connection Established `show ip bgp neighbor' display BGP TCP
+connection's source and destination address.
+
+** In case of BGP-4+ `show ip bgp neighbor' display BGP-4+ global and
+local nexthop which used for originated route.  This address will be
+used when `next-hop-self'.
+
+* Changes in ospfd
+
+** Fix bug of DR election.
+
+** Set IP precedence field with IPTOS_PREC_INTERNET_CONTROL.
+
+** Schedule NeighborChange event if NSM status change.
+
+** Never include a neighbor in Hello packet, when the neighbor goes
+down.
+\f
+* Changes in zebra-0.74
+
+* Changes in lib
+
+** Now `terminal length 0' means no line output control.
+
+** `line LINES' command deleted.  Instead of this please use `terminal
+length <0-512>'.
+
+** `terminal length <0-512>' is each vty specific configuration so it
+can not be configured in the configuration file.  If you want to
+configure system wide line control, please use `service
+terminal-length <0-512>'.  This configuration affects to the all vty
+interface.
+
+* Changes in zebra
+
+** Installation of IPv6 route bug is fixed.
+
+* Changes in bgpd
+
+** Very serious bug of bgp_stop () is fixed. When multiple route to
+the same destination exist, bgpd try to announce the information to
+stopped peer.  Then add orphan write thread is added.  This cause
+many strange behavior of bgpd.
+
+** Router-id parsing bug is fixed.
+
+** With BGP-4+ nexthop installation was done with global address but
+it should be link-local address.  This bug is fixed now.
+
+** When incoming route-map prepend AS, old AS path remained.  Now bgpd
+free old AS path.
+
+** `neighbor PEER weight <0-65535>' command added.
+
+* Changes in ripngd
+
+** Almost codes are rewritten to conform to RFC2080.
+
+* Changes in ospfd
+
+** SPF calculation timer is added.  Currently it is set to 30 seconds.
+
+** SPF calculation works now.
+
+** OSPF routing table codes are added.
+
+** OSPF's internal routes installed into the kernel routing table.
+
+** Now `ospfd' works as non-area, non-external route support OSPF
+router.
+
+** Call of log_rotate() is removed.
+
+* Changes in ospf6d
+
+** LSA data structure is changed.
+
+** Call of log_rotate() is removed.
+\f
+* Changes in zebra-0.73
+
+* Changes in lib
+
+** `config terminal' is changed to `configure terminal'.
+
+** `terminal length <0-512>' command is added.
+
+** Variable length argument was specified by `...'.  Now all strings
+started with character `.' is variable length argument.
+
+* Changes in zebra
+
+** Internal route (such as iBGP, internal OSPF route) handling works
+correctly.
+
+** In interface node, `ipv6 address' and `no ipv6 address' works.
+
+** Interface's address remain after `no ip address' bug is fixed.
+
+** Host route such as IPv4 with /32 mask and IPv6 with /128 mask
+didn't set RTF_GATEWAY even it has gateway.  This bug if fixed now.
+
+* Changes in bgpd
+
+** `match as-path' argument is used to be specify AS PATH value itself
+directly (e.g. ^$).  But it is changed to specify `ip as-apth
+access-list' name.
+
+** iBGP route handle works without getting error from the kernel.
+
+** `set aggregator as AS A.B.C.D' command is added to route-map.
+
+** `set atomic-aggregate' command is added to bgpd's routemap.
+
+** Announcement of atomic aggregate attribute and aggregator attribute
+works.
+
+** `update-source' bug is fixed.
+
+** When a route learned from eBGP is announced to iBGP, local
+preference was set to zero.  But now it set to
+DEFAULT_LOCAL_PREF(100).
+
+* Changes in ripd
+
+** RIPv1 route filter bug is fixed.
+
+** Some memory leak is fixed.
+
+* Changes in ospfd
+
+** Fix bug of DR Election.
+
+** Fix bug of adjacency forming.
+
+* Changes in ospf6d
+
+** Clean up logging message.
+
+** Reflect routing information to zebra daemon.
+\f
+* Changes in zebra-0.72
+
+* Changes in lib
+
+** When getsockname return IPv4 mapped IPv6 address.  Convert it to
+IPv4 address.
+
+* Changes in bgpd
+
+** Change route-map's next-hop related settings.
+
+set ip nexthop          -> set ip next-hop
+set ipv6 nexthop global -> set ipv6 next-hop global
+set ipv6 nexthop local  -> set ipv6 next-hop local
+
+** Add `next-hop-self' command.
+
+* Changes in ospfd
+
+** Fix bug of multiple `network area' directive crashes.
+\f
+* Changes in zebra-0.71
+
+* Changes in lib
+
+** `log syslog' command is added.
+
+** Use getaddrinfo function to bind IPv4/IPv6 server socket.
+
+** `no banner motd' will suppress motd output when user connect to VTY.
+
+** Bind `quit' command to major nodes.
+
+* Changes in zebra
+
+** Point-to-point link address handling bug is fixed.
+
+* Changes in bgpd
+
+** AS path validity check is added.  If malformed AS path is received
+NOTIFY Malformed AS path is send to the peer.
+
+** Use getaddrinfo function to bind IPv4/IPv6 server socket.
+
+* Changes in ripd
+
+** Connected network announcement bug is fixed.
+
+** `broadcast' command is deleted.
+
+** `network' command is added.
+
+** `neighbor' command is added.
+
+** `redistribute' command is added.
+
+** `timers basic' command is added.
+
+** `route' command is added.
+
+* Changes in ripngd
+
+** Fix metric calculation bug.
+
+* Changes in ospfd
+
+** Check sum bug is fixed.
+
+* Chanegs in ospf6d
+
+** Routing table code is rewritten.
+\f
+* Changes in zebra-0.70
+
+* Changes in zebra
+
+** Critical routing information base calculation bug check is fixed.
+
+** zebra ipv4 message is extended to support external/internal route
+flavor.
+
+** Now if internal route doesn't has direct connected nexthop, then
+nexthop is calculated by looking up IGP routing table.
+
+* Changes in bgpd
+
+** `neighbor PEER update-source IFNAME' command added as ALIAS to
+`neighbor PEER interface IFNAME'.
+
+* Changes in ospfd
+
+** DD null pointer bug is fixed.
+\f
+* Changes in zebra-0.69
+
+* Changes in zebra
+
+** zebra redistirbution supports dynamic notification of the route
+change.  If you add static route while running zebra, it will be
+reflected to other protocol daemon which set `redistribute static'.
+
+** If static route installation is failed due to the error.  The
+static route is not added to the configuration and zebra routing
+table.
+
+** zebra sets forwarding flag to on when it starts up.
+
+** `no ip forwarding' turn off IPv4 forwarding.
+
+** `no ipv6 forwarding' turn off IPv6 forwarding.
+
+** Change `show ipforward' command to `show ip forwarding'.
+
+** Change `show ipv6forward' command to `show ipv6 forwarding'.
+
+** `ip route A.B.C.D/M INTERFACE' works.  So you can set `ip route
+10.0.0.0/8 eth0'.
+
+* Changes in bgpd
+
+** `neighbor PEER send-community' command is added.  If the option is
+set, bgpd will send community attribute to the peer.
+
+** When a BGP route has no-export community attribute and
+send-community is set to the peer, the route is not announced to the
+peer.
+
+* Changes in ripngd
+
+** When ripngd terminates, delete all installed route.
+
+** `redistribute static', `redistribute connected' works.
+
+** Change `debug ripng event' to `debug ripng events'.
+
+** Change `show debug ripng' to `show debugging ripng'.
+
+** Bug of static route deletion is fixed.
+
+* Changes in ospfd
+
+** LS request and LS update can be send and received.
+\f
+* Changes in zebra-0.68
+
+* Changes in lib
+
+** DEFUN() is extended to support (a|b|c) statement.
+
+** Input buffer overflow bug is fixed.
+
+* Changes in bgpd
+
+** `ip community-list' is added.
+
+** set community and match community is added to route-map statement.
+
+** aggregate-address A.B.C.D/M partly works.  Now it works only
+summary-only mode.
+
+* Changes in zebra
+
+** IPv6 network address delete bug is fixed.
+
+* Changes in ospfd
+
+** DR election bug fixed.
+
+** Now Database Description can be send or received.
+
+** Neighbor State Machine goes to Full state.
+
+* Changes in ospf6d
+
+** router zebra related bug is fixed.
+\f
+* Changes in zebra-0.67
+
+* Changes in lib
+
+** `service password-encryption' is added for encrypted password.
+
+* Changes in bgpd
+
+** `set as-path prepend ASPATH' is added to route-map command.
+
+** `set weight WEIGHT' is added to route-map command.
+
+** `no set ipv6 nexthop global' and `no set ipv6 nexthop local'
+command is added to route-map.
+
+** `neighbor IP_ADDR version BGP_VERSION' command's BGP_VERSION
+argument changed.
+
+Old               New
+=====================
+bgp4              4
+bgp4+             4+
+bgp4+-draft-00    4-
+=====================
+
+If you want to peer with old draft version of BGP-4+, please configure
+like below:
+
+router bgp ASN
+ neighbor PEER version 4-
+
+** Some AS path isn't correctly compared during route selection.  Now
+it is fixed.
+
+* Changes in ospfd
+
+** `router zebra' is default behavior.
+
+* Changes in ospf6d
+
+** `router zebra' is default behavior.
+\f
+* Changes in zebra-0.66
+
+* Changes in zebra
+
+** When other daemon such as gated install routes into the kernel then
+zebra blocks.  This is only occur with netlink socket.  Now socket is
+set as NONBLOCKING and problem is fixed.  Reported and fixed by
+Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+* Changes in bgpd
+
+** Now `router zebra' is not needed to insert BGP routes into the
+kernel.  It is default behavior.  If you don't want to install the BGP
+routes to the kernel, please configure like below:
+
+!
+router zebra
+ no redistribute bgp
+!
+
+** redistribute connected works.
+
+** redistribute static now filter local loopback routes and link local
+network.
+
+* Changes in ripd
+
+** Some network check is added.  Patch is done by Carlos Alberto
+Barcenilla <barce@frlp.utn.edu.ar>
+
+* Changes in ripngd
+
+** Sometimes ripngd install wrong nexthop into the kernel.  This bug
+is fixed now.
+
+** Now `router zebra' is not needed to insert RIPng routes into the
+kernel.  It is default behavior. If you don't want to install the BGP
+routes to the kernel, please configure like below:
+
+!
+router zebra
+ no redistribute ripng
+!
+\f
+* Changes in zebra-0.65
+
+* Changes in lib
+
+** `C-c' changes current node to ENABLE_NODE.  Previously it doesn't.
+
+** In ENABLE_NODE, `exit' command close vty connection.
+
+** `service advanced-vty' enable advanced vty function.  If this
+service is specified one can directly connect to ENABLE_NODE when
+enable password is not set.
+
+** `lines LINES' command is added by Stephen R. van den Berg
+<srb@cuci.nl>.
+
+* Changes in zebra
+
+** Basic Linux policy based routing table support is added by Stephen
+R. van den Berg <srb@cuci.nl>.
+
+* Changes in bgpd
+
+** route-map command is improved:
+  `match ip next-hop': New command.
+  `match metric': New command.
+  `set metric': Doc fixed.
+  `set local-preference': DEFUN added.
+
+* Changes in ripd
+
+** Check of announced network is added.  Now multicast address is
+filtered.  Reported by Carlos Alberto Barcenilla
+<barce@frlp.utn.edu.ar>
+
+** Check of network 127 is added.  Reported by Carlos Alberto
+Barcenilla <barce@frlp.utn.edu.ar>
+
+* Changes in ripngd
+
+** Aging route bug is fixed.
+
+** `router zebra' semantics changed.  ripngd automatically connect to
+zebra.
+
+* Changes in ospfd
+
+** `no router ospf' works.
+
+* Changes in ospf6d
+
+** Bug fix about network vertex.
+\f
+* Changes in zebra-0.64.1.
+
+This is bug fix release.
+
+* Changes in lib
+
+** Add check of sin6_scope_id in struct sockaddr_in6.  For compilation
+on implementation which doesn't have sin6_scope_id.  Reported by Wim
+Biemolt <Wim.Biemolt@ipv6.surfnet.nl>.
+
+* Changes in zebra
+
+** Fix bug of display BGP routes as "O" instead of "B".  Reported by
+"William F. Maton" <wmaton@enterprise.ic.gc.ca> and Dave Hartzell
+<hartzell@greatplains.net>.
+
+* Changes in bgpd
+
+** `no network IPV6_NETWORK' statement and `no neighbor IP_ADDR timers
+holdtime [TIMER]' statement doesn't work. Reported by Georg Hitsch
+<georg@atnet.at>.  Now both statement work.
+
+* Changes in ospfd
+
+** Last interface is not updated by ospf_if_update().  Reported by
+Dave Hartzell <hartzell@greatplains.net>.
+
+* Changes in ospf6d
+
+** Byte order of ifid is changed.  Due to this change, this code will
+not work with previous version, sorry.
+
+** Fix `show ip route' route type mismatch.
+
+** Fix bug of no network IPV6_NETWORK.
+
+** Important bug fix about intra-area-prefix-lsa.
+\f
+* Changes in zebra-0.64.
+
+* Changes in lib
+
+** prefix-list based filtering routine is added.  Currently used in
+bgpd but it will be in other daemons.
+
+* Changes in bgpd
+
+** `no router bgp' works.  But network statement is not cleared.  This
+should be fixed in next beta.
+
+** Route reflector related statement is added.
+
+  router bgp ASN
+    bgp cluster-id a.b.c.d
+    neighbor a.b.c.d route-reflector-client
+
+  is added.
+
+** Prefix list based filtering is added.
+
+  router bgp ASN
+    neighbor a.b.c.d prefix-list PREFIX_LIST_NAME
+
+** Prefix list based routing display works.
+
+  show ip bgp prefix-list PREFIX_LIST_NAME
+
+* Changes in ripd
+
+** Fix route metric check bug.  Reported from Mr. Carlos Alberto
+Barcenilla.
+
+* Changes in ospf6d
+
+** There are many changes.  If you have interested in ospf6d please
+visit ospf6d/README file.
+\f
+* Changes in zebra-0.63 first beta package.
+
+* Changes in lib
+
+** `copy running-config stgartup-config' command is added.
+
+** prefix length check bug is fixed.  Thanks Marlos Barcenilla
+<barce@frip.utn.edu.ar>.
+
+* Changes in ospfd
+
+** DR and BDR election works.
+
+** OSPF Hello simple authentication works.
+
+* Changes in ospf6d
+
+** Now ospf6d can be compiled on both Linux and *BSD system.
+\f
+* Changes in zebra-19990420 snapshot
+
+** `make dist' at top directory works now.
+
+* Changes in lib
+
+** VTY has now access-class to restrict remote connection.
+Implemented by Alex Bligh <amb@gxn.net>.
+
+!
+line vty
+  access-class ACCESS-LIST-NAME
+!
+
+** `show version' command added.  Implemented by Carlos Alberto
+Barcenilla <barce@frlp.utn.edu.ar>
+
+* Changes in zebra
+
+** `ip address' command on *BSD bug is fixed.
+
+** `no ip address' works now for IPv4 address.
+
+** Now `write terminal' display `ip address' configuration.
+
+* Changes in bgpd
+
+** Redistribute static works now.  Please run both zebra and bgpd.
+bgpd.conf should be like this:
+
+!
+router zebra
+!
+router bgp ASN
+  redisitribute static
+!
+
+* Changes in guile
+
+** configure --enable-guile turns on zebra-guile build.
+
+** (router-bgp ASN) allocates real bgp structre.
+\f
+* Changes in zebra-19990416 snapshot
+
+** Set version to 0.60 for preparation of beta release.
+
+** New directory guile is added for linking with guile interpreter.
+
+* Changes in zebra
+
+** On GNU/Linux Kernel 2.2.x (with netlink support), zebra detects
+asynchronous routing updates.  *BSD support is not yet finished.
+
+* Changes in bgpd
+
+** `show ip bgp regexp ASPATH_REGEX' uses CISCO like regular expression 
+instead of RPSL like regular expression.  I'm planing to provide RPSL
+like regular expression with `show ip bgp rpsl' or something.
+
+* Changes in lib
+
+** Press '?' at variable mandatory argument, vty prints nothing.  Now
+vty outputs description about the argument.  Fixed by Alex Bligh
+<amb@gxn.net>
+
+** buffer.c has some ugly bugs.  Due to the bug, vty interface hangs
+when large output date exists.  This bug is fixed. Reported by Alex
+Bligh <amb@gxn.net>.
+
+* Changes in ospfd
+
+** DR and BDR information is shown by `show ip ospf interface' command.
+\f
+* Changes in zebra-19990408 snapshot
+
+* Changes in bgpd
+
+** Old BGP-4+ specification (described in old draft) treatment bug is
+fixed.  It seems that mrtd uses this format as default.  So if you
+have problem peering with mrtd and want to use old draft format please
+use version statement like this.
+
+neighbor PEER_ADDRESS remote-as ASN
+neighbor PEER_ADDRESS version bgp4+-draft-00
+
+** When AS path is epmty (routes generated by bgpd), SEGV is occur
+when announce the routes to eBGP peer.  Reported by
+kad@gibson.skif.net.
+
+** ip as-path access-list command is added.
+
+** neighbor PEER_ADDRESS filter-list AS_LIST [in|out] command is added.
+
+** neighbor PEER_ADDRESS timers holdtimer TIMER command is added.
+
+* Changes in all daemons
+
+** With KAME stack, terminal interface is now bind AF_INET socket
+instead of AF_INET6 one.
+\f
+* Changes in zebra-19990403 snapshot
+
+* Changes in bgpd
+
+** When bgpd has 'router zebra', bgpd automatically select it's router
+ID as most highest interface's IP Address.
+
+** When AS path is empty (in case of iBGP), it doesn't include any AS
+segment.  This change is for announcement to gated under iBGP.
+
+* Changes in ospfd
+
+** OSPF hello packet send/receive works.
+
+* Changes in ospf6d
+
+** Yasuhiro Ohara's ospf6d codes is imported.  It is under development
+and can't be compiled on any platform.
+\f
+* Changes in zebra-19990327 snapshot
+
+* Changes in bgpd
+
+** When BGP-4+ connection is done by IPv6 link-local address.  One
+have to specify interface index for the connection.  So I've added
+interface statement to the neighbor commmand.  Please specify
+interface name for getting interface index like below.  This statement
+only works on GNU/Linux.  I'll support BSD ASAP.
+
+router bgp 7675
+ neighbor fe80::200:f8ff:fe01:5fd3 remote-as 2500
+ neighbor fe80::200:f8ff:fe01:5fd3 interface sit3
+
+** For disable BGP peering `shutdown' command is added.
+
+router bgp 7675
+ neighbor 10.0.0.1 shutdown
+
+** `description' command is added to neighbor statement.
+
+router bgp 7675
+ neighbor 10.0.0.1 description peering with Norway.
+
+** `show ip bgp regexp AS-REGEXP' works again.
+
+show ip bgp regexp AS7675
+
+will show routes which include AS7675.
+
+** When a route which is made from `network' statement is send to
+neighbor.  Set it's nexthop to self.  So 10.0.0.0/8 is announced to
+the peer A with source address 192.168.1.1.  The routes nexthop is set
+to 192.168.1.1.
+
+* Changes in zebra
+
+** In zebra/rtread_sysctl.c, function rtm_read() may overrun allocated
+buffer when the address family is not supported and the length is big
+(i.e link address).  Reported Achim Patzner <ap@bnc.net>.
+
+* Changes in ospfd
+
+** Now ospfd receive OSPF packet.
+\f
+* Changes in zebra-19990319 snapshot
+
+* Changes in configuration and libraries
+
+** User can disable IPv6 feature and/or pthread feature by configure
+   option.
+
+  To disable IPv6:    configure --disable-ipv6
+  To disable pthread: configure --disable-pthread
+
+** User can disable specified daemon by configure option.
+
+  Don't make zebra:  configure --disable-zebra
+  Don't make bgpd:   configure --disable-bgpd
+  Don't make ripd:   configure --disable-ripd
+  Don't make ripngd: configure --disable-ripngd
+  Don't make ospfd:  configure --disable-ospfd
+  Don't make ospf6d: configure --disable-ospf6d
+
+** Sample configuration files are installed as 600 file flag.
+   Suggested by Jeroen Ruigrok/Asmodai <asmodai@wxs.nl>.
+
+** syslog logging feature is added by Peter Galbavy
+   <Peter.Galbavy@knowledge.com>
+
+** Inclusion of standard header files is reworked by Peter Galbavy
+   <Peter.Galbavy@knowledge.com>
+
+** Change description from GNU/Linux 2.1.X to GNU/Linux 2.2.X
+
+** If daemon function exists in standard C library use it.
+
+** To generate configure script we upgrade autoconf to 2.13.  To
+generate Makefile.in we upgrade automake to 1.4.
+
+** doc/texinfo.tex is added to distribution.
+
+** Update ports/pkg/DESCR description.
+
+** Update doc/zebra.texi.
+
+** logfile FILENAME statement deleted.  Instead of that please use log
+file FILENAME.
+
+* Changes in zebra
+
+* Changes in bgpd
+
+** Communication between zebra and bgpd works now.  So if there is
+   `router zebra' line in bgpd.conf, selected route is installed
+   into kernel routing table.
+
+** Delete all routes which inserted by bgpd when bgpd dies.  If you
+want to retain routes even bgpd dies please specify [-r|--retain]
+option to bgpd.
+
+** BGP announcement code is reworked.  Now bgpd announce selected
+   routes to other peer.
+
+** All output bgp packet is buffered.  It's written to the socket when
+   it gets ready.
+
+** Output route-map works now.  You can specify output route-map by:
+
+   neighbor IP_ADDR route-map ROUTE_MAP_NAME out
+
+** New route-map command added.
+
+   set ip nexthop IP_ADDR
+   set ipv6 nexthop global IP_ADDR
+
+** Fix bug about unlock of the route_node structure.
+
+** BGP-4+ support is added.  bgpd can listen and speak BGP-4+ packet
+specified in RFC2283. You can view IPv6 bgp table by: `show ipv6 bgp'.
+
+** Meny packet overflow check is added.
+
+* Changes in ripd
+
+* Changes in ripngd
+
+* Changes in ospfd
+
+** ospfd work is started by Toshiaki Takada <takada@zebra.org>.  Now
+several files are included in ospfd directory.
+
+** ospf6d codes are merged from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s
+ospfd work.  Now codes are located in ospf6d directory.
+
+\f
+Local variables:
+mode: outline
+paragraph-separate: "[         \f]*$"
+end:
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..72bccfc
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+GNU Zebra is free software that manages various IPv4 and IPv6 routing
+protocols.
+
+Currently GNU Zebra supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1,
+RIPv2, and RIPng.
+  
+See the file INSTALL for building and installation instructions.
+  
+See the file REPORTING-BUGS to report bugs.
+  
+GNU Zebra is free software. See the file COPYING for copying conditions.
+
diff --git a/REPORTING-BUGS b/REPORTING-BUGS
new file mode 100644 (file)
index 0000000..d6b23dd
--- /dev/null
@@ -0,0 +1,28 @@
+This file describes the procedure for reporting Zebra bugs.
+You are not obliged to follow this format , but it would be
+great help for Zebra developers if you report a bug as described
+below.
+
+Send your report to bug-zebra@gnu.org mailing list.
+
+Please supply the following information:
+1. Your zebra version or if it is CVS version then the date you did checkout.
+Always try to report the bugs on the current CVS version.
+2. Zebra daemons you run e.g. bgpd or ripd, your OS full name,
+any specific options you compiled zebra with. 
+3. Problem description. Copy and paste relative zebra commands and their
+output to describe your network setup e.g. "zebra>show ip route".
+Please, also give your simple network layout and output of relative OS commands
+(e.g. ifconfig).
+4. All zebra configuration files you use. If you don't want to publish
+your network numbers change 2 middle bytes in IPv4 address to be XXX e.g.
+192.XXX.XXX.32/24. Similar could be done with IPv6.
+5. If any zebra daemon core dumped, please, supply stack trace using
+the following commands: host> gdb exec_file core_file , (gdb) bt .
+6. Run all zebra daemons with full debugging on (see documentation on debugging) and
+send _only_ part of logs which are relative to your problem.
+7. If the problem is difficult to reproduce please send a shell script to
+reproduce it.
+8. Patches, workarounds, fixes are always welcome.
+
+Thank You.
diff --git a/SERVICES b/SERVICES
new file mode 100644 (file)
index 0000000..41d4b94
--- /dev/null
+++ b/SERVICES
@@ -0,0 +1,17 @@
+# As long as this software is in alpha testing it is not yet included
+# in /etc/services files. This means that you may need to add the following
+# lines into your /etc/services file on your hosts.
+# 
+# --- Please add this to your /etc/services ---
+
+#
+# GNU Zebra services
+#
+
+zebrasrv       2600/tcp
+zebra          2601/tcp
+ripd           2602/tcp
+ripng          2603/tcp
+ospfd          2604/tcp
+bgpd           2605/tcp
+ospf6d         2606/tcp
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..4c8b7b6
--- /dev/null
+++ b/TODO
@@ -0,0 +1,29 @@
+
+                          Zebra TODO list
+                             2002/06/18
+
+zebra:
+
+o Pointopoint address configuration.
+o Multiple (alias) address configuration for the interface when kernel
+  support it [just starting].
+
+bgpd:
+
+o BGP TCP MD5 authentication (on OpenBSD) by password command.
+o HUP signal support (reload configuration file).
+o BGP multi-path extension
+
+ripd:
+
+o Multipath support.
+
+ospfd:
+
+o Rewrite the incremental RT update code.
+o Demand circuits.
+o Multiple instances.
+o OSPF MIB [SNMP get is amost finished].
+o HUP signal treatment.
+--
+Kunihiro Ishiguro <kunihiro@zebra.org>
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..de39bc8
--- /dev/null
@@ -0,0 +1,161 @@
+/* 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
+
+/* 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/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..5401d28
--- /dev/null
@@ -0,0 +1,811 @@
+# generated automatically by aclocal 1.7 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Do all the work for Automake.                            -*- Autoconf -*-
+
+# This macro actually does too much some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 8
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+AC_PREREQ([2.54])
+
+# Autoconf 2.50 wants to disallow AM_ names.  We explicitly allow
+# the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+ AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+   test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], [AC_PACKAGE_TARNAME])dnl
+ AC_SUBST([VERSION], [AC_PACKAGE_VERSION])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_MISSING_PROG(AMTAR, tar)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+                  [_AM_DEPENDENCIES(CC)],
+                  [define([AC_PROG_CC],
+                          defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+                  [_AM_DEPENDENCIES(CXX)],
+                  [define([AC_PROG_CXX],
+                          defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[_am_stamp_count=`expr ${_am_stamp_count-0} + 1`
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# Copyright 2002  Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.7"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+        [AM_AUTOMAKE_VERSION([1.7])])
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+
+# Copyright 2001, 2002  Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 2
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+#  -*- Autoconf -*-
+
+
+# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# AM_AUX_DIR_EXPAND
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+# Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])
+
+AC_DEFUN([AM_AUX_DIR_EXPAND], [
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# AM_PROG_INSTALL_STRIP
+
+# Copyright 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# serial 4                                             -*- Autoconf -*-
+
+# Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    echo '#include "conftest.h"' > conftest.c
+    echo 'int i;' > conftest.h
+    echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+       continue
+      else
+       break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=conftest.c object=conftest.o \
+       depfile=conftest.Po tmpdepfile=conftest.TPo \
+       $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 &&
+       grep conftest.h conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      am_cv_$1_dependencies_compiler_type=$depmode
+      break
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[rm -f .deps 2>/dev/null
+mkdir .deps 2>/dev/null
+if test -d .deps; then
+  DEPDIR=.deps
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  DEPDIR=_deps
+fi
+rmdir .deps 2>/dev/null
+AC_SUBST([DEPDIR])
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking Speeds up one-time builds
+  --enable-dependency-tracking  Do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking.   -*- Autoconf -*-
+
+# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#serial 2
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+  # Strip MF so we end up with the name of the file.
+  mf=`echo "$mf" | sed -e 's/:.*$//'`
+  # Check whether this is an Automake generated Makefile or not.
+  # We used to match only the files named `Makefile.in', but
+  # some people rename them; so instead we look at the file content.
+  # Grep'ing the first line is not enough: some people post-process
+  # each Makefile.in and add a new line on top of each file to say so.
+  # So let's grep whole file.
+  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+    dirpart=`AS_DIRNAME("$mf")`
+  else
+    continue
+  fi
+  grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue
+  # Extract the definition of DEP_FILES from the Makefile without
+  # running `make'.
+  DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"`
+  test -z "$DEPDIR" && continue
+  # When using ansi2knr, U may be empty or an underscore; expand it
+  U=`sed -n -e '/^U = / s///p' < "$mf"`
+  test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR"
+  # We invoke sed twice because it is the simplest approach to
+  # changing $(DEPDIR) to its actual value in the expansion.
+  for file in `sed -n -e '
+    /^DEP_FILES = .*\\\\$/ {
+      s/^DEP_FILES = //
+      :loop
+       s/\\\\$//
+       p
+       n
+       /\\\\$/ b loop
+      p
+    }
+    /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \
+       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+    # Make sure the directory exists.
+    test -f "$dirpart/$file" && continue
+    fdir=`AS_DIRNAME(["$file"])`
+    AS_MKDIR_P([$dirpart/$fdir])
+    # echo "creating $dirpart/$file"
+    echo '# dummy' > "$dirpart/$file"
+  done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Check to see how 'make' treats includes.     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 2
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+doit:
+       @echo done
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+AC_SUBST(am__include)
+AC_SUBST(am__quote)
+AC_MSG_RESULT($_am_result)
+rm -f confinc confmf
+])
+
+# AM_CONDITIONAL                                              -*- Autoconf -*-
+
+# Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 5
+
+AC_PREREQ(2.52)
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+        [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.])
+fi])])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*-
+
+# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+AC_PREREQ([2.52])
+
+# serial 6
+
+# AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore
new file mode 100644 (file)
index 0000000..8edffb6
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile
+*.o
+bgpd
+bgp_btoa
+bgpd.conf
+tags
+TAGS
+.deps
diff --git a/bgpd/BGP4-MIB.txt b/bgpd/BGP4-MIB.txt
new file mode 100644 (file)
index 0000000..c911316
--- /dev/null
@@ -0,0 +1,929 @@
+    BGP4-MIB DEFINITIONS ::= BEGIN
+
+        IMPORTS
+            MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+            IpAddress, Integer32, Counter32, Gauge32, mib-2
+                FROM SNMPv2-SMI
+            MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+                FROM SNMPv2-CONF;
+
+        bgp MODULE-IDENTITY
+            LAST-UPDATED "9902100000Z"
+            ORGANIZATION "IETF IDR Working Group"
+            CONTACT-INFO "E-mail:  idr@merit.net
+
+                          Susan Hares  (Editor)
+                          Merit Network
+                          4251 Plymouth Road
+                          Suite C
+                          Ann Arbor, MI 48105-2785
+                          Tel: +1 734 936 2095
+                          Fax: +1 734 647 3185
+                          E-mail: skh@merit.edu
+
+                          Jeff Johnson (Editor)
+                          RedBack Networks, Inc.
+                          1389 Moffett Park Drive
+                          Sunnyvale, CA  94089-1134
+                          Tel: +1 408 548 3516
+                          Fax: +1 408 548 3599
+                          E-mail: jeff@redback.com"
+            DESCRIPTION
+                    "The MIB module for BGP-4."
+            REVISION    "9902100000Z"
+            DESCRIPTION
+                    "Corrected duplicate OBJECT IDENTIFIER
+                     assignment in the conformance information."
+            REVISION    "9601080000Z"
+            DESCRIPTION
+                    "1) Fixed the definitions of the traps to
+                     make them equivalent to their initial
+                     definition in RFC 1269.
+                     2) Added compliance and conformance info."
+            ::= { mib-2 15 }
+
+        bgpVersion OBJECT-TYPE
+            SYNTAX     OCTET STRING (SIZE (1..255))
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "Vector of supported BGP protocol version
+                    numbers.  Each peer negotiates the version
+                    from this vector.  Versions are identified
+                    via the string of bits contained within this
+                    object.  The first octet contains bits 0 to
+                    7, the second octet contains bits 8 to 15,
+                    and so on, with the most significant bit
+                    referring to the lowest bit number in the
+                    octet (e.g., the MSB of the first octet
+                    refers to bit 0).  If a bit, i, is present
+                    and set, then the version (i+1) of the BGP
+                    is supported."
+            ::= { bgp 1 }
+
+        bgpLocalAs OBJECT-TYPE
+            SYNTAX     INTEGER (0..65535)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The local autonomous system number."
+            ::= { bgp 2 }
+
+
+
+        -- BGP Peer table.  This table contains, one entry per BGP
+        -- peer, information about the BGP peer.
+
+        bgpPeerTable OBJECT-TYPE
+            SYNTAX     SEQUENCE OF BgpPeerEntry
+            MAX-ACCESS not-accessible
+            STATUS     current
+            DESCRIPTION
+                    "BGP peer table.  This table contains,
+                    one entry per BGP peer, information about the
+                    connections with BGP peers."
+            ::= { bgp 3 }
+
+        bgpPeerEntry OBJECT-TYPE
+            SYNTAX     BgpPeerEntry
+            MAX-ACCESS not-accessible
+            STATUS     current
+            DESCRIPTION
+                    "Entry containing information about the
+                    connection with a BGP peer."
+            INDEX { bgpPeerRemoteAddr }
+            ::= { bgpPeerTable 1 }
+
+        BgpPeerEntry ::= SEQUENCE {
+                bgpPeerIdentifier
+                    IpAddress,
+                bgpPeerState
+                    INTEGER,
+                bgpPeerAdminStatus
+                    INTEGER,
+                bgpPeerNegotiatedVersion
+                    Integer32,
+                bgpPeerLocalAddr
+                    IpAddress,
+                bgpPeerLocalPort
+                    INTEGER,
+                bgpPeerRemoteAddr
+                    IpAddress,
+                bgpPeerRemotePort
+                    INTEGER,
+                bgpPeerRemoteAs
+                    INTEGER,
+                bgpPeerInUpdates
+                    Counter32,
+                bgpPeerOutUpdates
+                    Counter32,
+                bgpPeerInTotalMessages
+                    Counter32,
+                bgpPeerOutTotalMessages
+                    Counter32,
+                bgpPeerLastError
+                    OCTET STRING,
+                bgpPeerFsmEstablishedTransitions
+                    Counter32,
+                bgpPeerFsmEstablishedTime
+                    Gauge32,
+                bgpPeerConnectRetryInterval
+                    INTEGER,
+                bgpPeerHoldTime
+                    INTEGER,
+                bgpPeerKeepAlive
+                    INTEGER,
+                bgpPeerHoldTimeConfigured
+                    INTEGER,
+                bgpPeerKeepAliveConfigured
+                    INTEGER,
+                bgpPeerMinASOriginationInterval
+                    INTEGER,
+                bgpPeerMinRouteAdvertisementInterval
+                    INTEGER,
+                bgpPeerInUpdateElapsedTime
+                    Gauge32
+                }
+
+        bgpPeerIdentifier OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The BGP Identifier of this entry's BGP peer."
+            ::= { bgpPeerEntry 1 }
+
+        bgpPeerState OBJECT-TYPE
+            SYNTAX     INTEGER {
+                                idle(1),
+                                connect(2),
+                                active(3),
+                                opensent(4),
+                                openconfirm(5),
+                                established(6)
+                       }
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The BGP peer connection state."
+            ::= { bgpPeerEntry 2 }
+
+        bgpPeerAdminStatus OBJECT-TYPE
+            SYNTAX     INTEGER {
+                                stop(1),
+                                start(2)
+                       }
+            MAX-ACCESS read-write
+            STATUS     current
+            DESCRIPTION
+                    "The desired state of the BGP connection.  A
+                    transition from 'stop' to 'start' will cause
+                    the BGP Start Event to be generated.  A
+                    transition from 'start' to 'stop' will cause
+                    the BGP Stop Event to be generated.  This
+                    parameter can be used to restart BGP peer
+                    connections.  Care should be used in providing
+                    write access to this object without adequate
+                    authentication."
+            ::= { bgpPeerEntry 3 }
+
+        bgpPeerNegotiatedVersion OBJECT-TYPE
+            SYNTAX     Integer32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The negotiated version of BGP running between
+                    the two peers."
+            ::= { bgpPeerEntry 4 }
+
+        bgpPeerLocalAddr OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The local IP address of this entry's BGP
+                    connection."
+            ::= { bgpPeerEntry 5 }
+
+        bgpPeerLocalPort OBJECT-TYPE
+            SYNTAX     INTEGER (0..65535)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The local port for the TCP connection between
+                    the BGP peers."
+            ::= { bgpPeerEntry 6 }
+
+        bgpPeerRemoteAddr OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The remote IP address of this entry's BGP
+                    peer."
+            ::= { bgpPeerEntry 7 }
+
+        bgpPeerRemotePort OBJECT-TYPE
+            SYNTAX     INTEGER (0..65535)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The remote port for the TCP connection between
+                    the BGP peers.  Note that the objects
+                    bgpPeerLocalAddr, bgpPeerLocalPort,
+                    bgpPeerRemoteAddr and bgpPeerRemotePort
+                    provide the appropriate reference to the
+                    standard MIB TCP connection table."
+            ::= { bgpPeerEntry 8 }
+
+        bgpPeerRemoteAs OBJECT-TYPE
+            SYNTAX     INTEGER (0..65535)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The remote autonomous system number."
+            ::= { bgpPeerEntry 9 }
+
+        bgpPeerInUpdates OBJECT-TYPE
+            SYNTAX     Counter32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The number of BGP UPDATE messages received on
+                    this connection.  This object should be
+                    initialized to zero (0) when the connection is
+                    established."
+            ::= { bgpPeerEntry 10 }
+
+        bgpPeerOutUpdates OBJECT-TYPE
+            SYNTAX     Counter32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The number of BGP UPDATE messages transmitted
+                    on this connection.  This object should be
+                    initialized to zero (0) when the connection is
+                    established."
+            ::= { bgpPeerEntry 11 }
+
+        bgpPeerInTotalMessages OBJECT-TYPE
+            SYNTAX     Counter32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The total number of messages received from the
+                    remote peer on this connection.  This object
+                    should be initialized to zero when the
+                    connection is established."
+            ::= { bgpPeerEntry 12 }
+
+        bgpPeerOutTotalMessages OBJECT-TYPE
+            SYNTAX     Counter32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The total number of messages transmitted to
+                    the remote peer on this connection.  This object
+                    should be initialized to zero when the
+                    connection is established."
+            ::= { bgpPeerEntry 13 }
+
+        bgpPeerLastError OBJECT-TYPE
+            SYNTAX     OCTET STRING (SIZE (2))
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The last error code and subcode seen by this
+                    peer on this connection.  If no error has
+                    occurred, this field is zero.  Otherwise, the
+                    first byte of this two byte OCTET STRING
+                    contains the error code, and the second byte
+                    contains the subcode."
+            ::= { bgpPeerEntry 14 }
+
+        bgpPeerFsmEstablishedTransitions OBJECT-TYPE
+            SYNTAX     Counter32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The total number of times the BGP FSM
+                    transitioned into the established state."
+            ::= { bgpPeerEntry 15 }
+
+        bgpPeerFsmEstablishedTime OBJECT-TYPE
+            SYNTAX     Gauge32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "This timer indicates how long (in seconds) this
+                    peer has been in the Established state or how long
+                    since this peer was last in the Established state.
+                    It is set to zero when a new peer is configured or
+                    the router is booted."
+            ::= { bgpPeerEntry 16 }
+
+        bgpPeerConnectRetryInterval OBJECT-TYPE
+            SYNTAX     INTEGER (1..65535)
+            MAX-ACCESS read-write
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the ConnectRetry
+                    timer.  The suggested value for this timer is
+                    120 seconds."
+            ::= { bgpPeerEntry 17 }
+
+        bgpPeerHoldTime OBJECT-TYPE
+            SYNTAX     INTEGER  ( 0 | 3..65535 )
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the Hold Timer
+                    established with the peer.  The value of this
+                    object is calculated by this BGP speaker by
+                    using the smaller of the value in
+                    bgpPeerHoldTimeConfigured and the Hold Time
+                    received in the OPEN message.  This value
+                    must be at lease three seconds if it is not
+                    zero (0) in which case the Hold Timer has
+                    not been established with the peer, or, the
+                    value of bgpPeerHoldTimeConfigured is zero (0)."
+            ::= { bgpPeerEntry 18 }
+
+        bgpPeerKeepAlive OBJECT-TYPE
+            SYNTAX     INTEGER ( 0 | 1..21845 )
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the KeepAlive
+                    timer established with the peer.  The value of
+                    this object is calculated by this BGP speaker
+                    such that, when compared with bgpPeerHoldTime,
+                    it has the same proportion as what
+                    bgpPeerKeepAliveConfigured has when compared
+                    with bgpPeerHoldTimeConfigured.  If the value
+                    of this object is zero (0), it indicates that
+                    the KeepAlive timer has not been established
+                    with the peer, or, the value of
+                    bgpPeerKeepAliveConfigured is zero (0)."
+            ::= { bgpPeerEntry 19 }
+
+        bgpPeerHoldTimeConfigured OBJECT-TYPE
+            SYNTAX     INTEGER ( 0 | 3..65535 )
+            MAX-ACCESS read-write
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the Hold Time
+                    configured for this BGP speaker with this peer.
+                    This value is placed in an OPEN message sent to
+                    this peer by this BGP speaker, and is compared
+                    with the Hold Time field in an OPEN message
+                    received from the peer when determining the Hold
+                    Time (bgpPeerHoldTime) with the peer.  This value
+                    must not be less than three seconds if it is not
+                    zero (0) in which case the Hold Time is NOT to be
+                    established with the peer.  The suggested value for
+                    this timer is 90 seconds."
+            ::= { bgpPeerEntry 20 }
+
+        bgpPeerKeepAliveConfigured OBJECT-TYPE
+            SYNTAX     INTEGER ( 0 | 1..21845 )
+            MAX-ACCESS read-write
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the KeepAlive timer
+                    configured for this BGP speaker with this peer.
+                    The value of this object will only determine the
+                    KEEPALIVE messages' frequency relative to the value
+                    specified in bgpPeerHoldTimeConfigured; the actual
+                    time interval for the KEEPALIVE messages is
+                    indicated by bgpPeerKeepAlive.  A reasonable
+                    maximum value for this timer would be configured to
+                    be one third of that of bgpPeerHoldTimeConfigured.
+                    If the value of this object is zero (0), no
+                    periodical KEEPALIVE messages are sent to the peer
+                    after the BGP connection has been established.  The
+                    suggested value for this timer is 30 seconds."
+            ::= { bgpPeerEntry 21 }
+
+        bgpPeerMinASOriginationInterval OBJECT-TYPE
+            SYNTAX     INTEGER (1..65535)
+            MAX-ACCESS read-write
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the
+                    MinASOriginationInterval timer.
+                    The suggested value for this timer is 15 seconds."
+            ::= { bgpPeerEntry 22 }
+
+        bgpPeerMinRouteAdvertisementInterval OBJECT-TYPE
+            SYNTAX     INTEGER (1..65535)
+            MAX-ACCESS read-write
+            STATUS     current
+            DESCRIPTION
+                    "Time interval in seconds for the
+                    MinRouteAdvertisementInterval timer.
+                    The suggested value for this timer is 30 seconds."
+            ::= { bgpPeerEntry 23 }
+
+        bgpPeerInUpdateElapsedTime OBJECT-TYPE
+            SYNTAX     Gauge32
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "Elapsed time in seconds since the last BGP
+                    UPDATE message was received from the peer.
+                    Each time bgpPeerInUpdates is incremented,
+                    the value of this object is set to zero (0)."
+            ::= { bgpPeerEntry 24 }
+
+
+
+        bgpIdentifier OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The BGP Identifier of local system."
+            ::= { bgp 4 }
+
+
+
+        -- Received Path Attribute Table.  This table contains,
+        -- one entry per path to a network, path attributes
+        -- received from all peers running BGP version 3 or less.
+        -- This table is obsolete, having been replaced in
+        -- functionality with the bgp4PathAttrTable.
+
+        bgpRcvdPathAttrTable OBJECT-TYPE
+            SYNTAX     SEQUENCE OF BgpPathAttrEntry
+            MAX-ACCESS not-accessible
+            STATUS     obsolete
+            DESCRIPTION
+                    "The BGP Received Path Attribute Table contains
+                    information about paths to destination networks
+                    received from all peers running BGP version 3 or
+                    less."
+            ::= { bgp 5 }
+
+        bgpPathAttrEntry OBJECT-TYPE
+            SYNTAX     BgpPathAttrEntry
+            MAX-ACCESS not-accessible
+            STATUS     obsolete
+            DESCRIPTION
+                    "Information about a path to a network."
+            INDEX { bgpPathAttrDestNetwork,
+                    bgpPathAttrPeer        }
+            ::= { bgpRcvdPathAttrTable 1 }
+
+        BgpPathAttrEntry ::= SEQUENCE {
+            bgpPathAttrPeer
+                 IpAddress,
+            bgpPathAttrDestNetwork
+                 IpAddress,
+            bgpPathAttrOrigin
+                 INTEGER,
+            bgpPathAttrASPath
+                 OCTET STRING,
+            bgpPathAttrNextHop
+                 IpAddress,
+            bgpPathAttrInterASMetric
+                 Integer32
+        }
+
+        bgpPathAttrPeer OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     obsolete
+            DESCRIPTION
+                    "The IP address of the peer where the path
+                    information was learned."
+            ::= { bgpPathAttrEntry 1 }
+
+        bgpPathAttrDestNetwork OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     obsolete
+            DESCRIPTION
+                    "The address of the destination network."
+            ::= { bgpPathAttrEntry 2 }
+
+        bgpPathAttrOrigin OBJECT-TYPE
+            SYNTAX     INTEGER {
+                           igp(1),-- networks are interior
+                           egp(2),-- networks learned via EGP
+                           incomplete(3) -- undetermined
+                       }
+            MAX-ACCESS read-only
+            STATUS     obsolete
+            DESCRIPTION
+                 "The ultimate origin of the path information."
+            ::= { bgpPathAttrEntry 3 }
+
+        bgpPathAttrASPath OBJECT-TYPE
+            SYNTAX     OCTET STRING (SIZE (2..255))
+            MAX-ACCESS read-only
+            STATUS     obsolete
+            DESCRIPTION
+                    "The set of ASs that must be traversed to reach
+                    the network.  This object is probably best
+                    represented as SEQUENCE OF INTEGER.  For SMI
+                    compatibility, though, it is represented as
+                    OCTET STRING.  Each AS is represented as a pair
+                    of octets according to the following algorithm:
+
+                        first-byte-of-pair = ASNumber / 256;
+                        second-byte-of-pair = ASNumber & 255;"
+            ::= { bgpPathAttrEntry 4 }
+
+        bgpPathAttrNextHop OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     obsolete
+            DESCRIPTION
+                    "The address of the border router that should
+                    be used for the destination network."
+            ::= { bgpPathAttrEntry 5 }
+
+        bgpPathAttrInterASMetric OBJECT-TYPE
+            SYNTAX     Integer32
+            MAX-ACCESS read-only
+            STATUS     obsolete
+            DESCRIPTION
+                    "The optional inter-AS metric.  If this
+                    attribute has not been provided for this route,
+                    the value for this object is 0."
+            ::= { bgpPathAttrEntry 6 }
+
+
+
+        -- BGP-4 Received Path Attribute Table.  This table contains,
+        -- one entry per path to a network, path attributes
+        -- received from all peers running BGP-4.
+
+        bgp4PathAttrTable OBJECT-TYPE
+            SYNTAX     SEQUENCE OF Bgp4PathAttrEntry
+            MAX-ACCESS not-accessible
+            STATUS     current
+            DESCRIPTION
+                    "The BGP-4 Received Path Attribute Table contains
+                    information about paths to destination networks
+                    received from all BGP4 peers."
+            ::= { bgp 6 }
+
+        bgp4PathAttrEntry OBJECT-TYPE
+            SYNTAX     Bgp4PathAttrEntry
+            MAX-ACCESS not-accessible
+            STATUS     current
+            DESCRIPTION
+                    "Information about a path to a network."
+            INDEX { bgp4PathAttrIpAddrPrefix,
+                    bgp4PathAttrIpAddrPrefixLen,
+                    bgp4PathAttrPeer            }
+            ::= { bgp4PathAttrTable 1 }
+
+        Bgp4PathAttrEntry ::= SEQUENCE {
+            bgp4PathAttrPeer
+                 IpAddress,
+            bgp4PathAttrIpAddrPrefixLen
+                 INTEGER,
+            bgp4PathAttrIpAddrPrefix
+                 IpAddress,
+            bgp4PathAttrOrigin
+                 INTEGER,
+            bgp4PathAttrASPathSegment
+                 OCTET STRING,
+            bgp4PathAttrNextHop
+                 IpAddress,
+            bgp4PathAttrMultiExitDisc
+                 INTEGER,
+            bgp4PathAttrLocalPref
+                 INTEGER,
+            bgp4PathAttrAtomicAggregate
+                 INTEGER,
+            bgp4PathAttrAggregatorAS
+                 INTEGER,
+            bgp4PathAttrAggregatorAddr
+                 IpAddress,
+            bgp4PathAttrCalcLocalPref
+                 INTEGER,
+            bgp4PathAttrBest
+                 INTEGER,
+            bgp4PathAttrUnknown
+                 OCTET STRING
+        }
+
+        bgp4PathAttrPeer OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The IP address of the peer where the path
+                    information was learned."
+            ::= { bgp4PathAttrEntry 1 }
+        bgp4PathAttrIpAddrPrefixLen OBJECT-TYPE
+            SYNTAX     INTEGER (0..32)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "Length in bits of the IP address prefix in the
+                    Network Layer Reachability Information field."
+            ::= { bgp4PathAttrEntry 2 }
+
+        bgp4PathAttrIpAddrPrefix OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "An IP address prefix in the Network Layer
+                    Reachability Information field.  This object
+                    is an IP address containing the prefix with
+                    length specified by bgp4PathAttrIpAddrPrefixLen.
+                    Any bits beyond the length specified by
+                    bgp4PathAttrIpAddrPrefixLen are zeroed."
+            ::= { bgp4PathAttrEntry 3 }
+
+        bgp4PathAttrOrigin OBJECT-TYPE
+            SYNTAX     INTEGER {
+                                 igp(1),-- networks are interior
+                                 egp(2),-- networks learned via EGP
+                                 incomplete(3) -- undetermined
+                               }
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The ultimate origin of the path information."
+            ::= { bgp4PathAttrEntry 4 }
+
+        bgp4PathAttrASPathSegment OBJECT-TYPE
+            SYNTAX     OCTET STRING (SIZE (2..255))
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The sequence of AS path segments.  Each AS
+                    path segment is represented by a triple
+                    <type, length, value>.
+
+                    The type is a 1-octet field which has two
+                    possible values:
+                         1      AS_SET: unordered set of ASs a
+                                     route in the UPDATE message
+                                     has traversed
+                         2      AS_SEQUENCE: ordered set of ASs
+                                     a route in the UPDATE message
+                                     has traversed.
+
+                    The length is a 1-octet field containing the
+                    number of ASs in the value field.
+
+                    The value field contains one or more AS
+                    numbers, each AS is represented in the octet
+                    string as a pair of octets according to the
+                    following algorithm:
+
+                        first-byte-of-pair = ASNumber / 256;
+                        second-byte-of-pair = ASNumber & 255;"
+            ::= { bgp4PathAttrEntry 5 }
+
+        bgp4PathAttrNextHop OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The address of the border router that should
+                    be used for the destination network."
+            ::= { bgp4PathAttrEntry 6 }
+
+        bgp4PathAttrMultiExitDisc OBJECT-TYPE
+            SYNTAX     INTEGER (-1..2147483647)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "This metric is used to discriminate between
+                    multiple exit points to an adjacent autonomous
+                    system.  A value of -1 indicates the absence of
+                    this attribute."
+            ::= { bgp4PathAttrEntry 7 }
+
+        bgp4PathAttrLocalPref OBJECT-TYPE
+            SYNTAX     INTEGER (-1..2147483647)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The originating BGP4 speaker's degree of
+                    preference for an advertised route.  A value of
+                    -1 indicates the absence of this attribute."
+            ::= { bgp4PathAttrEntry 8 }
+
+        bgp4PathAttrAtomicAggregate OBJECT-TYPE
+            SYNTAX     INTEGER {
+                           lessSpecificRrouteNotSelected(1),
+                           lessSpecificRouteSelected(2)
+                       }
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "Whether or not a system has selected
+                    a less specific route without selecting a
+                    more specific route."
+            ::= { bgp4PathAttrEntry 9 }
+
+        bgp4PathAttrAggregatorAS OBJECT-TYPE
+            SYNTAX     INTEGER (0..65535)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The AS number of the last BGP4 speaker that
+                    performed route aggregation.  A value of zero (0)
+                    indicates the absence of this attribute."
+            ::= { bgp4PathAttrEntry 10 }
+
+        bgp4PathAttrAggregatorAddr OBJECT-TYPE
+            SYNTAX     IpAddress
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The IP address of the last BGP4 speaker that
+                     performed route aggregation.  A value of
+                     0.0.0.0 indicates the absence of this attribute."
+            ::= { bgp4PathAttrEntry 11 }
+
+        bgp4PathAttrCalcLocalPref OBJECT-TYPE
+            SYNTAX     INTEGER (-1..2147483647)
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "The degree of preference calculated by the
+                    receiving BGP4 speaker for an advertised route.
+                    A value of -1 indicates the absence of this
+                    attribute."
+            ::= { bgp4PathAttrEntry 12 }
+
+        bgp4PathAttrBest OBJECT-TYPE
+            SYNTAX     INTEGER {
+                           false(1),-- not chosen as best route
+                           true(2) -- chosen as best route
+                       }
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "An indication of whether or not this route
+                    was chosen as the best BGP4 route."
+            ::= { bgp4PathAttrEntry 13 }
+
+        bgp4PathAttrUnknown OBJECT-TYPE
+            SYNTAX     OCTET STRING (SIZE(0..255))
+            MAX-ACCESS read-only
+            STATUS     current
+            DESCRIPTION
+                    "One or more path attributes not understood
+                     by this BGP4 speaker.  Size zero (0) indicates
+                     the absence of such attribute(s).  Octets
+                     beyond the maximum size, if any, are not
+                     recorded by this object."
+            ::= { bgp4PathAttrEntry 14 }
+
+
+        -- Traps.
+
+        -- note that in RFC 1657, bgpTraps was incorrectly
+        -- assigned a value of { bgp 7 }, and each of the
+        -- traps had the bgpPeerRemoteAddr object inappropriately
+        -- removed from their OBJECTS clause.  The following
+        -- definitions restore the semantics of the traps as
+        -- they were initially defined in RFC 1269.
+
+        -- { bgp 7 } is unused
+
+        bgpTraps          OBJECT IDENTIFIER ::= { bgp 0 }
+
+        bgpEstablished NOTIFICATION-TYPE
+            OBJECTS { bgpPeerRemoteAddr,
+                      bgpPeerLastError,
+                      bgpPeerState      }
+            STATUS  current
+            DESCRIPTION
+                    "The BGP Established event is generated when
+                    the BGP FSM enters the ESTABLISHED state."
+            ::= { bgpTraps 1 }
+
+        bgpBackwardTransition NOTIFICATION-TYPE
+            OBJECTS { bgpPeerRemoteAddr,
+                      bgpPeerLastError,
+                      bgpPeerState      }
+            STATUS  current
+            DESCRIPTION
+                    "The BGPBackwardTransition Event is generated
+                    when the BGP FSM moves from a higher numbered
+                    state to a lower numbered state."
+            ::= { bgpTraps 2 }
+
+        -- conformance information
+
+        bgpMIBConformance OBJECT IDENTIFIER ::= { bgp 8 }
+        bgpMIBCompliances OBJECT IDENTIFIER ::= { bgpMIBConformance 1 }
+        bgpMIBGroups      OBJECT IDENTIFIER ::= { bgpMIBConformance 2 }
+
+        -- compliance statements
+
+        bgpMIBCompliance MODULE-COMPLIANCE
+            STATUS  current
+            DESCRIPTION
+                    "The compliance statement for entities which
+                     implement the BGP4 mib."
+            MODULE  -- this module
+                MANDATORY-GROUPS { bgp4MIBGlobalsGroup,
+                                   bgp4MIBPeerGroup,
+                                   bgp4MIBPathAttrGroup,
+                                   bgp4MIBNotificationGroup }
+            ::= { bgpMIBCompliances 1 }
+
+        -- units of conformance
+
+        bgp4MIBGlobalsGroup OBJECT-GROUP
+            OBJECTS { bgpVersion,
+                      bgpLocalAs,
+                      bgpIdentifier }
+            STATUS  current
+            DESCRIPTION
+                    "A collection of objects providing information
+                     on global BGP state."
+            ::= { bgpMIBGroups 1 }
+
+        bgp4MIBPeerGroup OBJECT-GROUP
+            OBJECTS { bgpPeerIdentifier,
+                      bgpPeerState,
+                      bgpPeerAdminStatus,
+                      bgpPeerNegotiatedVersion,
+                      bgpPeerLocalAddr,
+                      bgpPeerLocalPort,
+                      bgpPeerRemoteAddr,
+                      bgpPeerRemotePort,
+                      bgpPeerRemoteAs,
+                      bgpPeerInUpdates,
+                      bgpPeerOutUpdates,
+                      bgpPeerInTotalMessages,
+                      bgpPeerOutTotalMessages,
+                      bgpPeerLastError,
+                      bgpPeerFsmEstablishedTransitions,
+                      bgpPeerFsmEstablishedTime,
+                      bgpPeerConnectRetryInterval,
+                      bgpPeerHoldTime,
+                      bgpPeerKeepAlive,
+                      bgpPeerHoldTimeConfigured,
+                      bgpPeerKeepAliveConfigured,
+                      bgpPeerMinASOriginationInterval,
+                      bgpPeerMinRouteAdvertisementInterval,
+                      bgpPeerInUpdateElapsedTime }
+            STATUS  current
+            DESCRIPTION
+                    "A collection of objects for managing
+                     BGP peers."
+            ::= { bgpMIBGroups 2 }
+
+        bgp4MIBRcvdPathAttrGroup OBJECT-GROUP
+            OBJECTS { bgpPathAttrPeer,
+                      bgpPathAttrDestNetwork,
+                      bgpPathAttrOrigin,
+                      bgpPathAttrASPath,
+                      bgpPathAttrNextHop,
+                      bgpPathAttrInterASMetric }
+            STATUS  obsolete
+            DESCRIPTION
+                    "A collection of objects for managing BGP
+                     path entries.
+
+                     This conformance group is obsolete,
+                     replaced by bgp4MIBPathAttrGroup."
+            ::= { bgpMIBGroups 3 }
+
+        bgp4MIBPathAttrGroup OBJECT-GROUP
+            OBJECTS { bgp4PathAttrPeer,
+                      bgp4PathAttrIpAddrPrefixLen,
+                      bgp4PathAttrIpAddrPrefix,
+                      bgp4PathAttrOrigin,
+                      bgp4PathAttrASPathSegment,
+                      bgp4PathAttrNextHop,
+                      bgp4PathAttrMultiExitDisc,
+                      bgp4PathAttrLocalPref,
+                      bgp4PathAttrAtomicAggregate,
+                      bgp4PathAttrAggregatorAS,
+                      bgp4PathAttrAggregatorAddr,
+                      bgp4PathAttrCalcLocalPref,
+                      bgp4PathAttrBest,
+                      bgp4PathAttrUnknown }
+            STATUS  current
+            DESCRIPTION
+                    "A collection of objects for managing
+                     BGP path entries."
+            ::= { bgpMIBGroups 4 }
+
+        bgp4MIBNotificationGroup NOTIFICATION-GROUP
+            NOTIFICATIONS { bgpEstablished,
+                            bgpBackwardTransition }
+            STATUS  current
+            DESCRIPTION
+                    "A collection of notifications for signaling
+                    changes in BGP peer relationships."
+            ::= { bgpMIBGroups 5 }
+
+    END
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
new file mode 100644 (file)
index 0000000..4f7a20e
--- /dev/null
@@ -0,0 +1,2368 @@
+2002-10-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_aspath.c (aspath_init): Extend hash size from default to
+       32767.
+       (aspath_key_make): Use unsigned shoft for making hash.  Suggested
+       by: Marc Evans <Marc@SoftwareHackery.Com>
+
+2002-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_clist.c (community_entry_free): Fix memory leak of standard
+       extcommunity-list config string.
+
+2002-08-19  Akihiro Mizutani <mizutani@net-chef.net>
+
+       * bgp_route.c (route_vty_out_detail): Fix bug of router-id display
+       when multiple instance is used.
+
+2002-08-18  Akihiro Mizutani <mizutani@net-chef.net>
+
+       * bgpd.c: Make "default-originate" and "maximum-prefix" commands
+       available in peer-group configuration.
+
+2002-08-13  Akihiro Mizutani <mizutani@net-chef.net>
+
+       * bgp_packet.c (bgp_open_send): Put Opt Parm Len 0 when last
+       capability packet cause error or dont-capability-negotiate option
+       is specified.
+
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2001-10-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_vty_init): Translate update commands are removed.
+
+2001-10-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_static_set): Add workaround for BGP static
+       route announcement when there is no zebra running.
+
+2001-10-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (neighbor_remote_as_unicast): Remove "remote-as nlri
+       unicast multicast" commands.
+
+2001-09-14  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_open.c: When we receive capability route-refresh, we should
+       check we send the capability not we receive the capability.
+
+       * bgp_route.c (bgp_network_mask_natural_route_map): network
+       statement route-map is added.
+
+2001-08-31  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_advertise.c (bgp_advertise_intern): attr must be interned
+       before looking up hash table.
+
+2001-08-30  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.h (struct peer): BGP filter is moved from peer_conf to
+       peer.
+
+2001-08-28  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_nexthop.c (bnc_nexthop_free): Fix next pointer bug.
+       Suggested by: "Hong-Sung Kim" <hoskim@lanbird.co.kr>.
+
+2001-08-26  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_table.c (bgp_node_create): Clearn memory before use it.
+
+2001-08-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * Change to use bgp_table.[ch].
+
+2001-08-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.c (bgp_init): Add "transparent-as" and
+       "transparent-nexthop" for old version compatibility.
+
+2001-08-23  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.h (struct peer): default-originate route-map is added.
+
+       * bgp_route.c: When self originated route is advertised with
+       attrubute-unchanged, nexthop was not properly set.  This bug is
+       fixed.
+
+2001-08-22  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c (neighbor_attr_unchanged): transparent-as and
+       transparent-next-hop commands are restructured.  Instead of
+       current transparent-* commands, attribute-unchanged command is
+       introduced.
+
+       neighbor A.B.C.D attribute-unchanged [as-path|next-hop|med]
+
+       (neighbor_default_originate): "default-originate" configuration
+       announce default route even 0.0.0.0/0 does not exists in BGP RIB.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-19  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: AF specific soft-reconfiguration inbound commands are
+       added.
+
+2001-08-17  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_route.c (bgp_show_callback): Do not do community NULL check.
+
+       * bgp_community.c (community_cmp): Add check for commnunity NULL
+       check.
+
+       * bgp_routemap.c (route_match_community): Do not check comunity is
+       NULL.  It may match to community-list "^$".
+
+       * bgp_community.c (community_match): Add check for community is
+       NULL case.
+
+2001-08-17  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: AF specific route-reflector-client and
+       route-server-client configuration are added.
+
+2001-08-17  Rick Payne <rickp@ayrnetworks.com>
+
+       * bgp_clist.c (community_match_regexp): Check special ^$ case.
+
+2001-08-17  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_clist.c (community_list_match): Fix bug of community list
+       permit and deny check.
+
+2001-08-16  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_mplsvpn.c (bgp_mplsvpn_init): Add AF specific "nexthop-self"
+       command.
+
+2001-08-15  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.h (PEER_FLAG_SEND_COMMUNITY): Per AF based configuration
+       flag is introduced.
+
+       * bgp_mplsvpn.c (bgp_mplsvpn_init): VPNv4 filtering is added.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-08-13  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.c (bgp_delete): "no router bgp" free static, aggregate, rib
+       table properly.
+
+2001-08-12  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_route.c (bgp_node_safi): Return SAFI of current node.
+       (bgp_config_write_network_vpnv4): VPNv4 static configuration
+       display.
+
+2001-08-11  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.c (no_bgp_ipv4_multicast_route_map): Add IPv4 multicast
+       node filter commands.
+
+2001-08-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h (PEER_FLAG_IGNORE_LINK_LOCAL_NEXTHOP): Add
+       "ignore-link-local-nexthop" flag for ignore link-local nexthop for
+       IPv6.
+
+2001-08-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.c (address_family_ipv4_multicast): "address-family ipv4
+       multicast" is added.
+       (address_family_ipv6_unicast): "address-family ipv6 unicast" is
+       added.
+       
+2001-08-07  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_process): Use flag instead of as_selected
+       memeber in struct bgp_info.
+
+       * bgp_route.h (struct bgp_info): Remove as_selected memeber from
+       struct bgp_info.
+
+2001-07-31  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_route.c (bgp_announce_check): Enclose sending time AS loop
+       check code with #ifdef BGP_SEND_ASPATH_CHECK.
+
+2001-07-29  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_packet.c (bgp_withdraw_send): Simplify address family check.
+
+       * bgpd.h (BGP_INFO_HOLDDOWN): Introduce new macro to check BGP
+       information is alive or not.
+
+       * bgp_community.c: Use community_val_get() on all OS.
+
+2001-07-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_route.c (bgp_announce_check): Simplify set next-hop self
+       check.
+
+2001-07-24  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_announce_check): To route server clients, we
+       announce AS path, MED and nexthop transparently.
+
+2001-06-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (route_set_atomic_aggregate_free): Do not call
+       XFREE.  No memory is allocated in
+       route_set_atomic_aggregate_compile().
+
+2001-06-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (bgp_route_map_init): `match nlri` and `set nlri`
+       are replaced by `address-family ipv4` and `address-family vpnvr'.
+
+2001-06-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_withdraw): Add check for BGP_PEER_CONFED.
+       Reported by Rick Payne <rickp@rossfell.co.uk>.
+
+2001-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (bgp_zebra_announce): When global IPv6 nexthop is
+       empty, use socket's remote address for the nexthop.
+
+2001-06-04  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.c (peer_delete): Fix memory leak.  Reported by Yosi Yarchi
+       <Yosi_Yarchi@KereniX.com>
+
+2001-06-01  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgpd.c (bgp_delete): Fix memory leak.  Reported by Yosi Yarchi
+       <Yosi_Yarchi@KereniX.com>
+
+2001-05-27  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * bgp_route.c (bgp_route_clear_with_afi_vpnv4): Use next instead
+       of ri->next.
+
+       * bgp_packet.c (bgp_withdraw_send): MPLS/VPN withdraw takes effect
+       when HAVE_IPV6 is not defined.
+
+2001-03-07  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgpd.c (peer_timers_set): Adjust keepalive timer to fit less
+       than holdtime / 3.
+       (bgp_confederation_peers_unset): Only set peer->local_as when
+       confederation is enabled.
+       (bgp_timers): Add "timers bgp <0-65535> <0-65535>" command.
+
+       * bgp_route.c (bgp_announce_check): Set med of redistributed route
+       when it is announced to EBGP peer.
+
+2001-03-06  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_nexthop.c (bgp_scan_ipv4): bgp_scan() call bgp_process() for
+       all prefixes.
+
+2001-03-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_attr_origin): When bgpd send NOTIFICATION with
+       erroneous attribute (type, length and value), it does include
+       attribute flags field.
+
+2001-02-21  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_announce_check): The route reflector is not
+       allowed to modify the attributes of the reflected IBGP routes.
+
+2001-02-20  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): During path seleciton, BGP
+       confederation peer is treated as same as IBGP peer.
+
+2001-02-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_redistribute_add): Initialize attr_new with
+       attr.  Call aspath_unintern when return from this function.
+
+2001-02-19  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgpd.c (bgp_router_id_set): Reset BGP peer when router-id is
+       changed.
+
+2001-02-18  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_packet.c (bgp_open_receive): When user configure holdtimer,
+       do not refrect the value to current session.
+
+2001-02-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_aggregate_delete): Set BGP_INFO_ATTR_CHANGE to
+       suppress route withdraw.
+
+       * bgp_damp.c (bgp_damp_init): Fix bug of flap dampening.
+
+2001-02-16  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_aspath.c (aspath_make_str_count): Use ',' for separator for
+       AS_SET and AS_CONFED_SET.
+
+2001-02-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_process): Do not consider suppress route.
+
+       * bgp_aspath.c (aspath_aggregate_as_set_add): Reset asset when
+       aspath->data is realloced.
+
+2001-02-15  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_attr.c (bgp_attr_aggregate_intern): Do not set atomic
+       aggregate when using as-set.
+
+2001-02-14  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgpd.c (bgp_confederation_peers_unset): Set peer's local-as
+       correctly.
+
+       * bgp_route.c (bgp_update): Just ignore AS path loop for
+       confederation peer.
+
+2001-02-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_aggregate_set): Add as_set argument.
+       (bgp_aggregate_unset): Remove summary_only argument.
+       (aggregate_address_as_set): New commands.
+       "aggregate-address A.B.C.D/M as-set"
+       "no aggregate-address A.B.C.D/M as-set"
+
+2001-02-08  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_announce_check): Do not modify nexthop when the
+       route is passed by route reflector.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c: "no bgp dampening" with argument.
+       (bgp_announce_check): Do not modify nexthop when the route is
+       passed by route reflector.
+
+2001-02-07  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgpd.c (neighbor_passive): Change "neighbor NEIGHBOR remote-as
+       ASN passive" to "neighbor NEIGHBOR passive".
+       (bgp_announce_check): Check well-known community attribute even
+       when "no neighbor send-community" is set.
+
+2001-02-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (bgp_establish): Do not send keepalive at established
+       time when keepalive timer is configured as zero.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_attr_check): When peer is IBGP peer, local
+       preference is well-known attribute.
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+       * bgp_attr.h (struct attr): Comment out DPA value.
+       (struct attr): Change refcnt type from int to unsinged long.
+
+       * bgp_attr.c (attrhash_key_make): Likewise.
+       (attrhash_cmp): Likewise.
+       (bgp_attr_dpa): Likewise.
+
+2001-01-30  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): Make route selection completely same
+       as Cisco's.
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.h (BGP_ATTR_FLAG_OPTIONAL): Rename old ATTR_FLAG_* to
+       BGP_ATTR_FLAG_* to clarify meenings.
+
+2001-01-30  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (route_vty_out): Display argument to suppress same
+       prefix information display.
+       (route_vty_out_route): Don't display mask information for
+       classfull network.
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.h (SET_BITMAP): Simple bitmapping macros.
+
+       * bgp_attr.c (bgp_attr_parse): Use bitmap for attribute type
+       check.
+
+2001-01-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_mp_reach_parse): Enclose loggin with BGP_DEBUG.
+       (bgp_attr_parse): Comment out well-known attribute check.
+
+2001-01-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_static_unset): Link-local IPv6 address can't be
+       used for network advertisement.
+       (nlri_parse): When link-local IPv6 address NLRI comes from
+       remote-peer, log the information then simply ignore it.
+
+       * bgp_zebra.c (zebra_read_ipv6): Link-local IPv6 address is not
+       redistributed.
+
+       * bgp_route.c (bgp_update): Check IPv6 global nexthop
+       reachability.
+
+2001-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_update): Check nexthop points local address or
+       not.
+       (bgp_static_update_vpnv4): Set valid flag.
+
+       * bgp_attr.c (bgp_attr_parse): Duplicate attribute check.
+       (bgp_attr_parse): Well-known attribute check.
+
+       * bgp_open.c (bgp_auth_parse): Authentication is not yet supported.
+
+       * bgp_packet.c (bgp_valid_marker): Check marker is synchronized.
+
+       * bgpd.c (clear_bgp): Send NOTIFICATION Cease when SEND_CEASE is
+       defined.
+
+       * bgp_snmp.c (bgp4PathAttrTable): Fix compile error.
+
+2001-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_network_import_check): New command for IGP network
+       check.
+
+2001-01-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_scan): Run bgp_process when IGP metric is
+       changed.  Call bgp_process once for each node.
+
+2001-01-23  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): Add IGP metric comparison.
+
+2001-01-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_info_cmp): Add IGP metric comparison.
+
+       * bgp_nexthop.c (bgp_nexthop_lookup): Set IGP metric for valid
+       IBGP route.
+
+2001-01-23  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (show_ip_bgp_prefix_longer): Add new commands.
+       "show ip bgp A.B.C.D/M longer-prefixes"
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes"
+       "show ipv6 bgp X:X::X:X/M longer-prefixes"
+       "show ipv6 mbgp X:X::X:X/M longer-prefixes"
+       
+2001-01-20  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (show_ip_bgp_cidr_only): Add new commands.
+       "show ip bgp cidr-only"
+       "show ip bgp ipv4 (unicast|multicast) cidr-only"
+       
+2001-01-18  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_update): AS path lookup check is done in
+       bgp_update() not in attr_parse().
+
+2001-01-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_update): Call bgp_aggregate_decrement() just
+       before bgp_attr_unintern().
+
+2001-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_update): Now intern is performed very last part
+       of the BGP packet update procedure.
+
+2001-01-17  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_update): When implicit withdraw occur, reuse
+       existing bgp_info structure.
+
+2001-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_aggregate_decrement): Fix bug of aggregate
+       address matching method.
+       (bgp_update): 
+
+       * bgp_nexthop.c (bgp_nexthop_onlink): Separate EBGP nexthop onlink
+       check and IBGP nexthop route check.
+
+2001-01-16  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.h (BGP_INFO_ATRR_CHANGED): Added for track attribute
+       change.
+
+2001-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.h (struct bgp_info): Remove selected flag.  Use
+       BGP_INFO_SELECTED for flags instead.
+       (struct bgp_info): Remove valid flag.  Use BGP_INFO_VALID for
+       flags instead.
+       (struct bgp_info): Add igpmetric for IBGP route nexthop IGP
+       metric.
+       (struct bgp_info_tab): Struct bgp_info_tag is integrated into
+       struct bgp_info.
+       (BGP_INFO_ATRR_CHANGED): Added for track attribute change.
+
+       * bgp_community.c (community_val_get): gcc-2.95 on
+       sparc-sun-solaris cause crush.  This function is for avoid the
+       crush.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_open_receive): Translated peer's packet_size
+       clear bug is fixed.
+
+2001-01-14  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_packet.c (bgp_open_receive): Return notification with
+       supported version number.
+
+2001-01-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_show_summary): Display AS path and community
+       entries.  Suggested by: "Matt Ranney" <mjr@ranney.com>.
+
+       * bgp_packet.c (bgp_read_packet): Fix bug of unblocking BGP socket
+       read.  When BGP packet read is partial, we must get size and type
+       from packet again.
+
+2001-01-12  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_route.c (bgp_update): Do not unset BGP_INFO_HISTORY flag.
+       (bgp_update): When there is a history entry increment route count.
+       (bgp_damp_set): Check BGP_CONFIG_DAMPENING flag.
+
+       * bgp_damp.c (bgp_damp_withdraw): Set status to
+       BGP_DAMP_DISCONTINUE.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_mp_reach_parse): Fix warning code when second
+       IPv6 nexthop is not link-local addresss.
+
+2001-01-11  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_damp.c (bgp_config_write_damp): Smart flap dampening
+       configuration display.
+       (bgp_damp_info_print): Display elapsed time from flap started.
+
+       * bgp_damp.h (struct bgp_damp_info): Add flap start time.
+
+       * bgpd.c (peer_create): Set last read time.
+       (bgp_show_peer): Display last read time.
+       (bgp_show_summary): Use BGP_CONFIG_DAMPENING flag to check
+       configuration.
+       
+       * bgpd.h (BGP_CONFIG_DAMPENING): Add new configuration option.
+       (struct peer): Add last read time member.
+       (BGP_VERSION_MP_4): Remove obsolete definition.
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c: Remove OLD_RIB codes.
+
+       * bgp_route.c (bgp_process): Likewise.
+
+       * zebra-0.90 is released.
+
+       * bgp_route.h (BGP_INFO_HISTORY): Remove damped member from struct
+       bgp_info.  Instead of that use BGP_INFO_DAMPED flag.
+       (struct bgp_info): Remove invalid member from struct bgp_info.
+       Instead of that use BGP_INFO_HISTORY flag.
+
+2001-01-10  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgp_damp.c (bgp_damp_info_print): New function to display
+       dampening status.
+       (DEFAULT_HARF_LIFE): Define default value.
+       (DEFAULT_REUSE): Likewise.
+       (DEFAULT_SUPPRESS): Likewise.
+       (bgp_config_write_damp): When config value is same as default
+       value, simply display "bgp dampening" to configuration.
+
+       * bgp_damp.h (struct bgp_damp_info): Add flap member.
+
+       * bgp_route.h (struct bgp_info): Added for BGP flap dampening
+       history status.
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_connected_add): Point-to-point connected
+       address is properly handled.
+       (bgp_connected_delete): Likewise.
+
+       * bgp_route.c (bgp_route_init): Turn off BGP Flap dampening code
+       until it works fine.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_show_summary): Add BGP_VERSION_MP_4 case.
+
+       * bgp_route.c (bgp_update): When this is not damped route, clear
+       ri pointer.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_main.c: Add "-n" no_kernel option to not install route to
+       kernel.  Suggested by: "Matt Ranney" <mjr@ranney.com>
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_connected_add): Revert point-to-point
+       connected route patch.  Reported by ruud@ruud.org (Ruud de Rooij)
+
+       * bgp_damp.c (bgp_config_write_damp): Add configuration display
+       function.
+
+       * bgp_route.c (bgp_info_free): Set NULL to BGP dampening
+       information when BGP info structure is freed.
+       (bgp_info_cmp): Check damped flag.
+       (bgp_announce_check): Damped route is not announced.
+
+2001-01-09  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * bgpd.c (neighbor_capability_route_refresh): Change "neighbor
+       route-refresh" command to "neighbor capability route-refresh".
+       (clear_bgp_soft_in): Change soft-reconfig method.
+
+       clear ip bgp <neighbor> soft in
+        --------------------------------------
+        Try stored cache first then route-refresh
+
+        clear ip bgp <neighbor> in
+        ---------------------------------
+        Try route-refresh first then try to use stored cache
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_connected_add): Check point-to-point
+       connected route.  Reported by ruud@ruud.org (Ruud de Rooij)
+
+2001-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_nexthop_lookup): When IBGP nexthop is
+       changed, refresh it.
+
+2001-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.h (struct bgp_info_tag): Add as_selected to
+       bgp_info_tag.
+
+2001-01-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.h (struct bgp_info_tag): Add damped and bgp_damp_info
+       member for BGP flap dampening.
+
+       * bgp_damp.c: New file is added.
+
+       * bgp_damp.h: Likewise.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h (BGP_VTYSH_PATH): Change "/tmp/bgpd" to "/tmp/.bgpd".
+
+2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (zlookup_connect): Change to use UNIX domain
+       socket for zebra communication.
+
+2000-12-29  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_process): Fix "bgp deterministic-med" process.
+
+2000-12-27  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_process): Add "bgp deterministic-med" process.
+
+2000-12-25  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): Use ntohl comparing router ID.
+
+2000-12-18  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): When over three same prefix exit,
+       withdrawing best prefix perform router ID comparison.
+
+2000-12-15  Akihiro Mizutani  <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): Do not compare router ID when the
+       routes comes from EBGP peer.  When originator ID is same, take
+       shorter cluster-list route.  If cluster-list is same take smaller
+       IP address neighbor's route.
+
+       * bgpd.c (bgp_bestpath_aspath_ignore): Add "bgp bestpath as-path
+       ignore" command.  When this option is set, do not concider AS path
+       length when route selection.
+       (bgp_bestpath_compare_router_id): Add "bgp bestpath
+       compare-routerid".  When this option is set, compare router ID
+       when the routes comes from EBGP peer.
+       
+2000-12-15  Akihiro Mizutani  <mizutani@dml.com>
+
+       * bgp_route.c (bgp_info_cmp): Compare originator ID when it is
+       available.
+
+2000-12-14  Akihiro Mizutani  <mizutani@dml.com>
+
+       * bgp_packet.c (bgp_notify_receive): Disply received Notify data
+       information.
+
+2000-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_filter.c (as_filter_free): Use MTYPE_AS_FILTER_STR to make
+       it sure the memory is freed.
+
+       * bgp_route.c (route_vty_out_detail): Do not use AF_INET6 outside
+       HAVE_IPV6.
+
+2000-12-08  Akihiro Mizutani  <mizutani@dml.com>
+
+       * bgp_packet.c (bgp_notify_send_with_data): Store BGP notification
+       data part.
+
+       * bgp_network.c (bgp_accept): When BGP connection comes from
+       unconfigured IP address, close socket immediately.
+
+       * bgpd.c: Fix some display format.
+
+2000-11-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_keepalive_send): Delete duplicate
+       bgp_packet_set_size () call.
+
+2000-11-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_read_packet): Remove debug codes.
+
+2000-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_snmp.c (write_bgpPeerTable): Add SNMP set method routine.
+
+       * bgp_fsm.c (bgp_stop): Use fsm_change_status to change peer's
+       status.
+       (bgp_establish): Likewise.
+
+2000-11-26  Akihiro Mizutani  <mizutani@dml.com>
+
+       * bgp_open.c: Fix error messages.
+
+2000-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (bgp_establish): Call BGP trap when the peer is
+       established.
+       (bgp_stop): Call BGP trap when the peer is dropped.
+
+2000-11-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_snmp.c (bgp4PathAttrTable): Return BGP path attribute table.
+
+       * bgpd.h (struct peer): Add update_time for track last update
+       received time.
+
+       * bgp_packet.c (bgp_notify_receive): Preserv notify code and sub
+       code in any case.
+
+       * bgp_snmp.c (bgpPeerTable): Return remote router ID instead of
+       peering IP address.
+       (bgpPeerTable): Return actual BGP version number.
+
+2000-11-22  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_debug.c (bgp_notify_print): Notify data length display bug
+       is fixed.
+
+2000-11-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (zlookup_connect): When UNIX domain connection to
+       zebra is enabled, use the method.
+
+2000-11-16  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: Revise debug message output.
+
+2000-11-15  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_clist.c (ip_community_list): Fix bug of string comparison.
+
+2000-11-14  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_community.c (community_match): Fix bug of memcmp return
+       value check.
+
+2000-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_clist.c (community_list_match_exact): Add check for
+       entry->style is COMMUNITY_LIST.
+       (community_match_regexp): Apply new com_nthval macro.
+
+2000-11-07  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_routemap.c (route_set_community_delete): "set
+       community-delete COMMUNITY-LIST" is added.
+
+       * bgp_community.c (community_del_val): Delete one community.
+       (community_delete): Delete all community included in list.
+       (community_match): Fix bug of matching community value.
+
+       * bgp_clist.c (community_entry_free): Free community regular
+       expression.
+       (community_entry_make): Default style is COMMUNITY_LIST.
+       (community_entry_lookup): Make it sure style is COMMUNITY_LIST.
+       (community_entry_regexp_lookup): New function for community
+       regular expression lookup.
+       (community_match_regexp): New function.
+       (community_delete_regexp): New function.
+       (community_list_delete_entries): New function.
+       (community_list_match): Add COMMUNITY_REGEXP treatment.
+       (community_list_match_exact): Likewise.
+       (config_write_community): Write community list according to
+       entry->style.
+
+2000-11-07  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_attr.c (bgp_attr_aspath): AS path first AS check.
+
+       * bgp_clist.c (struct community_entry): Add style, regexp, reg to
+       community_entry.
+
+2000-11-06  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_aspath.c (aspath_firstas_check): AS path first AS check.
+
+       * bgpd.c (bgp_enforce_first_as): New command "bgp
+       enforce-first-as".
+
+       * bgpd.h (BGP_CONFIG_ENFORCE_FIRST_AS): Add new flag.
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_community.c (community_compare): Copy byte stream data to
+       actual value instead of using type casting hack.
+       (community_add_val): Likewise.
+       (community_uniq_sort): Likewise.
+       (community_print): Likewise.
+       (community_print_vty): Likewise.
+       (community_include): Use memcmp to compare community value.
+
+       * bgp_community.h (com_lastval): com_lastval and com_nthval macro
+       return pointer.
+
+2000-11-06  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.h (struct peer): Add established and dropped member for
+       count peering up/down statistics.
+
+       * bgpd.c (bgp_show_peer): Display peering up/down statistics.
+
+       * bgp_fsm.c (bgp_establish): Increment established count.
+       (bgp_stop): Increment dropped count.
+
+       * bgp_packet.c (bgp_notify_receive): Increament notify count.
+
+2000-11-1  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_fsm.c: Fix bug of holdtimer is not reset when bgp cleared. 
+
+2000-10-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h: Static bit flag is set by (1 << DIGIT).
+
+2000-10-24  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_ecommunity.c (ecommunity_dup): Extended community display
+       format fix.
+
+2000-10-24  Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+       * bgp_network.c (bgp_serv_sock_addrinfo): Use gai_strerror.
+       (bgp_serv_sock_addrinfo): Check address family.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+       * bgp_snmp.c: bgp_oid and bgpd_oid are used in smux_open after it
+       is registered.  So those variables must be static.
+
+2000-10-23  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_routemap.c (route_match_ip_next_hop): Change "match ip
+       next-hop" argument from IP address to access-list name.
+       Remove zebra-0.88 compatibility commands.
+        "match ip prefix-list WORD"
+        "match ipv6 prefix-list WORD"
+       
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (route_match_ipv6_next_hop_compile): Fix bug of
+       passing the pointer to the pointer of struct in6_addr instead of
+       the pointer of struct in6_addr in "match ipv6 next-hop" command.
+
+       * bgp_route.c (bgp_announce_check): Enclose IPv6 part with
+       HAVE_IPV6.
+
+2000-10-20  Jasper Wallace <jasper@ivision.co.uk>
+
+       * bgp_snmp.c (bgpPeerTable): ntohs missing bug is fixed.  Change
+       to use linklist.c.  Define COUNTER32 as ASN_COUNTER.
+
+2000-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_announce_check): attr->nexthop empty check
+       should be done by attr->nexthop.s_addr instead of strcmp.
+
+2000-10-18  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_zebra.c (zebra_read_ipv4): Pass nexthop value to
+       bgp_redistribute_add().
+
+       * bgp_nexthop.c (bgp_multiaccess_check_v4): New function for
+       checking IPv4 multiaccess nexthop.
+
+       * bgp_route.c (bgp_announce_check): In case of the nexthop is
+       reachable on multiaccess media, do not change nexthop.
+       (bgp_redistribute_add): Set nexthop when the value is passed.
+
+2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (bgp_timer_set): If peer is passive mode, do not set
+       connect timer.
+       (bgp_start): If the peer is passive mode, force to move to Active
+       mode.
+
+2000-10-17  Horms <horms@vergenet.net>
+
+       * bgp_debug.c (debug_bgp_fsm): Fix typo.
+
+2000-10-17  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c: "show ipv6 bgp" route display improvement.
+
+2000-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (neighbor_routes): Allocate sockunion for callback
+       function.
+       (bgp_show_neighbor_route): Remove static declaration for union
+       sockunion.
+
+       * bgpd.c (peer_update_source_set): Clean previously allocated
+       memory before allocate new one.
+
+2000-10-03  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (neighbor_routes): Add show neighbor's routes
+       command.
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes"
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes"
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes"
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes"
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-10-02  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: "bgp deterministic-med" command is added.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_connected_add): Apply mask for connected
+       route addition and deletion.
+
+2000-09-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_cmp_left): Skip confederation AS segment
+       when comparing leftmost AS number.
+
+2000-09-29  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c (peer_route_reflector): Route reflector can be set for
+       IBGP peer.
+       (bgp_distribute_set): Fix bug of string check for (in|out).
+       (bgp_show_summary): Display total neighbor count.
+
+2000-09-28  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_attr.c (bgp_packet_attribute): Only add cluster_list and
+       originator for clinet to client routes.
+       (bgp_packet_attribute): Add new cluster_list to the beginning of
+       existing cluster_list.
+       (bgp_packet_attribute): Fix bug of originator is rewritten even
+       when originator is already set.
+
+2000-09-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_client_to_client_reflection): Add new command.
+       "no bgp client-to-client reflection"
+       "bgp client-to-client reflection"
+
+       * bgpd.h (BGP_CONFIG_NO_CLIENT_TO_CLIENT): Add new definition.
+
+2000-09-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_read): Make BGP packet read to non-blocking
+       read.
+       (bgp_read_packet): Likewise.
+       (bgp_read_packet): When errono is EAGAIN, try to read it again.
+
+       * bgp_fsm.c (bgp_stop): Clear packet size and read buffer.
+
+2000-09-26  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_routemap.c: Configuration of prefix-list match is shown as
+       "match ip address prefix-list <WORD>".  Old configuration "match
+       ip prefix-list <WORD>" is left for compatibilitty.
+
+2000-09-25  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.h (BGP_CONFIG_MED_MISSING_AS_WORST): Changed from
+       BGP_CONFIG_MISSING_AS_WORST.
+
+       * bgpd.c (bgp_bestpath_med): Change missing-as-worst syntax.
+       Old "bgp bestpath missing-as-worst"
+       New "bgp bestpath med missing-as-worst"
+
+2000-09-24  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c: Compare MED properly in case of CONFED-IBGP.
+
+2000-09-21  steve@Watt.COM (Steve Watt)
+
+       * bgp_debug.h: Do not declare debug variables conf_bgp_debug_* and
+       term_bgp_debug_*.
+
+       * bgp_debug.c: Declare variables here.
+
+2000-09-21  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: MBGP soft-reconfiguration command is added.
+       clear ip bgp x.x.x.x ipv4 (unicast|multicast) in
+       clear ip bgp x.x.x.x ipv4 (unicast|multicast) out
+       clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft
+       clear ip bgp <1-65535> ipv4 (unicast|multicast) in
+       clear ip bgp <1-65535> ipv4 (unicast|multicast) out
+       clear ip bgp <1-65535> ipv4 (unicast|multicast) soft
+       clear ip bgp * ipv4 (unicast|multicast) in
+       clear ip bgp * ipv4 (unicast|multicast) out
+       clear ip bgp * ipv4 (unicast|multicast) soft
+
+       Change "clear ip bgp vpnv4 x.x.x.x soft" command to
+       "clear ip bgp x.x.x.x vpnv4 unicast soft".
+
+       "bgp bestpath med confed" command is added.
+       
+       * bgpd.h (BGP_CONFIG_MED_CONFED): Add New definition.
+
+2000-09-18  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgpd.c (bgp_show_peer): Fix misplaced #endif.
+
+2000-09-12  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c (bgp_default_local_preference): Add "bgp default
+       local-preference" command.
+
+       * bgp_nexthop.c (no_bgp_scan_time): Add "no bgp scan-time"
+       command.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (bgp_zebra_announce): BGP confederation peer's routes
+       are passed to zebra like IBGP route.
+
+2000-09-10  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c (bgp_config_write_peer): Make it consistent passive
+       configuration.
+
+       * bgp_route.c: Community match command is added.
+       "show ip bgp community <val>"
+       "show ip bgp community <val> exact-match"
+
+2000-09-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_nexthop_lookup): ebgp-multihop routes are
+       treated as IBGP routes.
+
+2000-09-08  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (bgp_show_route): When local-AS community route is
+       selected, display "not advertised outside local AS" to "show ip
+       route A.B.C.D" output.
+       (show_ip_bgp_ipv4_filter_list): Add below four commands.
+       "show ip bgp ipv4 (unicast|multicast) filter-list WORD"
+       "show ip bgp ipv4 (unicast|multicast) community"
+       "show ip bgp ipv4 (unicast|multicast) community-list WORD"
+       "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match"
+       
+       * bgp_clist.c (community_list_match_exact): Community exact match
+       function.
+
+2000-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_update): Add peer's ttl check.
+
+       * bgpd.h (struct peer): Structure member refresh is renamed to
+       refresh_adv.
+
+       * bgpd.c (clear_bgp_soft_in): Check PEER_FLAG_ROUTE_REFRESH flag
+       when soft reconfiguration is performed.
+
+       * bgp_zebra.c (bgp_zebra_announce): When the peer is EBGP and
+       ebgp-multiphop is set, set ZEBRA_FLAG_INTERNAL for nexthop lookup.
+
+       * bgp_route.h (struct bgp_info_tag): Add valid flag.
+
+2000-08-25  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: Add AS base BGP soft reconfiguration.
+
+       * bgp_route.c: When no-advertise or no-export route is selected,
+       "show ip bgp" display "not advertised to EBGP peer" or "not
+       advertised to any peer" message.
+       
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+       * bgp_dump.c (dump_bgp_routes): Change "dump bgp routes" to "dump
+       bgp route-mrt" to support MRT specific dump format.
+
+       * bgpd.c (bgp_init): "clear ip bgp vpnv4 soft {in,out}" command is
+       added.
+
+       * bgp_route.c (bgp_update): Currently nexthop check is only works
+       for IPv4.
+
+2000-08-17  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd. (clear_ip_bgp_all_soft): Add "clear ip bgp * soft" for
+       both inbound and outbound soft reconfiguration.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (clear_ip_bgp_peer_soft_out): Add soft-reconfiguration
+       outbound.
+       (peer_new): Set route-refresh flag.
+
+2000-08-16  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: "no bgp router-id A.B.C.D" alias is added.  "no bgp
+       cluster-id A.B.C.D" alias is added.  " bgp cluster-id
+       <1-4294967295>" alias is added.  "clear ip bgp * soft in" command
+       is added.  "clear ip bgp A.B.C.D in" alias is added.  "clear ip
+       bgp * in" alias is added.
+
+2000-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_update): Add soft_reconfig flag.  When the flag
+       is set do not install the route into Adj-RIBs-In.
+       (bgp_update): Perform implicit withdraw before filtering of the
+       route.
+
+       * bgp_packet.c (bgp_read): draft-ietf-idr-bgp-route-refresh-01.txt
+       capability code and BGP message can be accepted.
+
+       * bgp_open.c (bgp_capability_parse): Likewise.
+
+       * bgp_route.c (bgp_refresh_table): New function for route refresh.
+       (bgp_refresh_rib): Likewise.
+
+       * bgpd.c (bgp_show_peer): Display route refresh status.
+
+       * bgp_route.c (bgp_aggregate_add): Add check for the route
+       validness.
+       (bgp_aggregate_delete): Likewise.
+
+2000-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_nexthop.c (bgp_scan): Care for aggregate route when the
+       route become inaccessible.
+
+2000-08-15  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (show_ip_bgp_prefix): "show ip bgp A.B.C.D/M"
+       command is added.
+
+2000-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (bgp_interface_up): Register connected route.
+       (bgp_interface_down): Unregister connected route.
+
+2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.h (struct bgp_info): Add distance to the structure.
+
+       * bgp_route.c (bgp_aggregate_increment): Aggregate route only
+       match to smaller prefixlen route not match same prefixlen route.
+       (bgp_aggregate_decrement): Likewise.
+       (bgp_aggregate_add): Likewise.
+       (bgp_aggregate_delete): Likewise.
+       (bgp_network_backdoor): Add backdoor network configuration.
+
+       * bgpd.h (struct bgp ): Add distance_{ebgp,ibgp,local} for store
+       configuration distance value.
+
+       * bgp_route.c (bgp_update): Filter EBGP route which has non
+       connected nexthop.
+
+       * bgp_attr.c (bgp_attr_aggregate_intern): New function for
+       aggregate route.  Set origin to IGP.  Set atomic aggregate flag.
+       Set aggregator AS and address.
+       (bgp_attr_aggregate_intern): Check BGP_CONFIG_CONFEDERATION when
+       filling aggregator_as.
+
+       * bgp_route.c (bgp_process): Delete suppress check for install
+       suppressed route into local routing table.
+       (bgp_aggregate_increment): Use bgp_attr_aggregate_intern() instead
+       of bgp_attr_default_intern ().
+       (bgp_aggregate_add): Likewise.
+
+       * bgpd.c (bgp_get): Call bgp_if_update_all() after BGP instance is
+       created.  This is for avoid 0.0.0.0 router-id.
+
+2000-08-13  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (route_vty_out_detail): Display "valid" when the
+       route is valied.  Display "aggregated" when the route is
+       aggregated.  "Advertisements suppressed by an aggregate" is
+       displayed when the route is suppressed.
+       (bgp_info_cmp): Prefer EBGP than Confed-EBGP.
+
+2000-08-10  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c (route_vty_out_detail): Display format change.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_update): Only AFI_IP nexthop check is enabled.
+
+       * bgpd.c (bgp_delete): Delete static route before delete peer
+       configuration.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c: Include bgpd/bgp_nexthop.h.
+
+2000-07-31  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c (bgp_show_summary): "show ip bgp summary" shows own BGP
+       identifier.  And status is changed like below.
+
+       State/Pref   -> State/PfxRcd
+       Shutdown     -> Idle (Admin)
+       PrefixOvflw  -> Idle (PfxCt)
+
+       * bgp_route.c (route_vty_out): Show internal route as "i".
+
+2000-07-13  Jim Bowen <jimb@zereau.net>
+
+       * bgp_snmp.c: Add BGP peer MIB implementation.
+
+2000-07-12  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c (bgp_show_peer): Fix typo.
+
+2000-07-11  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_routemap.c: Add commands for deleting set without argument.
+
+2000-07-03  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_zebra.c: Fix redistribute help strings.
+
+2000-07-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_show): When bgpd works as vtysh server send all
+       output to vty at once.
+
+2000-06-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_mplsvpn.c (no_vpnv4_network): "no network A.B.C.D/M rd WORD
+       tag WORD" command is added.
+
+       * bgp_ecommunity.c (ecommunity_vty_out): New function added.
+
+2000-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_show): Fix total number of prefix count bug.
+
+       * bgpd.c (bgp_show_peer): Display VPNv4 unicast configuration and
+       negotiation result in "show ip bgp neighbors".
+
+2000-06-12  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgpd.c: Fix help strings.
+       
+       * bgpd.h: Likewise.
+       
+2000-06-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_aggregate_unset): Fix bug of checking rn->info
+       instead of rn.  Reported by Akihiro Mizutani <mizutani@dml.com>.
+
+       * bgp_mplsvpn.c (vpnv4_network): For testing purpose, "network
+       A.B.C.D rd RD" is added to address-family vpnv4 unicast node.
+
+       * bgp_route.c (bgp_static_set): Set safi to p.safi.
+
+2000-06-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_show_prefix_list): Change to use bgp_show().
+       (bgp_show_regexp): Change to use bgp_show().
+       (show_adj_route): Change to display header.
+
+       * bgpd.c (clear_bgp): Set peer->v_start to default value when peer
+       is cleared manually.
+
+       * bgp_route.c (bgp_show_route): New function which display
+       specific BGP route.  Divided from bgp_show().
+       (bgp_static_delete): Delete all static route.
+
+2000-06-09  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * bgp_route.c (show_ipv6_bgp): "show ipv6 bgp" is broken with
+       invalid privious fix.  Now show_ipv6_bgp and show_ipv6_bgp_route
+       take care of "show ipv6 bgp [X:X::X:X]".  Same change for "show ip
+       mbgp" and "show ipv6 mbgp".
+
+2000-06-07  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_route.c: Fix help strings and command arguments.
+
+2000-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_ecommunity.c: Include prefix.h
+
+2000-06-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.h (struct bgp_info_tag): New structure to hold tag
+       value.
+
+       * bgp_route.c (bgp_adj_set): table NULL check is added.
+       (bgp_adj_unset): Likewise.
+       (bgp_adj_lookup): Likewise.
+       (bgp_adj_clear): Likewise.
+       (route_vty_out): Add SAFI check for nexthop display.
+       (bgp_withdraw): Add SAFI check for withdraw route.
+
+       * Remove all #ifdef MPLS_VPN then include it as default.
+
+       * bgpd.c: Temporary disable peer-group command until the
+       implementation is completed.
+
+       * bgp_routemap.c (bgp_route_map_init): Install
+       route_metric_match_cmd.
+       (route_match_metric_compile): MED value compile using strtoul.
+
+2000-06-05  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_filter.c: Fix help strings.  Change REGEXP to LINE.  Change
+       NAME to WORD.
+
+       * Change command argument to more comprehensive.
+
+       METRIC         -> <0-4294967295>
+       WEIGHT         -> <0-4294967295>
+       LOCAL_PREF     -> <0-4294967295>
+       IP_ADDR        -> A.B.C.D
+       AS             -> <1-65535>
+       AS-PATH-NAME   -> WORD
+       ACCESS_LIST    -> WORD
+       PREFIX_LIST    -> WORD
+       COMMUNITY      -> AA:NN
+       EXT_COMMUNITY  -> ASN:nn_or_IP-address:nn
+       IPv6_ADDR      -> X:X::X:X
+
+       * bgp_clist.c: Fix help strings.
+
+2000-06-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (peer_active): Add new function for check the peer is
+       active or not.
+       (neighbor_activate): New command "neighbor PEER activate" and "no
+       neighbor PEER activate" are added.
+
+       * bgp_packet.c: Include bgpd/bgp_mplsvpn.h.
+
+2000-06-02  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_clist.c: Fix commuity-list help strings.
+
+       * bgp_routemap.c: Fix "set community" help strings.  Add #define
+       SET_STR.  Use (unicast|multicast) argument for "set nlri" command.
+       
+2000-06-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (route_set_community_none_cmd): "set community
+       none" command is added to route-map.
+
+2000-06-01  Akihiro Mizutani <mizutani@dml.com>
+
+       * bgp_debug.c: Change "show debug" to "show debugging".  Now "show
+       debugging" is not used in VIEW_NODE.
+
+2000-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (bgp_timer_set): Add check for shutdown flag.  This
+       fix unconditional BGP connection.
+
+       * bgpd.c (peer_shutdown): Replace peer_shutdown() with
+       peer_change_flag_with_reset().
+
+2000-05-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (no_bgp_default_ipv4_unicast): Add "no bgp default
+       ipv4-unicast" command.
+
+       * bgpd.h (BGP_CONFIG_NO_DEFAULT_IPV4): Add new definition.
+
+       * bgp_filter.c (as_list_delete): Free all AS filter.
+
+       * bgp_clist.c (community_list_delete): Free all community entry.
+
+       * bgp_filter.c (no_ip_as_path_all): New DEFUN for "no ip as-path
+       access-list NAME".
+
+       * bgp_clist.c (no_ip_community_list_all): New DEFUN for "no ip
+       community-list NAME".
+
+2000-05-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (ipv6_mbgp_neighbor_routes): Change "show ip bgp PEER
+       routes" to "show ip bgp PEER received-routes"
+
+2000-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_ecommunity.c (ecommunity_parse): New file for Extended
+       Communities attribute.
+       * bgp_ecommunity.h: Likewise.
+
+2000-05-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_mplsvpn.h: New file for MPLS-VPN.
+       * bgp_mplsvpn.c: Likewise.
+
+       * bgpd.c (bgp_delete): Fix bug of "no router bgp" crush.
+
+2000-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_bestpath_missing_as_worst): Add "bgp bestpath
+       missing-as-worst".
+
+2000-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (match_community): Clarify help of "match
+       community".
+
+2000-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_cmp_left): Remove debug code.
+
+2000-04-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_info_cmp): Compare MED only both routes comes
+       from same neighboring AS.
+
+       * bgp_aspath.c (aspath_cmp_left): Compare leftmost AS value.
+
+       * bgp_route.c (bgp_info_cmp): Fix misused htonl() to ntohl().
+
+2000-04-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_output_filter): When distribute-list's
+       corresponding access-list does not exist, filter all routes.
+       (bgp_input_filter): Likewise.
+
+2000-04-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_packet_attribute): Propagate MED to IBGP peer.
+
+       * bgp_route.c (bgp_info_cmp): Add evaluation of local preference.
+
+2000-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_distribute_update): Add struct access_list *
+       argument.
+
+2000-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_clist.c (community_list_dup_check): Add duplicate insertion
+       check.
+
+       * bgp_filter.c (as_list_dup_check): Add duplicate insertion check.
+
+       * bgp_route.c (bgp_show): Fix undeclared write variable.
+
+2000-04-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c: Add "match ip address prefix-list".
+
+2000-03-29  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_aspath.c (aspath_strip_confed): Fix realloc problem.
+
+2000-03-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (bgp_reconnect): Connect retry timer is expired when
+       the peer status is Connect.
+
+2000-03-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Fix bug of rewritten originator-id.
+
+2000-01-27  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_aspath.c (aspath_delimiter_char): New function.  Instead of
+       directly referencing array, search proper AS path delimiter.
+       (aspath_strip_confed): Strip the confederation stuff from the
+       front of an AS path.
+       (aspath_add_left_confed): New function for adding specified AS to
+       the leftmost AS_CONFED_SEQUENCE.
+
+       * bgp_aspath.h: Change AS_CONFED_SEQUENCE and AS_CONFED_SET value
+       to Cisco compatible.
+
+       * bgpd.c (bgp_confederation_id_set): Confederation configuration.
+       (bgp_confederation_id_unset): Likewise.
+       (bgp_confederation_peers_check): Likewise.
+       (bgp_confederation_peers_add): Likewise.
+       (bgp_confederation_peers_remove): Likewise.
+       (bgp_confederation_peers_set): Likewise.
+       (bgp_confederation_peers_unset): Likewise.
+       (bgp_confederation_peers_print): Likewise.
+       
+2000-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c: Introduce peer_change_flag_with_reset() fucntion.
+
+2000-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_open.c (bgp_open_option_parse): When there is no common
+       capability send Unsupported Capability error to the peer.
+
+2000-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_open.c (bgp_capability_mp): Fix bug of mis-negotiation about
+       IPv6 unicast.
+
+       * bgpd.c (bgp_init): Add "soft-reconfiguration inbound" command.
+       
+2000-01-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (neighbor_strict_capability): Add
+       "strict-capability-match" command.
+
+       * bgp_zebra.c (bgp_if_update): Ignore NET127 determining
+       router-id.
+
+       * bgpd.c (peer_override_capability): Add "override-capability"
+       command.
+
+1999-12-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_write): Change status to Idle and set timer
+       after write failed.
+
+1999-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (bgp_zebra_announce): Add info->selected check.
+
+1999-12-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (nlri_unfeasible): nlri_unfeasible() is merged with
+       nlri_parse().
+
+1999-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.h (BGP_EVENT_DELETE): Macro added.
+
+       * bgp_fsm.c (bgp_stop): Clear all event threads of the peer when
+       the peer is cleared.
+
+       * bgp_zebra.c (bgp_nexthop_set): Clear interface index of
+       link-local address.  This is KAME specific problem.
+
+1999-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_mp_reach_parse): Comment out previous code for a
+       while.  We don't completely detect the link is shared or not at
+       this moment.
+
+       * bgp_packet.c (bgp_notify_send): Make shortcut call of
+       bgp_write() and bgp_stop().
+
+       * bgp_attr.c (bgp_mp_reach_parse): Fix serious bug when getting
+       global and link-local address.
+
+1999-12-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (no_neighbor_port): New command added.
+       (peer_new): Set send_community.
+
+1999-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (show_ip_bgp_summary): Changed to use bgp_show_summary().
+       (show_ip_mbgp_summary): Likewise.
+       (show_ipv6_bgp_summary): Likewise.
+       (show_ipv6_mbgp_summary): Add new command.
+       (peer_free): Free peer->host.
+       (peer_lookup_by_su): Delete function.
+       (ipv6_bgp_neighbor): Changed to use peer_remote_as().
+       (sockunion_vty_out): Function deleted.
+       (vty_clear_bgp): Use afi instead of family.
+       Delete old list bgp_list.  Use struct newlist *bgplist.
+       (peer_lookup_by_host): Function deleted.
+
+1999-12-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h (struct peer_group): New structure added.
+       (struct peer_conf): New structure added.
+       (struct peer): Change all prefix_count to unsigned long.
+       
+       * bgpd.c: Reconstruct all of VTY commands reflect internal
+       structure change.
+       Use bgplist instead of bgp_list.
+       Use peerlist intstead of peer_list.
+
+       * bgp_attr.c (bgp_mp_reach_parse): If nlri_parse return -1, stop
+       parsing then return immediately.
+
+       * bgp_route.c (nlri_parse): When NLRI parse error occured, return
+       -1.
+       (nlri_process): Use pcount_v4_{unicast,multicast}.
+       (nlri_delete): Likewise.
+
+1999-11-25  Robert Olsson <Robert.Olsson@data.slu.se>
+
+       * bgp_routemap.c (route_match_nlri): `match nlri
+       unicast|multicast' and `set nlri unicast|multicast' command are
+       added.
+
+1999-11-22  Robert Olsson <Robert.Olsson@data.slu.se>
+
+       * bgpd.c: Add translate-update support.
+
+       * bgpd.h (TRANSLATE_UPDATE_OFF): Add translate-update definition.
+
+1999-11-19  Robert.Olsson@data.slu.se
+
+       * bgp_route.c (bgp_peer_delete): Add MBGP peer clear codes.
+
+1999-11-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_open.c (bgp_capability_mp): Temporary comment out
+       SAFI_UNICAST_MULTICAST handling until we know the meanings.
+
+1999-11-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_btoa.c: New file added.
+
+1999-11-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h (struct peer): Add dont_capability flag.
+       (struct peer): Add override_capability flag.
+
+       * bgpd.c (neighbor_dont_capability_negotiation): `neighbor PEER
+       dont-capability-negotiation' added.
+
+1999-11-12  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+       * bgp_attr.c (bgp_mp_reach_parse): Ignore link-local addresses
+       attribute from non-shared-network peers.
+
+1999-11-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_snmp.c: New file added.
+
+       * BGP4-MIB.txt: Updated to the latest Internet-Draft
+       draft-ietf-idr-bgp4-mib-04.txt.
+
+1999-11-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_route_init): Add `show ipv6 bgp prefix-list'.
+
+       * bgp_attr.c (bgp_mp_unreach_parse): Enclose safi setup with
+       #ifdef HAVE_MBGPV4.
+
+1999-11-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_dump.c (no_dump_bgp_all): Add [PATH] and [INTERVAL] to no
+       dump bgp commands.
+       (config_write_bgp_dump): Write interval value to the
+       configuration.
+
+1999-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c: Redistribute route-map support is added.
+
+       * bgp_zebra.h: New file added.
+
+1999-11-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_dump.c: BGP packet dump routine compatible with MRT.
+       * bgp_dump.h: BGP packet dump routine compatible with MRT.
+
+       * bgp_debug.c: Renamed from bgp_dump.c
+       * bgp_debug.h: Renamed from bgp_dump.h
+
+1999-10-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * BGP4-MIB.txt: New file added.  Edited version of RFC1657.
+
+1999-10-25  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+       * bgp_route.c (bgp_announce): If we're not on a shared network
+       with the peer and we don't have a link-local next hop, but the
+       inbound next-hop has a link-local address, don't readvertise it to
+       our peer.
+
+1999-10-25  Marc Boucher <marc@mbsi.ca>
+
+       * bgp_zebra.c: Add redistribute kernel command.
+
+1999-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_reset): New function added.
+
+       * bgpd.conf.sample2: Add IPv6 configuration sample.
+
+1999-10-24  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+       * bgp_route.c (ipv6_aggregate_address): Function added.
+
+1999-10-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_update): Unintern aspath, community, cluster
+       list after parsing BGP update packet.
+
+       * bgp_attr.c (bgp_attr_aspath): Intern parsed aspath.
+       (bgp_attr_community): Intern parsed community.
+       (bgp_attr_cluster_list): Intern parsed cluster list.
+
+       * bgp_routemap.c: Add `set community-additive' command.
+
+1999-10-21  Alexandr D. Kanevskiy <kad@blackcatlinux.com>
+
+       * bgp_routemap.c (route_set_local_pref): Fix bug of setting
+       attribute flag.
+
+1999-10-21  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
+
+       * bgp_route.c (bgp_announce): Add check of IPv6 default route
+       announcement.
+
+       * bgp_packet.c (bgp_update_send): Add BGP announcement logging.
+
+1999-10-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * `show ip[v6] bgp PREFIX' show uptime of the route.
+
+1999-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_filter_set): Delete PEER_FAMILY_{IPV4,IPV6}. instead
+       of that use AF_INET and AF_INET6 directly.
+       (vty_clear_bgp): Add new function to support various clear ip bgp
+       method.
+
+1999-10-04  Lars Fenneberg <lf@elemental.net>
+
+       * bgpd.c (clear_ip_bgp): Add `clear ip bgp ASN'.
+
+1999-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c: Add `match ip prefix-list' and `match ipv6
+       prefix-list'.
+
+1999-09-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_collision_detect): Add BGP collision detection
+       function.
+
+1999-09-26  Blake Meike <bmeike@adero.com>
+
+       * bgpd.c (neighbor_port): New command `neighbor PEER port PORT' is
+       added.
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (no_neighbor_timers_keepalive): Change MIN to min.  Add
+       min() macro.
+
+1999-08-19  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_packet.c (bgp_open): BGP holdtimer bug is fixed.  Make BGP
+       keepalive timer configurable.
+
+1999-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (bgp_redistribute_set): Fix redistribute bug.
+
+1999-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_peer_display): show ip bgp neighbors PEER only list
+       the peer not all of them.
+
+1999-08-11  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_route.c (bgp_announce): Remove MED if its an EBGP peer -
+       will get overwritten by route-maps.
+
+1999-08-08  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_routemap.c: Multi protocol route-map modification.
+
+1999-08-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c: Set network statement route's origin attribute as
+       igp.
+
+       * bgp_zebra.c: Set redistribute route's origin attribute as
+       incomplete.
+
+       * bgp_route.c (bgp_info_cmp): Add attribute existance check,
+       origin attribute check, BGP peer type check.
+
+1999-07-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_peer_delete): Reselect of IPv6 route.
+
+1999-07-29  Rick Payne <rickp@rossfell.co.uk>
+
+       * Changed route-maps to behave in a more cisco-like fashion
+
+1999-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (bgp_stop): Very serious bug of bgp_stop () is fixed.
+       When multiple route to the same destination exist, bgpd try to
+       announce the information to stopped peer.  Then add orphan write
+       thread is added.  This cause many strange behavior of bgpd.
+       Reported by Georg Hitsch <georg@atnet.at>.
+
+1999-07-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c: Change peer's A.B.C.D to PEER.
+
+1999-07-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_announce): Add hack for link-local nexthop.
+
+       * bgp_zebra.c (bgp_zebra_announce): Fill in nexthop address from
+       local address.
+
+1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_open): Holdtime fetch bug is fixed.  Reported
+       by Yuji SEKIYA <sekiya@sfc.wide.ad.jp>.
+
+1999-07-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c (fsm_holdtime): Don't close file descriptor in
+       fsm_holdtime ().
+
+1999-07-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c: Add `set atomic-aggregate' command.
+
+1999-07-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (route_set_ip_nexthop_cmd): Change "ip nexthop"
+       to "ip next-hop".
+       
+1999-07-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (show_ipv6_bgp_regexp): `show ipv6 bgp regexp'
+       added.
+
+1999-07-01  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgp_zebra.c (zebra_init): Install standard commands to
+       ZEBRA_NODE.
+
+1999-06-28  Rick Payne <rickp@rossfell.co.uk>
+
+       * bgpd.c (bgp_delete): bgp peer deletion bug is fixed.
+
+1999-06-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c: Add neighbor update-source command as ALIAS to
+       neighbor_interface.
+
+1999-06-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_packet_attribute): Send community attribute when
+       send_community flag is set.
+
+       * bgpd.h (struct peer): Add send_community flag.
+
+1999-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (router_bgp): router bgp's argument changed from AS_NO to
+       <1-65535>.
+
+1999-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.h (struct bgp_info): Add subtype for BGP route type.
+
+1999-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_community.c (community_merge): Function added.
+
+1999-06-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_clist.c: New file.
+       * bgp_clist.h: New file.
+
+       * bgp_community.h (COMMUNITY_LOCAL_AS): Added for Cisco
+       compatibility.
+       (COMMUNITY_NO_ADVERTISE): Fix typo.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c: Add `set weight WEIGHT' command.
+
+       * bgpd.c: Remove all_digit_check function.  Instead of that use
+       all_digit function in lib/prefix.c.
+
+       * bgp_routemap.c (bgp_route_map_init): Install
+       no_set_ipv6_nexthop_global_cmd and no_set_ipv6_nexthop_local_cmd
+       element to the RMAP_NODE.
+
+1999-05-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_make_str): Declare aspath_delimiter_char
+       inside aspath_make_str function.
+       (aspath_prepend): New function is added for AS path prepend.
+       (aspath_make_str_count): Renamed from aspath_make_str.  AS path
+       count is set to the structure.
+       (aspath_merge): New function.
+
+1999-05-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (redistribute_bgp): Add new DEFUN.
+       (no_redistribute_bgp): Likewise.
+       (router_zebra): Semantics changed.  Now 'router zebra' is default
+       behavior of bgpd.
+
+1999-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c: Add some commands to bgp route-map.
+       match ip next-hop: New command.
+       match metric: New command.
+       set metric: Doc fix.
+       set local-preference: Add DEFUN.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+       * bgp_main.c (signal_init): SIGTERM call sigint.
+       (sigint): Loggging more better message.
+
+1999-05-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_packet_attribute): AS path attribute extended
+       length bit check is added.
+
+1999-05-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (bgp_route_map_init): Call route_map_install_set
+       function with route_set_local_pref_cmd argument.
+       (no_match_aspath): Function added.
+       (route_set_metric): Set attribute flag bit.
+
+       * bgp_attr.c (bgp_packet_attribute): MULTI_EXIT_DISC is now in BGP
+       packet.
+
+1999-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (no_neighbor_timers_holdtime): `no neighbor PEER timers
+       holdtime' command is added.
+
+       * bgpd.h (BGP_DEFAULT_HOLDTIME_BIG): Delete define.
+
+       * bgpd.c (bgp_prefix_list_set): New function added.
+       (bgp_prefix_list_unset): Likewise.
+       (bgp_prefix_list_update): Likewise.
+       (show_ip_bgp_neighbors): prefix-list information display.
+
+1999-05-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_delete): Function added for `no router bgp'.
+
+1999-05-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_dump.c (bgp_dump_attr): Add originator_id display.
+
+       * bgpd.c (bgp_router_id): Even when address is malformed set the
+       value to configuration bug fixed.
+       (no_bgp_router_id): New function.
+       (no_bgp_cluster_id): New function.
+
+1999-05-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h (BGP_ATTR_ORIGINATOR_ID): Changed from BGP_ATTR_ORIGINATOR.
+
+1999-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (bgp_announce): Add route reflector check.
+
+1999-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_cluster_id): Add function for route reflector.
+       (neighbor_route_reflector_client): Likewise.
+       (no_neighbor_route_reflector_client): Likewise.
+
+       * bgpd.h (struct bgp ): Add cluster for route reflector.
+
+       * bgp_route.c (show_ip_bgp_prefix_list): New command is added.
+
+1999-04-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (noinst_HEADERS): Add bgp_filter.h
+
+       * bgp_aspath.c (aspath_undup): Function deleted.  aspath_free ()
+       has same functionality.
+
+       * bgp_filter.h: New file.
+
+       * bgp_aspath.c (aspath_unintern): Rename aspath_free () to
+       aspath_unintern ()
+       (aspath_free): New function.
+
+1999-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_aggregate): Function added.
+
+       * bgp_aspath.h (aspath_aggregate): Prototype added.
+
+       * bgp_aspath.c (aspath_empty_aspath): New argument
+       gated_dont_eat_flag is added.
+
+1999-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c: Add bgp_aggregate_ipv4 and bgp_aggregate_ipv6.
+
+1999-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c (aggregate_address): Function added.
+
+       * bgp_zebra.c (zebra_read): Change log to zlog.
+
+1999-04-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (noninst_HEADERS): Added for make dist.
+
+1999-04-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * aspath_regex.c: Removed from distribution.
+
+1999-04-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c (bgp_packet_attribute): Old draft-00 packet treatment
+       bug fixed.
+
+1999-04-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_add_left): Fix empty aspath bug.  Reported
+       by kad@gibson.skif.net.
+
+       * bgp_regex.[ch]: New file added.
+
+       
+1999-04-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_filter.c: New file added.
+
+1999-04-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_empty_aspath): Change for peering with
+       gated.
+
+1999-03-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_main.c (main): Default loggin method changed from syslog to
+       stdout.
+
+1999-03-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c: Delete obsolete default attribute DEFUN.
+
+1999-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.c: Make attribute structure put into attribute hash.
+
+1999-03-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_view.c : Delete file.
+
+1999-02-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_routemap.c (bgp_apply_route_map): Add prefix argument. 
+
+       * bgp_route.h (struct bgp_info): Add bgp_info structre.  I'll
+       replace bgp_route with this.
+
+       * bgp_routemap.c (route_match_ip_address): Fix bug of passing non
+       prefix value to access_list_apply(). 
+
+       * bgpd.conf.sample: Add route-map sample.
+       Delete obsolete default-attr statements.
+
+       * bgp_packet.c: Use stream_fifo for packet queueing.
+
+1999-02-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_add_left): add non empty aspath treatment.
+
+       * bgp_main.c: include unistd.h for daemon().
+
+       * bgp_route.c (nlri_process): add IPv6 table lookup.
+
+       * bgp_attr.c (route_parse_ipv6): call nlri_process().
+       (attr_make): Obsolete function attr_make deleted.
+
+1999-02-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_add_left): change function name from
+       aspath_add_leftmost_as().
+
+1999-02-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c: add aspath_add_leftmost_as ().
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * syslog support added
+
+1999-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c: DEFUN (neighbor_nexthop): deleted.
+       DEFUN (neighbor_distribute_list): added.
+
+1999-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h (struct peer ): header_buf and read_buf is removed.
+
+       * bgp_peer.[ch]: Deleted.  Peer related functions are merged to
+       bgpd.c
+
+       * bgp_network.c: New file.
+       * bgp_network.h: New file.
+
+       * bgp_packet.h: New file.
+       
+1999-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c (bgp_keepalive_send): Now BGP keepalive packet is
+       buffered.
+
+1999-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_packet.c: New file.
+
+1998-12-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_zebra.c (zebra_client): Use zebra_connect() in lib/client.c. 
+
+       * `show ip bgp' bug fixed.
+       * aspath_log (): Remove argument logfp.
+
+1998-12-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.h: New file.
+
+1998-12-15  Magnus Ahltorp <map@stacken.kth.se>
+
+       * bgp_attr.c, bgp_community.h, bgp_dump.c, bgp_fsm.c, bgp_open.c
+       bgp_peer.c, bgp_peer.h, bgp_route.c, bgp_route.h, bgp_view.c
+       bgpd.c, bgpd.h, bgp_attr.c, bgp_community.h, bgp_dump.c,
+       bgp_fsm.c, bgp_open.c, bgp_peer.c, bgp_peer.h: Prototype fixes.
+
+1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (bgp_config_write): Delete vector v argument.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h: Delete annoying ld_[124]byte and st_[124]byte macros.
+
+1998-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_radix.[ch]: removed.
+
+1998-09-15  HEO SeonMeyong  <seirios@matrix.iri.co.jp>
+
+       * bgp_main.c: ifdef HYDRANGEA -> ifdef KAME
+
+1998-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_dump.c: delete nroute().
+
+1998-05-19  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * bgp_aspath.c: HAVE_CONFIG_H typo :-)
+       * bgpd.h: Modify for compile on Solaris.
+       * bgp_aspath.h: likewize
+       * bgp_community.h: likewize
+       * bgp_routemap.c: likewize
+
+1998-05-18  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * bgpd.h: Modify for compile on Solaris.
+       * bgp_aspath.h: likewize
+
+1998-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.[ch]: move to ../lib directory.
+
+1998-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.c (route_map_apply): add function.
+
+1998-05-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.h: add file.
+
+       * bgp_peer.h (enum ): change PEER_{IBGP,EBGP} to BGP_PEER_{IBGP,EBGP}
+
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: sysconfdir_DATA added.
+
+1998-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_dump.c: add `debug bgp fsm'
+                     add `no debug bgp fsm'
+                     add `show debug bgp'
+       * bgp_open.c: File added.
+
+1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * .cvsignore: File added.
+
+1998-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_community.[ch]: File added.
+
+1998-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd now use lib/thread.[ch].
+
+1998-01-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.c (show_ip_bgp_neighbors): add 'show ip bgp neighbors' command.
+
+       * bgpd.h (BGP_DEFAULT_START_TIMER): change from 1 to 30.
+
+1997-12-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_vty.c: bgp_vty.c deleted.
+
+       * bgpd.c (config_write_neighbor): add ebgp-multihop command.
+
+1997-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_fsm.c: [-p bgp_port] and [-P vty_port] works
+
+1997-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_vty.c: new file.
+
+       * bgp_attr.c: add new logging system.
+
+1997-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Change all inet_addr call into inet_aton.
+
+1997-11-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_radix.c: change radix_peer_delete
+
+1997-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c: move AS_TOKEN_??? definition from header to c source.
+
+1997-09-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_dump.c (bgp_log_route): add dump_attr function
+
+1997-09-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (aspath_test): change AS_SET brace from '[' to '{'
+       * bgp_dump.c (bgp_log_route): change logfile format.
+
+1997-08-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_open.c (bgp_open): move bgp_open function from bgpd.c
+       * bgp_attr.c (community_str2com): add community value generation
+       * bgp_attr.h: add SAFI definition for BGP-4+
+
+1997-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgpd.h: add BGP_OPEN_OPT_CAP for Capabilities Optional Parameter
+       * Makefile.in: add bgp_open.o, delete bgp_loop.o
+       * bgp_open.c: newfile which manages BGP Open message
+       * bgp_loop.c: this file is merged with bgp_fsm.c
+       * bgp_radix.c (radix_add): radix_add() now return route_t instead
+       of int
+       (bgp_sim): now we can read update & withdraw from file
+       * bgp_route.c: add route_free() call into route_parse etc.
+
+1997-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_radix.c: Radix code is completely rewritten. It has better
+       memory treatment than old one.
+
+1997-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_route.c: route_alloc for route struct allocation statistics.
+       * bgpd.c (bgp_make_update): now we cann announce MED attribute.
+       * bgp_aspath.c (aspath_print_all): change aspath_print_all output
+       format.
+
+1997-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_term.c (term_parse): add command : show asstat, show ashash
+       * bgp_aspath.c: aspath_cmp bug fix
+       (aspath_print_all): add aspath_print_all ();
+       * bgp_peer.h: delete rlist element from struct peer.
+
+1997-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c: completely rewritten.
+       * bgp_aspath.h: completely rewritten.
+       add AsPath, AsSegment structure
+       add AS_SET treatment
+       change Hash codes
+
+1997-08-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_attr.h: add Attribute flags defines
+       * bgp_route.c: delete rlist related functions
+       * bgp_aspath.c (as_origin): add as_origin function
+       (aspath_print): move from bgp_dump.c and add support of AS_SET
+       change Hash related function names.
+
+1997-08-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.h: add next entry, delete rlist entry from struct aspath
+
+1997-08-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * bgp_aspath.c (as_sort): add function as_sort
+       * bgp_aspath.h: add IBGP, EBGP
+
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
new file mode 100644 (file)
index 0000000..7f739f6
--- /dev/null
@@ -0,0 +1,44 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = libbgp.a
+sbin_PROGRAMS = bgpd
+
+libbgp_a_SOURCES = \
+       bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
+       bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
+       bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
+       bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
+       bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c
+
+noinst_HEADERS = \
+       bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
+       bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
+       bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
+       bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
+       bgp_advertise.h bgp_snmp.h bgp_vty.h
+
+bgpd_SOURCES = \
+       bgp_main.c $(libbgp_a_SOURCES)
+
+bgpd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2
+
+EXTRA_DIST = $(sysconf_DATA) BGP4-MIB.txt
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
diff --git a/bgpd/Makefile.in b/bgpd/Makefile.in
new file mode 100644 (file)
index 0000000..06c5189
--- /dev/null
@@ -0,0 +1,534 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = libbgp.a
+sbin_PROGRAMS = bgpd
+
+libbgp_a_SOURCES = \
+       bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
+       bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
+       bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
+       bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
+       bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c
+
+
+noinst_HEADERS = \
+       bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
+       bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
+       bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
+       bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
+       bgp_advertise.h bgp_snmp.h bgp_vty.h
+
+
+bgpd_SOURCES = \
+       bgp_main.c $(libbgp_a_SOURCES)
+
+
+bgpd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2
+
+EXTRA_DIST = $(sysconf_DATA) BGP4-MIB.txt
+subdir = bgpd
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libbgp_a_AR = $(AR) cru
+libbgp_a_LIBADD =
+am_libbgp_a_OBJECTS = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) \
+       bgp_aspath.$(OBJEXT) bgp_community.$(OBJEXT) bgp_attr.$(OBJEXT) \
+       bgp_debug.$(OBJEXT) bgp_route.$(OBJEXT) bgp_zebra.$(OBJEXT) \
+       bgp_open.$(OBJEXT) bgp_routemap.$(OBJEXT) bgp_packet.$(OBJEXT) \
+       bgp_network.$(OBJEXT) bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) \
+       bgp_clist.$(OBJEXT) bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) \
+       bgp_ecommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \
+       bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \
+       bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT)
+libbgp_a_OBJECTS = $(am_libbgp_a_OBJECTS)
+sbin_PROGRAMS = bgpd$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) bgp_aspath.$(OBJEXT) \
+       bgp_community.$(OBJEXT) bgp_attr.$(OBJEXT) bgp_debug.$(OBJEXT) \
+       bgp_route.$(OBJEXT) bgp_zebra.$(OBJEXT) bgp_open.$(OBJEXT) \
+       bgp_routemap.$(OBJEXT) bgp_packet.$(OBJEXT) \
+       bgp_network.$(OBJEXT) bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) \
+       bgp_clist.$(OBJEXT) bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) \
+       bgp_ecommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \
+       bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \
+       bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT)
+am_bgpd_OBJECTS = bgp_main.$(OBJEXT) $(am__objects_1)
+bgpd_OBJECTS = $(am_bgpd_OBJECTS)
+bgpd_DEPENDENCIES = ../lib/libzebra.a
+bgpd_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bgp_advertise.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_aspath.Po ./$(DEPDIR)/bgp_attr.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_clist.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_community.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_damp.Po ./$(DEPDIR)/bgp_debug.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_dump.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_ecommunity.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_filter.Po ./$(DEPDIR)/bgp_fsm.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_main.Po ./$(DEPDIR)/bgp_mplsvpn.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_network.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_nexthop.Po ./$(DEPDIR)/bgp_open.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_packet.Po ./$(DEPDIR)/bgp_regex.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_route.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_routemap.Po ./$(DEPDIR)/bgp_snmp.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_table.Po ./$(DEPDIR)/bgp_vty.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/bgp_zebra.Po ./$(DEPDIR)/bgpd.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  bgpd/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libbgp.a: $(libbgp_a_OBJECTS) $(libbgp_a_DEPENDENCIES) 
+       -rm -f libbgp.a
+       $(libbgp_a_AR) libbgp.a $(libbgp_a_OBJECTS) $(libbgp_a_LIBADD)
+       $(RANLIB) libbgp.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sbindir)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+         rm -f $(DESTDIR)$(sbindir)/$$f; \
+       done
+
+clean-sbinPROGRAMS:
+       -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+bgpd$(EXEEXT): $(bgpd_OBJECTS) $(bgpd_DEPENDENCIES) 
+       @rm -f bgpd$(EXEEXT)
+       $(LINK) $(bgpd_LDFLAGS) $(bgpd_OBJECTS) $(bgpd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_advertise.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_aspath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_attr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_clist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_community.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_damp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_ecommunity.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_filter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_fsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mplsvpn.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_nexthop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_open.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_regex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_vty.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgpd.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+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 =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-noinstLIBRARIES clean-sbinPROGRAMS ctags 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 pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
new file mode 100644 (file)
index 0000000..4778a97
--- /dev/null
@@ -0,0 +1,405 @@
+/* BGP advertisement and adjacency
+   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "hash.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_mplsvpn.h"
+\f
+/* BGP advertise attribute is used for pack same attribute update into
+   one packet.  To do that we maintain attribute hash in struct
+   peer.  */
+static struct bgp_advertise_attr *
+baa_new ()
+{
+  return (struct bgp_advertise_attr *)
+    XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr));
+}
+
+static void
+baa_free (struct bgp_advertise_attr *baa)
+{
+  XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa);
+}
+
+static void *
+baa_hash_alloc (struct bgp_advertise_attr *ref)
+{
+  struct bgp_advertise_attr *baa;
+
+  baa = baa_new ();
+  baa->attr = ref->attr;
+  return baa;
+}
+
+static unsigned int
+baa_hash_key (struct bgp_advertise_attr *baa)
+{
+  return attrhash_key_make (baa->attr);
+}
+
+static int
+baa_hash_cmp (struct bgp_advertise_attr *baa1, struct bgp_advertise_attr *baa2)
+{
+  return attrhash_cmp (baa1->attr, baa2->attr);
+}
+\f
+/* BGP update and withdraw information is stored in BGP advertise
+   structure.  This structure is referred from BGP adjacency
+   information.  */
+static struct bgp_advertise *
+bgp_advertise_new ()
+{
+  return (struct bgp_advertise *) 
+    XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise));
+}
+
+void
+bgp_advertise_free (struct bgp_advertise *adv)
+{
+  XFREE (MTYPE_BGP_ADVERTISE, adv);
+}
+
+void
+bgp_advertise_add (struct bgp_advertise_attr *baa,
+                  struct bgp_advertise *adv)
+{
+  adv->next = baa->adv;
+  if (baa->adv)
+    baa->adv->prev = adv;
+  baa->adv = adv;
+}
+
+void
+bgp_advertise_delete (struct bgp_advertise_attr *baa,
+                     struct bgp_advertise *adv)
+{
+  if (adv->next)
+    adv->next->prev = adv->prev;
+  if (adv->prev)
+    adv->prev->next = adv->next;
+  else
+    baa->adv = adv->next;
+}
+
+static struct bgp_advertise_attr *
+bgp_advertise_intern (struct hash *hash, struct attr *attr)
+{
+  struct bgp_advertise_attr ref;
+  struct bgp_advertise_attr *baa;
+
+  ref.attr = bgp_attr_intern (attr);
+  baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc);
+  baa->refcnt++;
+
+  return baa;
+}
+
+void
+bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
+{
+  if (baa->refcnt)
+    baa->refcnt--;
+
+  if (baa->refcnt && baa->attr)
+    bgp_attr_unintern (baa->attr);
+  else
+    {
+      if (baa->attr)
+       {
+         hash_release (hash, baa);
+         bgp_attr_unintern (baa->attr);
+       }
+      baa_free (baa);
+    }
+}
+\f
+/* BGP adjacency keeps minimal advertisement information.  */
+void
+bgp_adj_out_free (struct bgp_adj_out *adj)
+{
+  XFREE (MTYPE_BGP_ADJ_OUT, adj);
+}
+
+int
+bgp_adj_out_lookup (struct peer *peer, struct prefix *p,
+                   afi_t afi, safi_t safi, struct bgp_node *rn)
+{
+  struct bgp_adj_out *adj;
+
+  for (adj = rn->adj_out; adj; adj = adj->next)
+    if (adj->peer == peer)
+      break;
+
+  if (! adj)
+    return 0;
+
+  return (adj->adv 
+         ? (adj->adv->baa ? 1 : 0)
+         : (adj->attr ? 1 : 0));
+}
+
+struct bgp_advertise *
+bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj,
+                    afi_t afi, safi_t safi)
+{
+  struct bgp_advertise *adv;
+  struct bgp_advertise_attr *baa;
+  struct bgp_advertise *next;
+
+  adv = adj->adv;
+  baa = adv->baa;
+  next = NULL;
+
+  if (baa)
+    {
+      /* Unlink myself from advertise attribute FIFO.  */
+      bgp_advertise_delete (baa, adv);
+
+      /* Fetch next advertise candidate. */
+      next = baa->adv;
+
+      /* Unintern BGP advertise attribute.  */
+      bgp_advertise_unintern (peer->hash[afi][safi], baa);
+      adv->baa = NULL;
+      adv->rn = NULL;
+    }
+
+  /* Unlink myself from advertisement FIFO.  */
+  FIFO_DEL (adv);
+
+  /* Free memory.  */
+  bgp_advertise_free (adj->adv);
+  adj->adv = NULL;
+
+  return next;
+}
+
+void
+bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
+                struct attr *attr, afi_t afi, safi_t safi,
+                struct bgp_info *binfo)
+{
+  struct bgp_adj_out *adj = NULL;
+  struct bgp_advertise *adv;
+
+#ifdef DISABLE_BGP_ANNOUNCE
+  return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+  /* Look for adjacency information. */
+  if (rn)
+    {
+      for (adj = rn->adj_out; adj; adj = adj->next)
+       if (adj->peer == peer)
+         break;
+    }
+
+  if (! adj)
+    {
+      adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
+
+      if (rn)
+        {
+          BGP_ADJ_OUT_ADD (rn, adj);
+          bgp_lock_node (rn);
+        }
+    }
+
+  if (adj->adv)
+    bgp_advertise_clean (peer, adj, afi, safi);
+
+  adj->peer = peer;
+  adj->adv = bgp_advertise_new ();
+
+  adv = adj->adv;
+  adv->rn = rn;
+  adv->binfo = binfo;
+  if (attr)
+    adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr);
+  else
+    adv->baa = baa_new ();
+  adv->adj = adj;
+
+  /* Add new advertisement to advertisement attribute list. */
+  bgp_advertise_add (adv->baa, adv);
+
+  FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo);
+}
+
+void
+bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, 
+                  afi_t afi, safi_t safi)
+{
+  struct bgp_adj_out *adj;
+  struct bgp_advertise *adv;
+
+#ifdef DISABLE_BGP_ANNOUNCE
+  return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+  /* Lookup existing adjacency, if it is not there return immediately.  */
+  for (adj = rn->adj_out; adj; adj = adj->next)
+    if (adj->peer == peer)
+      break;
+
+  if (! adj)
+    return;
+
+  /* Clearn up previous advertisement.  */
+  if (adj->adv)
+    bgp_advertise_clean (peer, adj, afi, safi);
+
+  if (adj->attr)
+    {
+      /* We need advertisement structure.  */
+      adj->adv = bgp_advertise_new ();
+      adv = adj->adv;
+      adv->rn = rn;
+      adv->adj = adj;
+
+      /* Add to synchronization entry for withdraw announcement.  */
+      FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo);
+
+      /* Schedule packet write. */
+      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+    }
+  else
+    {
+      /* Remove myself from adjacency. */
+      BGP_ADJ_OUT_DEL (rn, adj);
+      
+      /* Free allocated information.  */
+      bgp_adj_out_free (adj);
+
+      bgp_unlock_node (rn);
+    }
+}
+
+void
+bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, 
+                   struct peer *peer, afi_t afi, safi_t safi)
+{
+  if (adj->attr)
+    bgp_attr_unintern (adj->attr);
+
+  if (adj->adv)
+    bgp_advertise_clean (peer, adj, afi, safi);
+
+  BGP_ADJ_OUT_DEL (rn, adj);
+  bgp_adj_out_free (adj);
+}
+\f
+void
+bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
+{
+  struct bgp_adj_in *adj;
+
+  for (adj = rn->adj_in; adj; adj = adj->next)
+    {
+      if (adj->peer == peer)
+       {
+         if (adj->attr != attr)
+           {
+             bgp_attr_unintern (adj->attr);
+             adj->attr = bgp_attr_intern (attr);
+           }
+         return;
+       }
+    }
+  adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in));
+  adj->peer = peer;
+  adj->attr = bgp_attr_intern (attr);
+  BGP_ADJ_IN_ADD (rn, adj);
+  bgp_lock_node (rn);
+}
+
+void
+bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
+{
+  bgp_attr_unintern (bai->attr);
+  BGP_ADJ_IN_DEL (rn, bai);
+  XFREE (MTYPE_BGP_ADJ_IN, bai);
+}
+
+void
+bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer)
+{
+  struct bgp_adj_in *adj;
+
+  for (adj = rn->adj_in; adj; adj = adj->next)
+    if (adj->peer == peer)
+      break;
+
+  if (! adj)
+    return;
+
+  bgp_adj_in_remove (rn, adj);
+  bgp_unlock_node (rn);
+}
+\f
+void
+bgp_sync_init (struct peer *peer)
+{
+  afi_t afi;
+  safi_t safi;
+  struct bgp_synchronize *sync;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       sync = XCALLOC (MTYPE_TMP, sizeof (struct bgp_synchronize));
+       FIFO_INIT (&sync->update);
+       FIFO_INIT (&sync->withdraw);
+       FIFO_INIT (&sync->withdraw_low);
+       peer->sync[afi][safi] = sync;
+       peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp);
+      }
+}
+
+void
+bgp_sync_delete (struct peer *peer)
+{
+  afi_t afi;
+  safi_t safi;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       if (peer->sync[afi][safi])
+         XFREE (MTYPE_TMP, peer->sync[afi][safi]);
+       peer->sync[afi][safi] = NULL;
+
+       hash_free (peer->hash[afi][safi]);
+      }
+}
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
new file mode 100644 (file)
index 0000000..e2ae010
--- /dev/null
@@ -0,0 +1,178 @@
+/* BGP advertisement and adjacency
+   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* BGP advertise FIFO.  */
+struct bgp_advertise_fifo
+{
+  struct bgp_advertise *next;
+  struct bgp_advertise *prev;
+};
+
+/* BGP advertise attribute.  */
+struct bgp_advertise_attr
+{
+  /* Head of advertisement pointer. */
+  struct bgp_advertise *adv;
+
+  /* Reference counter.  */
+  unsigned long refcnt;
+
+  /* Attribute pointer to be announced.  */
+  struct attr *attr;
+};
+
+struct bgp_advertise
+{
+  /* FIFO for advertisement.  */
+  struct bgp_advertise_fifo fifo;
+
+  /* Link list for same attribute advertise.  */
+  struct bgp_advertise *next;
+  struct bgp_advertise *prev;
+
+  /* Prefix information.  */
+  struct bgp_node *rn;
+
+  /* Reference pointer.  */
+  struct bgp_adj_out *adj;
+
+  /* Advertisement attribute.  */
+  struct bgp_advertise_attr *baa;
+
+  /* BGP info.  */
+  struct bgp_info *binfo;
+};
+
+/* BGP adjacency out.  */
+struct bgp_adj_out
+{
+  /* Lined list pointer.  */
+  struct bgp_adj_out *next;
+  struct bgp_adj_out *prev;
+
+  /* Advertised peer.  */
+  struct peer *peer;
+
+  /* Advertised attribute.  */
+  struct attr *attr;
+
+  /* Advertisement information.  */
+  struct bgp_advertise *adv;
+};
+
+/* BGP adjacency in. */
+struct bgp_adj_in
+{
+  /* Linked list pointer.  */
+  struct bgp_adj_in *next;
+  struct bgp_adj_in *prev;
+
+  /* Received peer.  */
+  struct peer *peer;
+
+  /* Received attribute.  */
+  struct attr *attr;
+};
+
+/* BGP advertisement list.  */
+struct bgp_synchronize
+{
+  struct bgp_advertise_fifo update;
+  struct bgp_advertise_fifo withdraw;
+  struct bgp_advertise_fifo withdraw_low;
+};
+
+/* FIFO -- first in first out structure and macros.  */
+struct fifo
+{
+  struct fifo *next;
+  struct fifo *prev;
+};
+
+#define FIFO_INIT(F)                                  \
+  do {                                                \
+    struct fifo *Xfifo = (struct fifo *)(F);          \
+    Xfifo->next = Xfifo->prev = Xfifo;                \
+  } while (0)
+
+#define FIFO_ADD(F,N)                                 \
+  do {                                                \
+    struct fifo *Xfifo = (struct fifo *)(F);          \
+    struct fifo *Xnode = (struct fifo *)(N);          \
+    Xnode->next = Xfifo;                              \
+    Xnode->prev = Xfifo->prev;                        \
+    Xfifo->prev = Xfifo->prev->next = Xnode;          \
+  } while (0)
+
+#define FIFO_DEL(N)                                   \
+  do {                                                \
+    struct fifo *Xnode = (struct fifo *)(N);          \
+    Xnode->prev->next = Xnode->next;                  \
+    Xnode->next->prev = Xnode->prev;                  \
+  } while (0)
+
+#define FIFO_HEAD(F)                                  \
+  ((((struct fifo *)(F))->next == (struct fifo *)(F)) \
+  ? NULL : (F)->next)
+
+/* BGP adjacency linked list.  */
+#define BGP_INFO_ADD(N,A,TYPE)                        \
+  do {                                                \
+    (A)->prev = NULL;                                 \
+    (A)->next = (N)->TYPE;                            \
+    if ((N)->TYPE)                                    \
+      (N)->TYPE->prev = (A);                          \
+    (N)->TYPE = (A);                                  \
+  } while (0)
+
+#define BGP_INFO_DEL(N,A,TYPE)                        \
+  do {                                                \
+    if ((A)->next)                                    \
+      (A)->next->prev = (A)->prev;                    \
+    if ((A)->prev)                                    \
+      (A)->prev->next = (A)->next;                    \
+    else                                              \
+      (N)->TYPE = (A)->next;                          \
+  } while (0)
+
+#define BGP_ADJ_IN_ADD(N,A)    BGP_INFO_ADD(N,A,adj_in)
+#define BGP_ADJ_IN_DEL(N,A)    BGP_INFO_DEL(N,A,adj_in)
+#define BGP_ADJ_OUT_ADD(N,A)   BGP_INFO_ADD(N,A,adj_out)
+#define BGP_ADJ_OUT_DEL(N,A)   BGP_INFO_DEL(N,A,adj_out)
+
+/* Prototypes.  */
+void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *,
+                     struct attr *, afi_t, safi_t, struct bgp_info *);
+void bgp_adj_out_unset (struct bgp_node *, struct peer *, struct prefix *,
+                       afi_t, safi_t);
+void bgp_adj_out_remove (struct bgp_node *, struct bgp_adj_out *, 
+                        struct peer *, afi_t, safi_t);
+int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t,
+                       struct bgp_node *);
+
+void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *);
+void bgp_adj_in_unset (struct bgp_node *, struct peer *);
+void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *);
+
+struct bgp_advertise *
+bgp_advertise_clean (struct peer *, struct bgp_adj_out *, afi_t, safi_t);
+
+void bgp_sync_init (struct peer *);
+void bgp_sync_delete (struct peer *);
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
new file mode 100644 (file)
index 0000000..fc5efb1
--- /dev/null
@@ -0,0 +1,1186 @@
+/* AS path management routines.
+   Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+#include "vector.h"
+#include "vty.h"
+#include "str.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+\f
+/* Attr. Flags and Attr. Type Code. */
+#define AS_HEADER_SIZE        2         
+
+/* Two octet is used for AS value. */
+#define AS_VALUE_SIZE         sizeof (as_t)
+
+/* AS segment octet length. */
+#define ASSEGMENT_LEN(X)  ((X)->length * AS_VALUE_SIZE + AS_HEADER_SIZE)
+
+/* To fetch and store as segment value. */
+struct assegment
+{
+  u_char type;
+  u_char length;
+  as_t asval[1];
+};
+
+/* Hash for aspath.  This is the top level structure of AS path. */
+struct hash *ashash;
+\f
+static struct aspath *
+aspath_new ()
+{
+  struct aspath *aspath;
+
+  aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
+  memset (aspath, 0, sizeof (struct aspath));
+  return aspath;
+}
+
+/* Free AS path structure. */
+void
+aspath_free (struct aspath *aspath)
+{
+  if (!aspath)
+    return;
+  if (aspath->data)
+    XFREE (MTYPE_AS_SEG, aspath->data);
+  if (aspath->str)
+    XFREE (MTYPE_AS_STR, aspath->str);
+  XFREE (MTYPE_AS_PATH, aspath);
+}
+
+/* Unintern aspath from AS path bucket. */
+void
+aspath_unintern (struct aspath *aspath)
+{
+  struct aspath *ret;
+
+  if (aspath->refcnt)
+    aspath->refcnt--;
+
+  if (aspath->refcnt == 0)
+    {
+      /* This aspath must exist in aspath hash table. */
+      ret = hash_release (ashash, aspath);
+      assert (ret != NULL);
+      aspath_free (aspath);
+    }
+}
+
+/* Return the start or end delimiters for a particular Segment type */
+#define AS_SEG_START 0
+#define AS_SEG_END 1
+static char
+aspath_delimiter_char (u_char type, u_char which)
+{
+  int i;
+  struct
+  {
+    int type;
+    char start;
+    char end;
+  } aspath_delim_char [] =
+    {
+      { AS_SET,             '{', '}' },
+      { AS_SEQUENCE,        ' ', ' ' },
+      { AS_CONFED_SET,      '[', ']' },
+      { AS_CONFED_SEQUENCE, '(', ')' },
+      { 0 }
+    };
+
+  for (i = 0; aspath_delim_char[i].type != 0; i++)
+    {
+      if (aspath_delim_char[i].type == type)
+       {
+         if (which == AS_SEG_START)
+           return aspath_delim_char[i].start;
+         else if (which == AS_SEG_END)
+           return aspath_delim_char[i].end;
+       }
+    }
+  return ' ';
+}
+
+/* Convert aspath structure to string expression. */
+char *
+aspath_make_str_count (struct aspath *as)
+{
+  int space;
+  u_char type;
+  caddr_t pnt;
+  caddr_t end;
+  struct assegment *assegment;
+  int str_size = ASPATH_STR_DEFAULT_LEN;
+  int str_pnt;
+  u_char *str_buf;
+  int count = 0;
+
+  /* Empty aspath. */
+  if (as->length == 0)
+    {
+      str_buf = XMALLOC (MTYPE_AS_STR, 1);
+      str_buf[0] = '\0';
+      as->count = count;
+      return str_buf;
+    }
+
+  /* Set default value. */
+  space = 0;
+  type = AS_SEQUENCE;
+
+  /* Set initial pointer. */
+  pnt = as->data;
+  end = pnt + as->length;
+
+  str_buf = XMALLOC (MTYPE_AS_STR, str_size);
+  str_pnt = 0;
+
+  assegment = (struct assegment *) pnt;
+
+  while (pnt < end)
+    {
+      int i;
+      int estimate_len;
+
+      /* For fetch value. */
+      assegment = (struct assegment *) pnt;
+
+      /* Check AS type validity. */
+      if ((assegment->type != AS_SET) && 
+         (assegment->type != AS_SEQUENCE) &&
+         (assegment->type != AS_CONFED_SET) && 
+         (assegment->type != AS_CONFED_SEQUENCE))
+       {
+         XFREE (MTYPE_AS_STR, str_buf);
+         return NULL;
+       }
+
+      /* Check AS length. */
+      if ((pnt + (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE) > end)
+       {
+         XFREE (MTYPE_AS_STR, str_buf);
+         return NULL;
+       }
+
+      /* Buffer length check. */
+      estimate_len = ((assegment->length * 6) + 4);
+      
+      /* String length check. */
+      while (str_pnt + estimate_len >= str_size)
+       {
+         str_size *= 2;
+         str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
+       }
+
+      /* If assegment type is changed, print previous type's end
+         character. */
+      if (type != AS_SEQUENCE)
+       str_buf[str_pnt++] = aspath_delimiter_char (type, AS_SEG_END);
+      if (space)
+       str_buf[str_pnt++] = ' ';
+
+      if (assegment->type != AS_SEQUENCE)
+       str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_START);
+
+      space = 0;
+
+      /* Increment count - ignoring CONFED SETS/SEQUENCES */
+      if (assegment->type != AS_CONFED_SEQUENCE
+         && assegment->type != AS_CONFED_SET)
+       {
+         if (assegment->type == AS_SEQUENCE)
+           count += assegment->length;
+         else if (assegment->type == AS_SET)
+           count++;
+       }
+
+      for (i = 0; i < assegment->length; i++)
+       {
+         int len;
+
+         if (space)
+           {
+             if (assegment->type == AS_SET
+                 || assegment->type == AS_CONFED_SET)
+               str_buf[str_pnt++] = ',';
+             else
+               str_buf[str_pnt++] = ' ';
+           }
+         else
+           space = 1;
+
+         len = sprintf (str_buf + str_pnt, "%d", ntohs (assegment->asval[i]));
+         str_pnt += len;
+       }
+
+      type = assegment->type;
+      pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
+    }
+
+  if (assegment->type != AS_SEQUENCE)
+    str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_END);
+
+  str_buf[str_pnt] = '\0';
+
+  as->count = count;
+
+  return str_buf;
+}
+
+/* Intern allocated AS path. */
+struct aspath *
+aspath_intern (struct aspath *aspath)
+{
+  struct aspath *find;
+  
+  /* Assert this AS path structure is not interned. */
+  assert (aspath->refcnt == 0);
+
+  /* Check AS path hash. */
+  find = hash_get (ashash, aspath, hash_alloc_intern);
+
+  if (find != aspath)
+      aspath_free (aspath);
+
+  find->refcnt++;
+
+  if (! find->str)
+    find->str = aspath_make_str_count (find);
+
+  return find;
+}
+
+/* Duplicate aspath structure.  Created same aspath structure but
+   reference count and AS path string is cleared. */
+struct aspath *
+aspath_dup (struct aspath *aspath)
+{
+  struct aspath *new;
+
+  new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
+  memset (new, 0, sizeof (struct aspath));
+
+  new->length = aspath->length;
+
+  if (new->length)
+    {
+      new->data = XMALLOC (MTYPE_AS_SEG, aspath->length);
+      memcpy (new->data, aspath->data, aspath->length);
+    }
+  else
+    new->data = NULL;
+
+  /* new->str = aspath_make_str_count (aspath); */
+
+  return new;
+}
+
+void *
+aspath_hash_alloc (struct aspath *arg)
+{
+  struct aspath *aspath;
+
+  /* New aspath strucutre is needed. */
+  aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
+  memset ((void *) aspath, 0, sizeof (struct aspath));
+  aspath->length = arg->length;
+
+  /* In case of IBGP connection aspath's length can be zero. */
+  if (arg->length)
+    {
+      aspath->data = XMALLOC (MTYPE_AS_SEG, arg->length);
+      memcpy (aspath->data, arg->data, arg->length);
+    }
+  else
+    aspath->data = NULL;
+
+  /* Make AS path string. */
+  aspath->str = aspath_make_str_count (aspath);
+
+  /* Malformed AS path value. */
+  if (! aspath->str)
+    {
+      aspath_free (aspath);
+      return NULL;
+    }
+
+  return aspath;
+}
+
+/* AS path parse function.  pnt is a pointer to byte stream and length
+   is length of byte stream.  If there is same AS path in the the AS
+   path hash then return it else make new AS path structure. */
+struct aspath *
+aspath_parse (caddr_t pnt, int length)
+{
+  struct aspath as;
+  struct aspath *find;
+
+  /* If length is odd it's malformed AS path. */
+  if (length % 2)
+    return NULL;
+
+  /* Looking up aspath hash entry. */
+  as.data = pnt;
+  as.length = length;
+
+  /* If already same aspath exist then return it. */
+  find = hash_get (ashash, &as, aspath_hash_alloc);
+  if (! find)
+    return NULL;
+  find->refcnt++;
+
+  return find;
+}
+
+#define min(A,B) ((A) < (B) ? (A) : (B))
+
+#define ASSEGMENT_SIZE(N)  (AS_HEADER_SIZE + ((N) * AS_VALUE_SIZE))
+
+struct aspath *
+aspath_aggregate_segment_copy (struct aspath *aspath, struct assegment *seg,
+                              int i)
+{
+  struct assegment *newseg;
+
+  if (! aspath->data)
+    {
+      aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (i));
+      newseg = (struct assegment *) aspath->data;
+      aspath->length = ASSEGMENT_SIZE (i);
+    }
+  else
+    {
+      aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
+                              aspath->length + ASSEGMENT_SIZE (i));
+      newseg = (struct assegment *) (aspath->data + aspath->length);
+      aspath->length += ASSEGMENT_SIZE (i);
+    }
+
+  newseg->type = seg->type;
+  newseg->length = i;
+  memcpy (newseg->asval, seg->asval, (i * AS_VALUE_SIZE));
+
+  return aspath;
+}
+
+struct assegment *
+aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
+                            as_t as)
+{
+  int i;
+
+  /* If this is first AS set member, create new as-set segment. */
+  if (asset == NULL)
+    {
+      if (! aspath->data)
+       {
+         aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (1));
+         asset = (struct assegment *) aspath->data;
+         aspath->length = ASSEGMENT_SIZE (1);
+       }
+      else
+       {
+         aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
+                                  aspath->length + ASSEGMENT_SIZE (1));
+         asset = (struct assegment *) (aspath->data + aspath->length);
+         aspath->length += ASSEGMENT_SIZE (1);
+       }
+      asset->type = AS_SET;
+      asset->length = 1;
+      asset->asval[0] = as;
+    }
+  else
+    {
+      size_t offset;
+
+      /* Check this AS value already exists or not. */
+      for (i = 0; i < asset->length; i++)
+       if (asset->asval[i] == as)
+         return asset;
+
+      offset = (caddr_t) asset - (caddr_t) aspath->data;
+      aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
+                              aspath->length + AS_VALUE_SIZE);
+
+      asset = (struct assegment *) (aspath->data + offset);
+      aspath->length += AS_VALUE_SIZE;
+      asset->asval[asset->length] = as;
+      asset->length++;
+    }
+
+  return asset;
+}
+
+/* Modify as1 using as2 for aggregation. */
+struct aspath *
+aspath_aggregate (struct aspath *as1, struct aspath *as2)
+{
+  int i;
+  int minlen;
+  int match;
+  int match1;
+  int match2;
+  caddr_t cp1;
+  caddr_t cp2;
+  caddr_t end1;
+  caddr_t end2;
+  struct assegment *seg1;
+  struct assegment *seg2;
+  struct aspath *aspath;
+  struct assegment *asset;
+
+  match = 0;
+  minlen = 0;
+  aspath = NULL;
+  asset = NULL;
+  cp1 = as1->data;
+  end1 = as1->data + as1->length;
+  cp2 = as2->data;
+  end2 = as2->data + as2->length;
+
+  seg1 = (struct assegment *) cp1;
+  seg2 = (struct assegment *) cp2;
+
+  /* First of all check common leading sequence. */
+  while ((cp1 < end1) && (cp2 < end2))
+    {
+      /* Check segment type. */
+      if (seg1->type != seg2->type)
+       break;
+
+      /* Minimum segment length. */
+      minlen = min (seg1->length, seg2->length);
+
+      for (match = 0; match < minlen; match++)
+       if (seg1->asval[match] != seg2->asval[match])
+         break;
+
+      if (match)
+       {
+         if (! aspath)
+           aspath = aspath_new();
+         aspath = aspath_aggregate_segment_copy (aspath, seg1, match);
+       }
+
+      if (match != minlen || match != seg1->length 
+         || seg1->length != seg2->length)
+       break;
+
+      cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
+      cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
+
+      seg1 = (struct assegment *) cp1;
+      seg2 = (struct assegment *) cp2;
+    }
+
+  if (! aspath)
+    aspath = aspath_new();
+
+  /* Make as-set using rest of all information. */
+  match1 = match;
+  while (cp1 < end1)
+    {
+      seg1 = (struct assegment *) cp1;
+
+      for (i = match1; i < seg1->length; i++)
+       asset = aspath_aggregate_as_set_add (aspath, asset, seg1->asval[i]);
+
+      match1 = 0;
+      cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
+    }
+
+  match2 = match;
+  while (cp2 < end2)
+    {
+      seg2 = (struct assegment *) cp2;
+
+      for (i = match2; i < seg2->length; i++)
+       asset = aspath_aggregate_as_set_add (aspath, asset, seg2->asval[i]);
+
+      match2 = 0;
+      cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE);
+    }
+
+  return aspath;
+}
+
+/* When a BGP router receives an UPDATE with an MP_REACH_NLRI
+   attribute, check the leftmost AS number in the AS_PATH attribute is
+   or not the peer's AS number. */ 
+int
+aspath_firstas_check (struct aspath *aspath, as_t asno)
+{
+  caddr_t pnt;
+  struct assegment *assegment;
+
+  if (aspath == NULL)
+    return 0;
+
+  pnt = aspath->data;
+  assegment = (struct assegment *) pnt;
+
+  if (assegment
+      && assegment->type == AS_SEQUENCE
+      && assegment->asval[0] == htons (asno))
+    return 1;
+
+  return 0;
+}
+
+/* AS path loop check.  If aspath contains asno then return 1. */
+int
+aspath_loop_check (struct aspath *aspath, as_t asno)
+{
+  caddr_t pnt;
+  caddr_t end;
+  struct assegment *assegment;
+  int count = 0;
+
+  if (aspath == NULL)
+    return 0;
+
+  pnt = aspath->data;
+  end = aspath->data + aspath->length;
+
+  while (pnt < end)
+    {
+      int i;
+      assegment = (struct assegment *) pnt;
+      
+      for (i = 0; i < assegment->length; i++)
+       if (assegment->asval[i] == htons (asno))
+         count++;
+
+      pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
+    }
+  return count;
+}
+
+/* When all of AS path is private AS return 1.  */
+int
+aspath_private_as_check (struct aspath *aspath)
+{
+  caddr_t pnt;
+  caddr_t end;
+  struct assegment *assegment;
+
+  if (aspath == NULL)
+    return 0;
+
+  if (aspath->length == 0)
+    return 0;
+
+  pnt = aspath->data;
+  end = aspath->data + aspath->length;
+
+  while (pnt < end)
+    {
+      int i;
+      assegment = (struct assegment *) pnt;
+      
+      for (i = 0; i < assegment->length; i++)
+       {
+         if (ntohs (assegment->asval[i]) < BGP_PRIVATE_AS_MIN
+             || ntohs (assegment->asval[i]) > BGP_PRIVATE_AS_MAX)
+           return 0;
+       }
+      pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
+    }
+  return 1;
+}
+
+/* Merge as1 to as2.  as2 should be uninterned aspath. */
+struct aspath *
+aspath_merge (struct aspath *as1, struct aspath *as2)
+{
+  caddr_t data;
+
+  if (! as1 || ! as2)
+    return NULL;
+
+  data = XMALLOC (MTYPE_AS_SEG, as1->length + as2->length);
+  memcpy (data, as1->data, as1->length);
+  memcpy (data + as1->length, as2->data, as2->length);
+
+  XFREE (MTYPE_AS_SEG, as2->data);
+  as2->data = data;
+  as2->length += as1->length;
+  as2->count += as1->count;
+  return as2;
+}
+
+/* Prepend as1 to as2.  as2 should be uninterned aspath. */
+struct aspath *
+aspath_prepend (struct aspath *as1, struct aspath *as2)
+{
+  caddr_t pnt;
+  caddr_t end;
+  struct assegment *seg1 = NULL;
+  struct assegment *seg2 = NULL;
+
+  if (! as1 || ! as2)
+    return NULL;
+
+  seg2 = (struct assegment *) as2->data;
+
+  /* In case of as2 is empty AS. */
+  if (seg2 == NULL)
+    {
+      as2->length = as1->length;
+      as2->data = XMALLOC (MTYPE_AS_SEG, as1->length);
+      as2->count = as1->count;
+      memcpy (as2->data, as1->data, as1->length);
+      return as2;
+    }
+
+  /* assegment points last segment of as1. */
+  pnt = as1->data;
+  end = as1->data + as1->length;
+  while (pnt < end)
+    {
+      seg1 = (struct assegment *) pnt;
+      pnt += (seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE;
+    }
+
+  /* In case of as1 is empty AS. */
+  if (seg1 == NULL)
+    return as2;
+
+  /* Compare last segment type of as1 and first segment type of as2. */
+  if (seg1->type != seg2->type)
+    return aspath_merge (as1, as2);
+
+  if (seg1->type == AS_SEQUENCE)
+    {
+      caddr_t newdata;
+      struct assegment *seg = NULL;
+      
+      newdata = XMALLOC (MTYPE_AS_SEG, 
+                        as1->length + as2->length - AS_HEADER_SIZE);
+      memcpy (newdata, as1->data, as1->length);
+      seg = (struct assegment *) (newdata + ((caddr_t)seg1 - as1->data));
+      seg->length += seg2->length;
+      memcpy (newdata + as1->length, as2->data + AS_HEADER_SIZE,
+             as2->length - AS_HEADER_SIZE);
+
+      XFREE (MTYPE_AS_SEG, as2->data);
+      as2->data = newdata;
+      as2->length += (as1->length - AS_HEADER_SIZE);
+      as2->count += as1->count;
+
+      return as2;
+    }
+  else
+    {
+      /* AS_SET merge code is needed at here. */
+      return aspath_merge (as1, as2);
+    }
+
+  /* Not reached */
+}
+
+/* Add specified AS to the leftmost of aspath. */
+static struct aspath *
+aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
+{
+  struct assegment *assegment;
+
+  assegment = (struct assegment *) aspath->data;
+
+  /* In case of empty aspath. */
+  if (assegment == NULL || assegment->length == 0)
+    {
+      aspath->length = AS_HEADER_SIZE + AS_VALUE_SIZE;
+
+      if (assegment)
+       aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, aspath->length);
+      else
+       aspath->data = XMALLOC (MTYPE_AS_SEG, aspath->length);
+
+      assegment = (struct assegment *) aspath->data;
+      assegment->type = type;
+      assegment->length = 1;
+      assegment->asval[0] = htons (asno);
+
+      return aspath;
+    }
+
+  if (assegment->type == type)
+    {
+      caddr_t newdata;
+      struct assegment *newsegment;
+
+      newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE);
+      newsegment = (struct assegment *) newdata;
+
+      newsegment->type = type;
+      newsegment->length = assegment->length + 1;
+      newsegment->asval[0] = htons (asno);
+
+      memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE,
+             aspath->data + AS_HEADER_SIZE, 
+             aspath->length - AS_HEADER_SIZE);
+
+      XFREE (MTYPE_AS_SEG, aspath->data);
+
+      aspath->data = newdata;
+      aspath->length += AS_VALUE_SIZE;
+    } else {
+      caddr_t newdata;
+      struct assegment *newsegment;
+
+      newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE + AS_HEADER_SIZE);
+      newsegment = (struct assegment *) newdata;
+
+      newsegment->type = type;
+      newsegment->length = 1;
+      newsegment->asval[0] = htons (asno);
+
+      memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE,
+             aspath->data,
+             aspath->length);
+
+      XFREE (MTYPE_AS_SEG, aspath->data);
+
+      aspath->data = newdata;
+      aspath->length += AS_HEADER_SIZE + AS_VALUE_SIZE;
+    }
+
+  return aspath;
+}
+
+/* Add specified AS to the leftmost of aspath. */
+struct aspath *
+aspath_add_seq (struct aspath *aspath, as_t asno)
+{
+  return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
+}
+
+/* Compare leftmost AS value for MED check.  If as1's leftmost AS and
+   as2's leftmost AS is same return 1. */
+int
+aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2)
+{
+  struct assegment *seg1;
+  struct assegment *seg2;
+  as_t as1;
+  as_t as2;
+
+  seg1 = (struct assegment *) aspath1->data;
+  seg2 = (struct assegment *) aspath2->data;
+
+  while (seg1 && seg1->length 
+        && (seg1->type == AS_CONFED_SEQUENCE || seg1->type == AS_CONFED_SET))
+    seg1 = (struct assegment *) ((caddr_t) seg1 + ASSEGMENT_LEN (seg1));
+  while (seg2 && seg2->length 
+        && (seg2->type == AS_CONFED_SEQUENCE || seg2->type == AS_CONFED_SET))
+    seg2 = (struct assegment *) ((caddr_t) seg2 + ASSEGMENT_LEN (seg2));
+
+  /* Check as1's */
+  if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_SEQUENCE)
+    return 0;
+  as1 = seg1->asval[0];
+
+  if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_SEQUENCE)
+    return 0;
+  as2 = seg2->asval[0];
+
+  if (as1 == as2)
+    return 1;
+
+  return 0;
+}
+
+/* Compare leftmost AS value for MED check.  If as1's leftmost AS and
+   as2's leftmost AS is same return 1. (confederation as-path
+   only).  */
+int
+aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2)
+{
+  struct assegment *seg1;
+  struct assegment *seg2;
+
+  as_t as1;
+  as_t as2;
+
+  if (aspath1->count || aspath2->count) 
+    return 0;
+
+  seg1 = (struct assegment *) aspath1->data;
+  seg2 = (struct assegment *) aspath2->data;
+
+  /* Check as1's */
+  if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_CONFED_SEQUENCE)
+    return 0;
+  as1 = seg1->asval[0];
+
+  /* Check as2's */
+  if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_CONFED_SEQUENCE)
+    return 0;
+  as2 = seg2->asval[0];
+
+  if (as1 == as2)
+    return 1;
+
+  return 0;
+}
+
+/* Delete first sequential AS_CONFED_SEQUENCE from aspath.  */
+struct aspath *
+aspath_delete_confed_seq (struct aspath *aspath)
+{
+  int seglen;
+  struct assegment *assegment;
+
+  if (! aspath)
+    return aspath;
+
+  assegment = (struct assegment *) aspath->data;
+
+  while (assegment)
+    {
+      if (assegment->type != AS_CONFED_SEQUENCE)
+       return aspath;
+
+      seglen = ASSEGMENT_LEN (assegment);
+
+      if (seglen == aspath->length)
+       {
+         XFREE (MTYPE_AS_SEG, aspath->data);
+         aspath->data = NULL;
+         aspath->length = 0;
+       }
+      else
+       {
+         memcpy (aspath->data, aspath->data + seglen,
+                 aspath->length - seglen);
+         aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data,
+                                  aspath->length - seglen);
+         aspath->length -= seglen;
+       }
+
+      assegment = (struct assegment *) aspath->data;
+    }
+  return aspath;
+}
+
+/* Add new AS number to the leftmost part of the aspath as
+   AS_CONFED_SEQUENCE.  */
+struct aspath*
+aspath_add_confed_seq (struct aspath *aspath, as_t asno)
+{
+  return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
+}
+
+/* Add new as value to as path structure. */
+void
+aspath_as_add (struct aspath *as, as_t asno)
+{
+  caddr_t pnt;
+  caddr_t end;
+  struct assegment *assegment;
+
+  /* Increase as->data for new as value. */
+  as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2);
+  as->length += 2;
+
+  pnt = as->data;
+  end = as->data + as->length;
+  assegment = (struct assegment *) pnt;
+
+  /* Last segment search procedure. */
+  while (pnt + 2 < end)
+    {
+      assegment = (struct assegment *) pnt;
+
+      /* We add 2 for segment_type and segment_length and segment
+         value assegment->length * 2. */
+      pnt += (AS_HEADER_SIZE + (assegment->length * AS_VALUE_SIZE));
+    }
+
+  assegment->asval[assegment->length] = htons (asno);
+  assegment->length++;
+}
+
+/* Add new as segment to the as path. */
+void
+aspath_segment_add (struct aspath *as, int type)
+{
+  struct assegment *assegment;
+
+  if (as->data == NULL)
+    {
+      as->data = XMALLOC (MTYPE_AS_SEG, 2);
+      assegment = (struct assegment *) as->data;
+      as->length = 2;
+    }
+  else
+    {
+      as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2);
+      assegment = (struct assegment *) (as->data + as->length);
+      as->length += 2;
+    }
+
+  assegment->type = type;
+  assegment->length = 0;
+}
+
+struct aspath *
+aspath_empty ()
+{
+  return aspath_parse (NULL, 0);
+}
+
+struct aspath *
+aspath_empty_get ()
+{
+  struct aspath *aspath;
+
+  aspath = aspath_new ();
+  aspath->str = aspath_make_str_count (aspath);
+  return aspath;
+}
+
+unsigned long
+aspath_count ()
+{
+  return ashash->count;
+}     
+\f
+/* 
+   Theoretically, one as path can have:
+
+   One BGP packet size should be less than 4096.
+   One BGP attribute size should be less than 4096 - BGP header size.
+   One BGP aspath size should be less than 4096 - BGP header size -
+       BGP mandantry attribute size.
+*/
+
+/* AS path string lexical token enum. */
+enum as_token
+{
+  as_token_asval,
+  as_token_set_start,
+  as_token_set_end,
+  as_token_confed_start,
+  as_token_confed_end,
+  as_token_unknown
+};
+
+/* Return next token and point for string parse. */
+char *
+aspath_gettoken (char *buf, enum as_token *token, u_short *asno)
+{
+  char *p = buf;
+
+  /* Skip space. */
+  while (isspace ((int) *p))
+    p++;
+
+  /* Check the end of the string and type specify characters
+     (e.g. {}()). */
+  switch (*p)
+    {
+    case '\0':
+      return NULL;
+      break;
+    case '{':
+      *token = as_token_set_start;
+      p++;
+      return p;
+      break;
+    case '}':
+      *token = as_token_set_end;
+      p++;
+      return p;
+      break;
+    case '(':
+      *token = as_token_confed_start;
+      p++;
+      return p;
+      break;
+    case ')':
+      *token = as_token_confed_end;
+      p++;
+      return p;
+      break;
+    }
+
+  /* Check actual AS value. */
+  if (isdigit ((int) *p)) 
+    {
+      u_short asval;
+
+      *token = as_token_asval;
+      asval = (*p - '0');
+      p++;
+      while (isdigit ((int) *p)) 
+       {
+         asval *= 10;
+         asval += (*p - '0');
+         p++;
+       }
+      *asno = asval;
+      return p;
+    }
+  
+  /* There is no match then return unknown token. */
+  *token = as_token_unknown;
+  return  p++;
+}
+
+struct aspath *
+aspath_str2aspath (char *str)
+{
+  enum as_token token;
+  u_short as_type;
+  u_short asno;
+  struct aspath *aspath;
+  int needtype;
+
+  aspath = aspath_new ();
+
+  /* We start default type as AS_SEQUENCE. */
+  as_type = AS_SEQUENCE;
+  needtype = 1;
+
+  while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
+    {
+      switch (token)
+       {
+       case as_token_asval:
+         if (needtype)
+           {
+             aspath_segment_add (aspath, as_type);
+             needtype = 0;
+           }
+         aspath_as_add (aspath, asno);
+         break;
+       case as_token_set_start:
+         as_type = AS_SET;
+         aspath_segment_add (aspath, as_type);
+         needtype = 0;
+         break;
+       case as_token_set_end:
+         as_type = AS_SEQUENCE;
+         needtype = 1;
+         break;
+       case as_token_confed_start:
+         as_type = AS_CONFED_SEQUENCE;
+         aspath_segment_add (aspath, as_type);
+         needtype = 0;
+         break;
+       case as_token_confed_end:
+         as_type = AS_SEQUENCE;
+         needtype = 1;
+         break;
+       case as_token_unknown:
+       default:
+         return NULL;
+         break;
+       }
+    }
+
+  aspath->str = aspath_make_str_count (aspath);
+
+  return aspath;
+}
+\f
+/* Make hash value by raw aspath data. */
+unsigned int
+aspath_key_make (struct aspath *aspath)
+{
+  unsigned int key = 0;
+  int length;
+  unsigned short *pnt;
+
+  length = aspath->length / 2;
+  pnt = (unsigned short *) aspath->data;
+
+  while (length)
+    {
+      key += *pnt++;
+      length--;
+    }
+
+  return key;
+}
+
+/* If two aspath have same value then return 1 else return 0 */
+int
+aspath_cmp (struct aspath *as1, struct aspath *as2)
+{
+  if (as1->length == as2->length 
+      && !memcmp (as1->data, as2->data, as1->length))
+    return 1;
+  else
+    return 0;
+}
+
+/* AS path hash initialize. */
+void
+aspath_init ()
+{
+  ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
+}
+\f
+/* return and as path value */
+const char *
+aspath_print (struct aspath *as)
+{
+  return as->str;
+}
+
+/* Printing functions */
+void
+aspath_print_vty (struct vty *vty, struct aspath *as)
+{
+  vty_out (vty, "%s", as->str);
+}
+
+void
+aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+{
+  struct aspath *as;
+
+  as = (struct aspath *) backet->data;
+
+  vty_out (vty, "[%p:%d] (%ld) ", backet, backet->key, as->refcnt);
+  vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
+}
+
+/* Print all aspath and hash information.  This function is used from
+   `show ip bgp paths' command. */
+void
+aspath_print_all_vty (struct vty *vty)
+{
+  hash_iterate (ashash, 
+               (void (*) (struct hash_backet *, void *))
+               aspath_show_all_iterator,
+               vty);
+}
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
new file mode 100644 (file)
index 0000000..0295faf
--- /dev/null
@@ -0,0 +1,77 @@
+/* AS path related definitions.
+   Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* AS path segment type.  */
+#define AS_SET                       1
+#define AS_SEQUENCE                  2
+#define AS_CONFED_SEQUENCE           3
+#define AS_CONFED_SET                4
+
+/* Private AS range defined in RFC2270.  */
+#define BGP_PRIVATE_AS_MIN       64512
+#define BGP_PRIVATE_AS_MAX       65535
+
+/* AS path may be include some AsSegments.  */
+struct aspath 
+{
+  /* Reference count to this aspath.  */
+  unsigned long refcnt;
+
+  /* Rawdata length.  */
+  int length;
+
+  /* AS count.  */
+  int count;
+
+  /* Rawdata.  */
+  caddr_t data;
+
+  /* String expression of AS path.  This string is used by vty output
+     and AS path regular expression match.  */
+  char *str;
+};
+
+#define ASPATH_STR_DEFAULT_LEN 32
+
+/* Prototypes. */
+void aspath_init ();
+struct aspath *aspath_parse ();
+struct aspath *aspath_dup (struct aspath *);
+struct aspath *aspath_aggregate (struct aspath *, struct aspath *);
+struct aspath *aspath_prepend (struct aspath *, struct aspath *);
+struct aspath *aspath_add_seq (struct aspath *, as_t);
+struct aspath *aspath_add_confed_seq (struct aspath *, as_t);
+int aspath_cmp_left (struct aspath *, struct aspath *);
+int aspath_cmp_left_confed (struct aspath *, struct aspath *);
+struct aspath *aspath_delete_confed_seq (struct aspath *);
+struct aspath *aspath_empty ();
+struct aspath *aspath_empty_get ();
+struct aspath *aspath_str2aspath (char *);
+void aspath_free (struct aspath *);
+struct aspath *aspath_intern (struct aspath *);
+void aspath_unintern (struct aspath *);
+const char *aspath_print (struct aspath *);
+void aspath_print_vty (struct vty *, struct aspath *);
+void aspath_print_all_vty (struct vty *);
+unsigned int aspath_key_make (struct aspath *);
+int aspath_loop_check (struct aspath *, as_t);
+int aspath_private_as_check (struct aspath *);
+int aspath_firstas_check (struct aspath *, as_t);
+unsigned long aspath_count ();
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
new file mode 100644 (file)
index 0000000..480bb91
--- /dev/null
@@ -0,0 +1,1838 @@
+/* BGP attributes management routines.
+   Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "memory.h"
+#include "vector.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "hash.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_ecommunity.h"
+\f
+/* Attribute strings for logging. */
+struct message attr_str [] = 
+{
+  { BGP_ATTR_ORIGIN,           "ORIGIN" }, 
+  { BGP_ATTR_AS_PATH,          "AS_PATH" }, 
+  { BGP_ATTR_NEXT_HOP,         "NEXT_HOP" }, 
+  { BGP_ATTR_MULTI_EXIT_DISC,  "MULTI_EXIT_DISC" }, 
+  { BGP_ATTR_LOCAL_PREF,       "LOCAL_PREF" }, 
+  { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, 
+  { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" }, 
+  { BGP_ATTR_COMMUNITIES,      "COMMUNITY" }, 
+  { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },
+  { BGP_ATTR_CLUSTER_LIST,     "CLUSTERLIST" }, 
+  { BGP_ATTR_DPA,              "DPA" },
+  { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,
+  { BGP_ATTR_RCID_PATH,        "RCID_PATH" },
+  { BGP_ATTR_MP_REACH_NLRI,    "MP_REACH_NLRI" },
+  { BGP_ATTR_MP_UNREACH_NLRI,  "MP_UNREACH_NLRI" },
+  { 0, NULL }
+};
+\f
+struct hash *cluster_hash;
+
+void *
+cluster_hash_alloc (struct cluster_list *val)
+{
+  struct cluster_list *cluster;
+
+  cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
+  cluster->length = val->length;
+
+  if (cluster->length)
+    {
+      cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
+      memcpy (cluster->list, val->list, val->length);
+    }
+  else
+    cluster->list = NULL;
+
+  cluster->refcnt = 0;
+
+  return cluster;
+}
+
+/* Cluster list related functions. */
+struct cluster_list *
+cluster_parse (caddr_t pnt, int length)
+{
+  struct cluster_list tmp;
+  struct cluster_list *cluster;
+
+  tmp.length = length;
+  tmp.list = (struct in_addr *) pnt;
+
+  cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
+  cluster->refcnt++;
+  return cluster;
+}
+
+int
+cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
+{
+  int i;
+    
+  for (i = 0; i < cluster->length / 4; i++)
+    if (cluster->list[i].s_addr == originator.s_addr)
+      return 1;
+  return 0;
+}
+
+unsigned int
+cluster_hash_key_make (struct cluster_list *cluster)
+{
+  unsigned int key = 0;
+  int length;
+  caddr_t pnt;
+
+  length = cluster->length;
+  pnt = (caddr_t) cluster->list;
+  
+  while (length)
+    key += pnt[--length];
+
+  return key;
+}
+
+int
+cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2)
+{
+  if (cluster1->length == cluster2->length &&
+      memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
+    return 1;
+  return 0;
+}
+
+void
+cluster_free (struct cluster_list *cluster)
+{
+  if (cluster->list)
+    XFREE (MTYPE_CLUSTER_VAL, cluster->list);
+  XFREE (MTYPE_CLUSTER, cluster);
+}
+
+struct cluster_list *
+cluster_dup (struct cluster_list *cluster)
+{
+  struct cluster_list *new;
+
+  new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
+  memset (new, 0, sizeof (struct cluster_list));
+  new->length = cluster->length;
+
+  if (cluster->length)
+    {
+      new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
+      memcpy (new->list, cluster->list, cluster->length);
+    }
+  else
+    new->list = NULL;
+  
+  return new;
+}
+
+struct cluster_list *
+cluster_intern (struct cluster_list *cluster)
+{
+  struct cluster_list *find;
+
+  find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
+  find->refcnt++;
+
+  return find;
+}
+
+void
+cluster_unintern (struct cluster_list *cluster)
+{
+  struct cluster_list *ret;
+
+  if (cluster->refcnt)
+    cluster->refcnt--;
+
+  if (cluster->refcnt == 0)
+    {
+      ret = hash_release (cluster_hash, cluster);
+      cluster_free (cluster);
+    }
+}
+
+void
+cluster_init ()
+{
+  cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
+}
+\f
+/* Unknown transit attribute. */
+struct hash *transit_hash;
+
+void
+transit_free (struct transit *transit)
+{
+  if (transit->val)
+    XFREE (MTYPE_TRANSIT_VAL, transit->val);
+  XFREE (MTYPE_TRANSIT, transit);
+}
+
+void *
+transit_hash_alloc (struct transit *transit)
+{
+  /* Transit structure is already allocated.  */
+  return transit;
+}
+
+struct transit *
+transit_intern (struct transit *transit)
+{
+  struct transit *find;
+
+  find = hash_get (transit_hash, transit, transit_hash_alloc);
+  if (find != transit)
+    transit_free (transit);
+  find->refcnt++;
+
+  return find;
+}
+
+void
+transit_unintern (struct transit *transit)
+{
+  struct transit *ret;
+
+  if (transit->refcnt)
+    transit->refcnt--;
+
+  if (transit->refcnt == 0)
+    {
+      ret = hash_release (transit_hash, transit);
+      transit_free (transit);
+    }
+}
+
+unsigned int
+transit_hash_key_make (struct transit *transit)
+{
+  unsigned int key = 0;
+  int length;
+  caddr_t pnt;
+
+  length = transit->length;
+  pnt = (caddr_t) transit->val;
+  
+  while (length)
+    key += pnt[--length];
+
+  return key;
+}
+
+int
+transit_hash_cmp (struct transit *transit1, struct transit *transit2)
+{
+  if (transit1->length == transit2->length &&
+      memcmp (transit1->val, transit2->val, transit1->length) == 0)
+    return 1;
+  return 0;
+}
+
+void
+transit_init ()
+{
+  transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
+}
+\f
+/* Attribute hash routines. */
+
+struct hash *attrhash;
+
+unsigned int
+attrhash_key_make (struct attr *attr)
+{
+  unsigned int key = 0;
+
+  key += attr->origin;
+  key += attr->nexthop.s_addr;
+  key += attr->med;
+  key += attr->local_pref;
+  key += attr->aggregator_as;
+  key += attr->aggregator_addr.s_addr;
+  key += attr->weight;
+
+  key += attr->mp_nexthop_global_in.s_addr;
+  if (attr->aspath)
+    key += aspath_key_make (attr->aspath);
+  if (attr->community)
+    key += community_hash_make (attr->community);
+  if (attr->ecommunity)
+    key += ecommunity_hash_make (attr->ecommunity);
+  if (attr->cluster)
+    key += cluster_hash_key_make (attr->cluster);
+  if (attr->transit)
+    key += transit_hash_key_make (attr->transit);
+
+#ifdef HAVE_IPV6
+ {
+   int i;
+   
+   key += attr->mp_nexthop_len;
+   for (i = 0; i < 16; i++)
+     key += attr->mp_nexthop_global.s6_addr[i];
+   for (i = 0; i < 16; i++)
+     key += attr->mp_nexthop_local.s6_addr[i];
+ }
+#endif /* HAVE_IPV6 */
+
+  return key;
+}
+
+int
+attrhash_cmp (struct attr *attr1, struct attr *attr2)
+{
+  if (attr1->flag == attr2->flag
+      && attr1->origin == attr2->origin
+      && attr1->nexthop.s_addr == attr2->nexthop.s_addr
+      && attr1->med == attr2->med
+      && attr1->local_pref == attr2->local_pref
+      && attr1->aggregator_as == attr2->aggregator_as
+      && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
+      && attr1->weight == attr2->weight
+#ifdef HAVE_IPV6
+      && attr1->mp_nexthop_len == attr2->mp_nexthop_len
+      && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
+      && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
+#endif /* HAVE_IPV6 */
+      && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
+      && attr1->aspath == attr2->aspath
+      && attr1->community == attr2->community
+      && attr1->ecommunity == attr2->ecommunity
+      && attr1->cluster == attr2->cluster
+      && attr1->transit == attr2->transit)
+    return 1;
+  else
+    return 0;
+}
+
+void
+attrhash_init ()
+{
+  attrhash = hash_create (attrhash_key_make, attrhash_cmp);
+}
+
+void
+attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+{
+  struct attr *attr = backet->data;
+
+  vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, 
+          inet_ntoa (attr->nexthop), VTY_NEWLINE);
+}
+
+void
+attr_show_all (struct vty *vty)
+{
+  hash_iterate (attrhash, 
+               (void (*)(struct hash_backet *, void *))
+               attr_show_all_iterator,
+               vty);
+}
+
+void *
+bgp_attr_hash_alloc (struct attr *val)
+{
+  struct attr *attr;
+
+  attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
+  *attr = *val;
+  attr->refcnt = 0;
+  return attr;
+}
+
+/* Internet argument attribute. */
+struct attr *
+bgp_attr_intern (struct attr *attr)
+{
+  struct attr *find;
+
+  /* Intern referenced strucutre. */
+  if (attr->aspath)
+    {
+      if (! attr->aspath->refcnt)
+       attr->aspath = aspath_intern (attr->aspath);
+      else
+       attr->aspath->refcnt++;
+    }
+  if (attr->community)
+    {
+      if (! attr->community->refcnt)
+       attr->community = community_intern (attr->community);
+      else
+       attr->community->refcnt++;
+    }
+  if (attr->ecommunity)
+    {
+      if (! attr->ecommunity->refcnt)
+       attr->ecommunity = ecommunity_intern (attr->ecommunity);
+      else
+       attr->ecommunity->refcnt++;
+    }
+  if (attr->cluster)
+    {
+      if (! attr->cluster->refcnt)
+       attr->cluster = cluster_intern (attr->cluster);
+      else
+       attr->cluster->refcnt++;
+    }
+  if (attr->transit)
+    {
+      if (! attr->transit->refcnt)
+       attr->transit = transit_intern (attr->transit);
+      else
+       attr->transit->refcnt++;
+    }
+
+  find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
+  find->refcnt++;
+
+  return find;
+}
+
+/* Make network statement's attribute. */
+struct attr *
+bgp_attr_default_set (struct attr *attr, u_char origin)
+{
+  memset (attr, 0, sizeof (struct attr));
+
+  attr->origin = origin;
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
+  attr->aspath = aspath_empty ();
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+  attr->weight = 32768;
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
+#ifdef HAVE_IPV6
+  attr->mp_nexthop_len = 16;
+#endif
+  return attr;
+}
+
+/* Make network statement's attribute. */
+struct attr *
+bgp_attr_default_intern (u_char origin)
+{
+  struct attr attr;
+  struct attr *new;
+
+  memset (&attr, 0, sizeof (struct attr));
+
+  attr.origin = origin;
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
+  attr.aspath = aspath_empty ();
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+  attr.weight = 32768;
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
+#ifdef HAVE_IPV6
+  attr.mp_nexthop_len = 16;
+#endif
+
+  new = bgp_attr_intern (&attr);
+  aspath_unintern (new->aspath);
+  return new;
+}
+
+struct attr *
+bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
+                          struct aspath *aspath,
+                          struct community *community, int as_set)
+{
+  struct attr attr;
+  struct attr *new;
+
+  memset (&attr, 0, sizeof (struct attr));
+
+  /* Origin attribute. */
+  attr.origin = origin;
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
+
+  /* AS path attribute. */
+  if (aspath)
+    attr.aspath = aspath_intern (aspath);
+  else
+    attr.aspath = aspath_empty ();
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+
+  /* Next hop attribute.  */
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
+
+  if (community)
+    {
+      attr.community = community;
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+    }
+
+  attr.weight = 32768;
+#ifdef HAVE_IPV6
+  attr.mp_nexthop_len = 16;
+#endif
+  if (! as_set)
+    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
+  if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
+    attr.aggregator_as = bgp->confed_id;
+  else
+    attr.aggregator_as = bgp->as;
+  attr.aggregator_addr = bgp->router_id;
+
+  new = bgp_attr_intern (&attr);
+  aspath_unintern (new->aspath);
+  return new;
+}
+
+/* Free bgp attribute and aspath. */
+void
+bgp_attr_unintern (struct attr *attr)
+{
+  struct attr *ret;
+  struct aspath *aspath;
+  struct community *community;
+  struct ecommunity *ecommunity;
+  struct cluster_list *cluster;
+  struct transit *transit;
+
+  /* Decrement attribute reference. */
+  attr->refcnt--;
+  aspath = attr->aspath;
+  community = attr->community;
+  ecommunity = attr->ecommunity;
+  cluster = attr->cluster;
+  transit = attr->transit;
+
+  /* If reference becomes zero then free attribute object. */
+  if (attr->refcnt == 0)
+    {    
+      ret = hash_release (attrhash, attr);
+      assert (ret != NULL);
+      XFREE (MTYPE_ATTR, attr);
+    }
+
+  /* aspath refcount shoud be decrement. */
+  if (aspath)
+    aspath_unintern (aspath);
+  if (community)
+    community_unintern (community);
+  if (ecommunity)
+    ecommunity_unintern (ecommunity);
+  if (cluster)
+    cluster_unintern (cluster);
+  if (transit)
+    transit_unintern (transit);
+}
+
+void
+bgp_attr_flush (struct attr *attr)
+{
+  if (attr->aspath && ! attr->aspath->refcnt)
+    aspath_free (attr->aspath);
+  if (attr->community && ! attr->community->refcnt)
+    community_free (attr->community);
+  if (attr->ecommunity && ! attr->ecommunity->refcnt)
+    ecommunity_free (attr->ecommunity);
+  if (attr->cluster && ! attr->cluster->refcnt)
+    cluster_free (attr->cluster);
+  if (attr->transit && ! attr->transit->refcnt)
+    transit_free (attr->transit);
+}
+
+/* Get origin attribute of the update message. */
+int
+bgp_attr_origin (struct peer *peer, bgp_size_t length, 
+                struct attr *attr, u_char flag, u_char *startp)
+{
+  bgp_size_t total;
+
+  /* total is entire attribute length include Attribute Flags (1),
+     Attribute Type code (1) and Attribute length (1 or 2).  */
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+  /* If any recognized attribute has Attribute Flags that conflict
+     with the Attribute Type Code, then the Error Subcode is set to
+     Attribute Flags Error.  The Data field contains the erroneous
+     attribute (type, length and value). */
+  if (flag != BGP_ATTR_FLAG_TRANS)
+    {
+      zlog (peer->log, LOG_ERR, 
+           "Origin attribute flag isn't transitive %d", flag);
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                                startp, total);
+      return -1;
+    }
+
+  /* If any recognized attribute has Attribute Length that conflicts
+     with the expected length (based on the attribute type code), then
+     the Error Subcode is set to Attribute Length Error.  The Data
+     field contains the erroneous attribute (type, length and
+     value). */
+  if (length != 1)
+    {
+      zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
+           length);
+      bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                startp, total);
+      return -1;
+    }
+
+  /* Fetch origin attribute. */
+  attr->origin = stream_getc (BGP_INPUT (peer));
+
+  /* If the ORIGIN attribute has an undefined value, then the Error
+     Subcode is set to Invalid Origin Attribute.  The Data field
+     contains the unrecognized attribute (type, length and value). */
+  if ((attr->origin != BGP_ORIGIN_IGP)
+      && (attr->origin != BGP_ORIGIN_EGP)
+      && (attr->origin != BGP_ORIGIN_INCOMPLETE))
+    {
+      zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
+             attr->origin);
+
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+                                startp, total);
+      return -1;
+    }
+
+  /* Set oring attribute flag. */
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
+
+  return 0;
+}
+
+/* Parse AS path information.  This function is wrapper of
+   aspath_parse. */
+int
+bgp_attr_aspath (struct peer *peer, bgp_size_t length, 
+                struct attr *attr, u_char flag, u_char *startp)
+{
+  struct bgp *bgp;
+  struct aspath *aspath;
+  bgp_size_t total;
+
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+  /* Flag check. */
+  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
+      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
+    {
+      zlog (peer->log, LOG_ERR, 
+           "Origin attribute flag isn't transitive %d", flag);
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                                startp, total);
+      return -1;
+    }
+
+  /* In case of IBGP, length will be zero. */
+  attr->aspath = aspath_parse (stream_pnt (peer->ibuf), length);
+  if (! attr->aspath)
+    {
+      zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
+      bgp_notify_send (peer, 
+                      BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+      return -1;
+    }
+
+  bgp = peer->bgp;
+    
+  /* First AS check for EBGP. */
+  if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
+    {
+      if (peer_sort (peer) == BGP_PEER_EBGP 
+         && ! aspath_firstas_check (attr->aspath, peer->as))
+       {
+         zlog (peer->log, LOG_ERR,
+               "%s incorrect first AS (must be %d)", peer->host, peer->as);
+         bgp_notify_send (peer,
+                          BGP_NOTIFY_UPDATE_ERR,
+                          BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+         return -1;
+       }
+    }
+
+  /* local-as prepend */
+  if (peer->change_local_as &&
+      ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
+    {
+      aspath = aspath_dup (attr->aspath);
+      aspath = aspath_add_seq (aspath, peer->change_local_as);
+      aspath_unintern (attr->aspath);
+      attr->aspath = aspath_intern (aspath);
+    }
+
+  /* Forward pointer. */
+  stream_forward (peer->ibuf, length);
+
+  /* Set aspath attribute flag. */
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+
+  return 0;
+}
+
+/* Nexthop attribute. */
+int
+bgp_attr_nexthop (struct peer *peer, bgp_size_t length, 
+                 struct attr *attr, u_char flag, u_char *startp)
+{
+  bgp_size_t total;
+
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+  /* Flag check. */
+  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
+      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
+    {
+      zlog (peer->log, LOG_ERR, 
+           "Origin attribute flag isn't transitive %d", flag);
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                                startp, total);
+      return -1;
+    }
+
+  /* Check nexthop attribute length. */
+  if (length != 4)
+    {
+      zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
+             length);
+
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                startp, total);
+      return -1;
+    }
+
+  attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
+
+  return 0;
+}
+
+/* MED atrribute. */
+int
+bgp_attr_med (struct peer *peer, bgp_size_t length, 
+             struct attr *attr, u_char flag, u_char *startp)
+{
+  bgp_size_t total;
+
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+  /* Length check. */
+  if (length != 4)
+    {
+      zlog (peer->log, LOG_ERR, 
+           "MED attribute length isn't four [%d]", length);
+      
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                startp, total);
+      return -1;
+    }
+
+  attr->med = stream_getl (peer->ibuf);
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+
+  return 0;
+}
+
+/* Local preference attribute. */
+int
+bgp_attr_local_pref (struct peer *peer, bgp_size_t length, 
+                    struct attr *attr, u_char flag)
+{
+  /* If it is contained in an UPDATE message that is received from an
+     external peer, then this attribute MUST be ignored by the
+     receiving speaker. */
+  if (peer_sort (peer) == BGP_PEER_EBGP)
+    {
+      stream_forward (peer->ibuf, length);
+      return 0;
+    }
+
+  if (length == 4) 
+    attr->local_pref = stream_getl (peer->ibuf);
+  else 
+    attr->local_pref = 0;
+
+  /* Set atomic aggregate flag. */
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
+
+  return 0;
+}
+
+/* Atomic aggregate. */
+int
+bgp_attr_atomic (struct peer *peer, bgp_size_t length, 
+                struct attr *attr, u_char flag)
+{
+  if (length != 0)
+    {
+      zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
+
+      bgp_notify_send (peer, 
+                      BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+      return -1;
+    }
+
+  /* Set atomic aggregate flag. */
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+
+  return 0;
+}
+
+/* Aggregator attribute */
+int
+bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
+                    struct attr *attr, u_char flag)
+{
+  if (length != 6)
+    {
+      zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
+
+      bgp_notify_send (peer,
+                      BGP_NOTIFY_UPDATE_ERR,
+                      BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+      return -1;
+    }
+  attr->aggregator_as = stream_getw (peer->ibuf);
+  attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
+
+  /* Set atomic aggregate flag. */
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
+
+  return 0;
+}
+
+/* Community attribute. */
+int
+bgp_attr_community (struct peer *peer, bgp_size_t length, 
+                   struct attr *attr, u_char flag)
+{
+  if (length == 0)
+    attr->community = NULL;
+  else
+    {
+      attr->community = community_parse (stream_pnt (peer->ibuf), length);
+      stream_forward (peer->ibuf, length);
+    }
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+
+  return 0;
+}
+
+/* Originator ID attribute. */
+int
+bgp_attr_originator_id (struct peer *peer, bgp_size_t length, 
+                       struct attr *attr, u_char flag)
+{
+  if (length != 4)
+    {
+      zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
+
+      bgp_notify_send (peer, 
+                      BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+      return -1;
+    }
+
+  attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
+
+  return 0;
+}
+
+/* Cluster list attribute. */
+int
+bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, 
+                      struct attr *attr, u_char flag)
+{
+  /* Check length. */
+  if (length % 4)
+    {
+      zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
+
+      bgp_notify_send (peer, 
+                      BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+      return -1;
+    }
+
+  attr->cluster = cluster_parse (stream_pnt (peer->ibuf), length);
+
+  stream_forward (peer->ibuf, length);;
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
+
+  return 0;
+}
+
+/* Multiprotocol reachability information parse. */
+int
+bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
+                   struct bgp_nlri *mp_update)
+{
+  u_int16_t afi;
+  u_char safi;
+  u_char snpa_num;
+  u_char snpa_len;
+  u_char *lim;
+  bgp_size_t nlri_len;
+  int ret;
+  struct stream *s;
+  
+  /* Set end of packet. */
+  s = peer->ibuf;
+  lim = stream_pnt (s) + length;
+
+  /* Load AFI, SAFI. */
+  afi = stream_getw (s);
+  safi = stream_getc (s);
+
+  /* Get nexthop length. */
+  attr->mp_nexthop_len = stream_getc (s);
+
+  /* Nexthop length check. */
+  switch (attr->mp_nexthop_len)
+    {
+    case 4:
+      stream_get (&attr->mp_nexthop_global_in, s, 4);
+      break;
+    case 12:
+      {
+       u_int32_t rd_high;
+       u_int32_t rd_low;
+
+       rd_high = stream_getl (s);
+       rd_low = stream_getl (s);
+       stream_get (&attr->mp_nexthop_global_in, s, 4);
+      }
+      break;
+#ifdef HAVE_IPV6
+    case 16:
+      stream_get (&attr->mp_nexthop_global, s, 16);
+      break;
+    case 32:
+      stream_get (&attr->mp_nexthop_global, s, 16);
+      stream_get (&attr->mp_nexthop_local, s, 16);
+      if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
+       {
+         char buf1[INET6_ADDRSTRLEN];
+         char buf2[INET6_ADDRSTRLEN];
+
+         if (BGP_DEBUG (update, UPDATE_IN))
+           zlog_warn ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
+                      inet_ntop (AF_INET6, &attr->mp_nexthop_global,
+                                 buf1, INET6_ADDRSTRLEN),
+                      inet_ntop (AF_INET6, &attr->mp_nexthop_local,
+                                 buf2, INET6_ADDRSTRLEN));
+
+         attr->mp_nexthop_len = 16;
+       }
+      break;
+#endif /* HAVE_IPV6 */
+    default:
+      zlog_info ("Wrong multiprotocol next hop length: %d", 
+                attr->mp_nexthop_len);
+      return -1;
+      break;
+    }
+
+  snpa_num = stream_getc (s);
+
+  while (snpa_num--)
+    {
+      snpa_len = stream_getc (s);
+      stream_forward (s, (snpa_len + 1) >> 1);
+    }
+  
+  /* If peer is based on old draft-00. I read NLRI length from the
+     packet. */
+  if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+    {
+      bgp_size_t nlri_total_len;
+      nlri_total_len = stream_getw (s);
+    }
+
+  nlri_len = lim - stream_pnt (s);
+  if (safi != BGP_SAFI_VPNV4)
+    {
+      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
+      if (ret < 0)
+       return -1;
+    }
+
+  mp_update->afi = afi;
+  mp_update->safi = safi;
+  mp_update->nlri = stream_pnt (s);
+  mp_update->length = nlri_len;
+
+  stream_forward (s, nlri_len);
+
+  return 0;
+}
+
+/* Multiprotocol unreachable parse */
+int
+bgp_mp_unreach_parse (struct peer *peer, int length, 
+                     struct bgp_nlri *mp_withdraw)
+{
+  struct stream *s;
+  u_int16_t afi;
+  u_char safi;
+  u_char *lim;
+  u_int16_t withdraw_len;
+  int ret;
+
+  s = peer->ibuf;
+  lim = stream_pnt (s) + length;
+
+  afi = stream_getw (s);
+  safi = stream_getc (s);
+
+  withdraw_len = lim - stream_pnt (s);
+
+  if (safi != BGP_SAFI_VPNV4)
+    {
+      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
+      if (ret < 0)
+       return -1;
+    }
+
+  mp_withdraw->afi = afi;
+  mp_withdraw->safi = safi;
+  mp_withdraw->nlri = stream_pnt (s);
+  mp_withdraw->length = withdraw_len;
+
+  stream_forward (s, withdraw_len);
+
+  return 0;
+}
+
+/* Extended Community attribute. */
+int
+bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, 
+                         struct attr *attr, u_char flag)
+{
+  if (length == 0)
+    attr->ecommunity = NULL;
+  else
+    {
+      attr->ecommunity = ecommunity_parse (stream_pnt (peer->ibuf), length);
+      stream_forward (peer->ibuf, length);
+    }
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
+
+  return 0;
+}
+
+/* BGP unknown attribute treatment. */
+int
+bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
+                 u_char type, bgp_size_t length, u_char *startp)
+{
+  bgp_size_t total;
+  struct transit *transit;
+
+  if (BGP_DEBUG (events, EVENTS))
+    zlog (peer->log, LOG_INFO, 
+         "Unknown attribute type %d length %d is received", type, length);
+
+  /* Forward read pointer of input stream. */
+  stream_forward (peer->ibuf, length);
+
+  /* Adjest total length to include type and length. */
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+  /* If any of the mandatory well-known attributes are not recognized,
+     then the Error Subcode is set to Unrecognized Well-known
+     Attribute.  The Data field contains the unrecognized attribute
+     (type, length and value). */
+  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
+    {
+      /* Adjust startp to do not include flag value. */
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_UNREC_ATTR,
+                                startp, total);
+      return -1;
+    }
+
+  /* Unrecognized non-transitive optional attributes must be quietly
+     ignored and not passed along to other BGP peers. */
+  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
+    return 0;
+
+  /* If a path with recognized transitive optional attribute is
+     accepted and passed along to other BGP peers and the Partial bit
+     in the Attribute Flags octet is set to 1 by some previous AS, it
+     is not set back to 0 by the current AS. */
+  SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
+
+  /* Store transitive attribute to the end of attr->transit. */
+  if (! attr->transit)
+    {
+      attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
+      memset (attr->transit, 0, sizeof (struct transit));
+    }
+
+  transit = attr->transit;
+
+  if (transit->val)
+    transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, 
+                            transit->length + total);
+  else
+    transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
+
+  memcpy (transit->val + transit->length, startp, total);
+  transit->length += total;
+
+  return 0;
+}
+
+/* Read attribute of update packet.  This function is called from
+   bgp_update() in bgpd.c.  */
+int
+bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
+               struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
+{
+  int ret;
+  u_char flag;
+  u_char type;
+  bgp_size_t length;
+  u_char *startp, *endp;
+  u_char *attr_endp;
+  u_char seen[BGP_ATTR_BITMAP_SIZE];
+
+  /* Initialize bitmap. */
+  memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
+
+  /* End pointer of BGP attribute. */
+  endp = BGP_INPUT_PNT (peer) + size;
+
+  /* Get attributes to the end of attribute length. */
+  while (BGP_INPUT_PNT (peer) < endp)
+    {
+      /* Check remaining length check.*/
+      if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
+       {
+         zlog (peer->log, LOG_WARNING, 
+               "%s error BGP attribute length %d is smaller than min len",
+               peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
+
+         bgp_notify_send (peer, 
+                          BGP_NOTIFY_UPDATE_ERR, 
+                          BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+         return -1;
+       }
+
+      /* Fetch attribute flag and type. */
+      startp = BGP_INPUT_PNT (peer);
+      flag = stream_getc (BGP_INPUT (peer));
+      type = stream_getc (BGP_INPUT (peer));
+
+      /* Check extended attribue length bit. */
+      if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
+       length = stream_getw (BGP_INPUT (peer));
+      else
+       length = stream_getc (BGP_INPUT (peer));
+      
+      /* If any attribute appears more than once in the UPDATE
+        message, then the Error Subcode is set to Malformed Attribute
+        List. */
+
+      if (CHECK_BITMAP (seen, type))
+       {
+         zlog (peer->log, LOG_WARNING,
+               "%s error BGP attribute type %d appears twice in a message",
+               peer->host, type);
+
+         bgp_notify_send (peer, 
+                          BGP_NOTIFY_UPDATE_ERR, 
+                          BGP_NOTIFY_UPDATE_MAL_ATTR);
+         return -1;
+       }
+
+      /* Set type to bitmap to check duplicate attribute.  `type' is
+        unsigned char so it never overflow bitmap range. */
+
+      SET_BITMAP (seen, type);
+
+      /* Overflow check. */
+      attr_endp =  BGP_INPUT_PNT (peer) + length;
+
+      if (attr_endp > endp)
+       {
+         zlog (peer->log, LOG_WARNING, 
+               "%s BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p", peer->host, type, length, size, attr_endp, endp);
+         bgp_notify_send (peer, 
+                          BGP_NOTIFY_UPDATE_ERR, 
+                          BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+         return -1;
+       }
+
+      /* OK check attribute and store it's value. */
+      switch (type)
+       {
+       case BGP_ATTR_ORIGIN:
+         ret = bgp_attr_origin (peer, length, attr, flag, startp);
+         break;
+       case BGP_ATTR_AS_PATH:
+         ret = bgp_attr_aspath (peer, length, attr, flag, startp);
+         break;
+       case BGP_ATTR_NEXT_HOP: 
+         ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
+         break;
+       case BGP_ATTR_MULTI_EXIT_DISC:
+         ret = bgp_attr_med (peer, length, attr, flag, startp);
+         break;
+       case BGP_ATTR_LOCAL_PREF:
+         ret = bgp_attr_local_pref (peer, length, attr, flag);
+         break;
+       case BGP_ATTR_ATOMIC_AGGREGATE:
+         ret = bgp_attr_atomic (peer, length, attr, flag);
+         break;
+       case BGP_ATTR_AGGREGATOR:
+         ret = bgp_attr_aggregator (peer, length, attr, flag);
+         break;
+       case BGP_ATTR_COMMUNITIES:
+         ret = bgp_attr_community (peer, length, attr, flag);
+         break;
+       case BGP_ATTR_ORIGINATOR_ID:
+         ret = bgp_attr_originator_id (peer, length, attr, flag);
+         break;
+       case BGP_ATTR_CLUSTER_LIST:
+         ret = bgp_attr_cluster_list (peer, length, attr, flag);
+         break;
+       case BGP_ATTR_MP_REACH_NLRI:
+         ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
+         break;
+       case BGP_ATTR_MP_UNREACH_NLRI:
+         ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
+         break;
+       case BGP_ATTR_EXT_COMMUNITIES:
+         ret = bgp_attr_ext_communities (peer, length, attr, flag);
+         break;
+       default:
+         ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
+         break;
+       }
+
+      /* If error occured immediately return to the caller. */
+      if (ret < 0)
+       return ret;
+
+      /* Check the fetched length. */
+      if (BGP_INPUT_PNT (peer) != attr_endp)
+       {
+         zlog (peer->log, LOG_WARNING, 
+               "%s BGP attribute fetch error", peer->host);
+         bgp_notify_send (peer, 
+                          BGP_NOTIFY_UPDATE_ERR, 
+                          BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+         return -1;
+       }
+    }
+
+  /* Check final read pointer is same as end pointer. */
+  if (BGP_INPUT_PNT (peer) != endp)
+    {
+      zlog (peer->log, LOG_WARNING, 
+           "%s BGP attribute length mismatch", peer->host);
+      bgp_notify_send (peer, 
+                      BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+      return -1;
+    }
+
+  /* Finally intern unknown attribute. */
+  if (attr->transit)
+    attr->transit = transit_intern (attr->transit);
+
+  return 0;
+}
+
+/* Well-known attribute check. */
+int
+bgp_attr_check (struct peer *peer, struct attr *attr)
+{
+  u_char type = 0;
+  
+  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
+    type = BGP_ATTR_ORIGIN;
+
+  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
+    type = BGP_ATTR_AS_PATH;
+
+  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
+    type = BGP_ATTR_NEXT_HOP;
+
+  if (peer_sort (peer) == BGP_PEER_IBGP
+      && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
+    type = BGP_ATTR_LOCAL_PREF;
+
+  if (type)
+    {
+      zlog (peer->log, LOG_WARNING, 
+           "%s Missing well-known attribute %d.",
+           peer->host, type);
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_UPDATE_ERR, 
+                                BGP_NOTIFY_UPDATE_MISS_ATTR,
+                                &type, 1);
+      return -1;
+    }
+  return 0;
+}
+\f
+int stream_put_prefix (struct stream *, struct prefix *);
+
+/* Make attribute packet. */
+bgp_size_t
+bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
+                     struct stream *s, struct attr *attr, struct prefix *p,
+                     afi_t afi, safi_t safi, struct peer *from,
+                     struct prefix_rd *prd, u_char *tag)
+{
+  unsigned long cp;
+  struct aspath *aspath;
+
+  if (! bgp)
+    bgp = bgp_get_default ();
+
+  /* Remember current pointer. */
+  cp = stream_get_putp (s);
+
+  /* Origin attribute. */
+  stream_putc (s, BGP_ATTR_FLAG_TRANS);
+  stream_putc (s, BGP_ATTR_ORIGIN);
+  stream_putc (s, 1);
+  stream_putc (s, attr->origin);
+
+  /* AS path attribute. */
+
+  /* If remote-peer is EBGP */
+  if (peer_sort (peer) == BGP_PEER_EBGP
+      && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
+         || attr->aspath->length == 0)
+      && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
+           && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
+    {    
+      aspath = aspath_dup (attr->aspath);
+
+      if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
+       {
+         /* Strip the confed info, and then stuff our path CONFED_ID
+            on the front */
+         aspath = aspath_delete_confed_seq (aspath);
+         aspath = aspath_add_seq (aspath, bgp->confed_id);
+       }
+      else
+       {
+         aspath = aspath_add_seq (aspath, peer->local_as);
+         if (peer->change_local_as)
+           aspath = aspath_add_seq (aspath, peer->change_local_as);
+       }
+    }
+  else if (peer_sort (peer) == BGP_PEER_CONFED)
+    {
+      /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
+      aspath = aspath_dup (attr->aspath);
+      aspath = aspath_add_confed_seq (aspath, peer->local_as);
+    }
+  else
+    aspath = attr->aspath;
+
+  /* AS path attribute extended length bit check. */
+  if (aspath->length > 255)
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+      stream_putc (s, BGP_ATTR_AS_PATH);
+      stream_putw (s, aspath->length);
+    }
+  else
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc(s, BGP_ATTR_AS_PATH);
+      stream_putc (s, aspath->length);
+    }
+  stream_put (s, aspath->data, aspath->length);
+
+  if (aspath != attr->aspath)
+    aspath_free (aspath);
+
+  /* Nexthop attribute. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_NEXT_HOP);
+      stream_putc (s, 4);
+      if (safi == SAFI_MPLS_VPN)
+       {
+         if (attr->nexthop.s_addr == 0)
+           stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
+         else
+           stream_put_ipv4 (s, attr->nexthop.s_addr);
+       }
+      else
+       stream_put_ipv4 (s, attr->nexthop.s_addr);
+    }
+
+  /* MED attribute. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
+      stream_putc (s, 4);
+      stream_putl (s, attr->med);
+    }
+
+  /* Local preference. */
+  if (peer_sort (peer) == BGP_PEER_IBGP ||
+      peer_sort (peer) == BGP_PEER_CONFED)
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_LOCAL_PREF);
+      stream_putc (s, 4);
+      stream_putl (s, attr->local_pref);
+    }
+
+  /* Atomic aggregate. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
+      stream_putc (s, 0);
+    }
+
+  /* Aggregator. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_AGGREGATOR);
+      stream_putc (s, 6);
+      stream_putw (s, attr->aggregator_as);
+      stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+    }
+
+  /* Community attribute. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) 
+      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
+    {
+      if (attr->community->size * 4 > 255)
+       {
+         stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+         stream_putc (s, BGP_ATTR_COMMUNITIES);
+         stream_putw (s, attr->community->size * 4);
+       }
+      else
+       {
+         stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+         stream_putc (s, BGP_ATTR_COMMUNITIES);
+         stream_putc (s, attr->community->size * 4);
+       }
+      stream_put (s, attr->community->val, attr->community->size * 4);
+    }
+
+  /* Route Reflector. */
+  if (peer_sort (peer) == BGP_PEER_IBGP
+      && from
+      && peer_sort (from) == BGP_PEER_IBGP)
+    {
+      /* Originator ID. */
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
+      stream_putc (s, 4);
+
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+       stream_put_in_addr (s, &attr->originator_id);
+      else
+       {
+         if (from)
+           stream_put_in_addr (s, &from->remote_id);
+         else
+           stream_put_in_addr (s, &attr->originator_id);
+       }
+
+      /* Cluster list. */
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_CLUSTER_LIST);
+      
+      if (attr->cluster)
+       {
+         stream_putc (s, attr->cluster->length + 4);
+         /* If this peer configuration's parent BGP has cluster_id. */
+         if (bgp->config & BGP_CONFIG_CLUSTER_ID)
+           stream_put_in_addr (s, &bgp->cluster_id);
+         else
+           stream_put_in_addr (s, &bgp->router_id);
+         stream_put (s, attr->cluster->list, attr->cluster->length);
+       }
+      else
+       {
+         stream_putc (s, 4);
+         /* If this peer configuration's parent BGP has cluster_id. */
+         if (bgp->config & BGP_CONFIG_CLUSTER_ID)
+           stream_put_in_addr (s, &bgp->cluster_id);
+         else
+           stream_put_in_addr (s, &bgp->router_id);
+       }
+    }
+
+#ifdef HAVE_IPV6
+  /* If p is IPv6 address put it into attribute. */
+  if (p->family == AF_INET6)
+    {
+      unsigned long sizep;
+      unsigned long draftp = 0;
+
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
+      sizep = stream_get_putp (s);
+      stream_putc (s, 0);      /* Length of this attribute. */
+      stream_putw (s, AFI_IP6);        /* AFI */
+      stream_putc (s, safi);   /* SAFI */
+
+      stream_putc (s, attr->mp_nexthop_len);
+
+      if (attr->mp_nexthop_len == 16)
+       stream_put (s, &attr->mp_nexthop_global, 16);
+      else if (attr->mp_nexthop_len == 32)
+       {
+         stream_put (s, &attr->mp_nexthop_global, 16);
+         stream_put (s, &attr->mp_nexthop_local, 16);
+       }
+      
+      /* SNPA */
+      stream_putc (s, 0);
+
+      /* In case of old draft BGP-4+. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       {
+         draftp = stream_get_putp (s);
+         stream_putw (s, 0);
+       }
+      
+      /* Prefix write. */
+      stream_put_prefix (s, p);
+
+      /* Set MP attribute length. */
+      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
+
+      /* In case of old draft BGP-4+. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2);
+    }
+#endif /* HAVE_IPV6 */
+
+  if (p->family == AF_INET && safi == SAFI_MULTICAST)
+    {
+      unsigned long sizep;
+      unsigned long draftp = 0;
+
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
+      sizep = stream_get_putp (s);
+      stream_putc (s, 0);      /* Length of this attribute. */
+      stream_putw (s, AFI_IP); /* AFI */
+      stream_putc (s, SAFI_MULTICAST); /* SAFI */
+
+      stream_putc (s, 4);
+      stream_put_ipv4 (s, attr->nexthop.s_addr);
+
+      /* SNPA */
+      stream_putc (s, 0);
+
+      /* In case of old draft BGP-4+. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       {
+         draftp = stream_get_putp (s);
+         stream_putw (s, 0);
+       }
+      
+      /* Prefix write. */
+      stream_put_prefix (s, p);
+
+      /* Set MP attribute length. */
+      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
+
+      /* In case of old draft BGP-4+. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2);
+    }
+
+  if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
+    {
+      unsigned long sizep;
+      unsigned long draftp = 0;
+
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
+      sizep = stream_get_putp (s);
+      stream_putc (s, 0);      /* Length of this attribute. */
+      stream_putw (s, AFI_IP); /* AFI */
+      stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
+
+      stream_putc (s, 12);
+      stream_putl (s, 0);
+      stream_putl (s, 0);
+      stream_put (s, &attr->mp_nexthop_global_in, 4);
+
+      /* SNPA */
+      stream_putc (s, 0);
+
+      /* In case of old draft BGP-4+. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       {
+         draftp = stream_get_putp (s);
+         stream_putw (s, 0);
+       }
+      
+      /* Tag, RD, Prefix write. */
+      stream_putc (s, p->prefixlen + 88);
+      stream_put (s, tag, 3);
+      stream_put (s, prd->val, 8);
+      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
+
+      /* Set MP attribute length. */
+      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
+
+      /* In case of old draft BGP-4+. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2);
+    }
+
+  /* Extended Communities attribute. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) 
+      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
+    {
+      if (attr->ecommunity->size * 8 > 255)
+       {
+         stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+         stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
+         stream_putw (s, attr->ecommunity->size * 8);
+       }
+      else
+       {
+         stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+         stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
+         stream_putc (s, attr->ecommunity->size * 8);
+       }
+      stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
+    }
+
+  /* Unknown transit attribute. */
+  if (attr->transit)
+    stream_put (s, attr->transit->val, attr->transit->length);
+
+  /* Return total size of attribute. */
+  return stream_get_putp (s) - cp;
+}
+
+bgp_size_t
+bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
+                    afi_t afi, safi_t safi, struct prefix_rd *prd,
+                    u_char *tag)
+{
+  unsigned long cp;
+  unsigned long attrlen_pnt;
+  bgp_size_t size;
+
+  cp = stream_get_putp (s);
+
+  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+  stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
+
+  attrlen_pnt = stream_get_putp (s);
+  stream_putc (s, 0);          /* Length of this attribute. */
+
+  stream_putw (s, family2afi (p->family));
+
+  if (safi == SAFI_MPLS_VPN)
+    {
+      /* SAFI */
+      stream_putc (s, BGP_SAFI_VPNV4);
+
+      /* prefix. */
+      stream_putc (s, p->prefixlen + 88);
+      stream_put (s, tag, 3);
+      stream_put (s, prd->val, 8);
+      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
+    }
+  else
+    {
+      /* SAFI */
+      stream_putc (s, safi);
+
+      /* prefix */
+      stream_put_prefix (s, p);
+    }
+
+  /* Set MP attribute length. */
+  size = stream_get_putp (s) - attrlen_pnt - 1;
+  stream_putc_at (s, attrlen_pnt, size);
+
+  return stream_get_putp (s) - cp;
+}
+
+/* Initialization of attribute. */
+void
+bgp_attr_init ()
+{
+  void attrhash_init ();
+
+  aspath_init ();
+  attrhash_init ();
+  community_init ();
+  ecommunity_init ();
+  cluster_init ();
+  transit_init ();
+}
+
+/* Make attribute packet. */
+void
+bgp_dump_routes_attr (struct stream *s, struct attr *attr)
+{
+  unsigned long cp;
+  unsigned long len;
+  struct aspath *aspath;
+
+  /* Remember current pointer. */
+  cp = stream_get_putp (s);
+
+  /* Place holder of length. */
+  stream_putw (s, 0);
+
+  /* Origin attribute. */
+  stream_putc (s, BGP_ATTR_FLAG_TRANS);
+  stream_putc (s, BGP_ATTR_ORIGIN);
+  stream_putc (s, 1);
+  stream_putc (s, attr->origin);
+
+  aspath = attr->aspath;
+
+  if (aspath->length > 255)
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+      stream_putc (s, BGP_ATTR_AS_PATH);
+      stream_putw (s, aspath->length);
+    }
+  else
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_AS_PATH);
+      stream_putc (s, aspath->length);
+    }
+  stream_put (s, aspath->data, aspath->length);
+
+  /* Nexthop attribute. */
+  stream_putc (s, BGP_ATTR_FLAG_TRANS);
+  stream_putc (s, BGP_ATTR_NEXT_HOP);
+  stream_putc (s, 4);
+  stream_put_ipv4 (s, attr->nexthop.s_addr);
+
+  /* MED attribute. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+      stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
+      stream_putc (s, 4);
+      stream_putl (s, attr->med);
+    }
+
+  /* Local preference. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_LOCAL_PREF);
+      stream_putc (s, 4);
+      stream_putl (s, attr->local_pref);
+    }
+
+  /* Atomic aggregate. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
+      stream_putc (s, 0);
+    }
+
+  /* Aggregator. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_AGGREGATOR);
+      stream_putc (s, 6);
+      stream_putw (s, attr->aggregator_as);
+      stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
+    }
+
+  /* Community attribute. */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
+    {
+      if (attr->community->size * 4 > 255)
+       {
+         stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+         stream_putc (s, BGP_ATTR_COMMUNITIES);
+         stream_putw (s, attr->community->size * 4);
+       }
+      else
+       {
+         stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+         stream_putc (s, BGP_ATTR_COMMUNITIES);
+         stream_putc (s, attr->community->size * 4);
+       }
+      stream_put (s, attr->community->val, attr->community->size * 4);
+    }
+
+  /* Return total size of attribute. */
+  len = stream_get_putp (s) - cp - 2;
+  stream_putw_at (s, cp, len);
+}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
new file mode 100644 (file)
index 0000000..9c5bf87
--- /dev/null
@@ -0,0 +1,125 @@
+/* BGP attributes. 
+   Copyright (C) 1996, 97, 98 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* Simple bit mapping. */
+#define BITMAP_NBBY 8
+
+#define SET_BITMAP(MAP, NUM) \
+        SET_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY))
+
+#define CHECK_BITMAP(MAP, NUM) \
+        CHECK_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY))
+
+/* BGP Attribute type range. */
+#define BGP_ATTR_TYPE_RANGE     256
+#define BGP_ATTR_BITMAP_SIZE    (BGP_ATTR_TYPE_RANGE / BITMAP_NBBY)
+
+/* BGP Attribute flags. */
+#define BGP_ATTR_FLAG_OPTIONAL  0x80   /* Attribute is optional. */
+#define BGP_ATTR_FLAG_TRANS     0x40   /* Attribute is transitive. */
+#define BGP_ATTR_FLAG_PARTIAL   0x20   /* Attribute is partial. */
+#define BGP_ATTR_FLAG_EXTLEN    0x10   /* Extended length flag. */
+
+/* BGP attribute header must bigger than 2. */
+#define BGP_ATTR_MIN_LEN        2       /* Attribute flag and type. */
+
+/* BGP attribute structure. */
+struct attr
+{
+  /* Reference count of this attribute. */
+  unsigned long refcnt;
+
+  /* Flag of attribute is set or not. */
+  u_int32_t flag;
+
+  /* Attributes. */
+  u_char origin;
+  struct in_addr nexthop;
+  u_int32_t med;
+  u_int32_t local_pref;
+  as_t aggregator_as;
+  struct in_addr aggregator_addr;
+  u_int32_t weight;
+  struct in_addr originator_id;
+  struct cluster_list *cluster;
+
+  u_char mp_nexthop_len;
+#ifdef HAVE_IPV6
+  struct in6_addr mp_nexthop_global;
+  struct in6_addr mp_nexthop_local;
+#endif /* HAVE_IPV6 */
+  struct in_addr mp_nexthop_global_in;
+  struct in_addr mp_nexthop_local_in;
+
+  /* AS Path structure */
+  struct aspath *aspath;
+
+  /* Community structure */
+  struct community *community; 
+
+  /* Extended Communities attribute. */
+  struct ecommunity *ecommunity;
+
+  /* Unknown transitive attribute. */
+  struct transit *transit;
+};
+
+/* Router Reflector related structure. */
+struct cluster_list
+{
+  unsigned long refcnt;
+  int length;
+  struct in_addr *list;
+};
+
+/* Unknown transit attribute. */
+struct transit
+{
+  unsigned long refcnt;
+  int length;
+  u_char *val;
+};
+
+#define ATTR_FLAG_BIT(X)  (1 << ((X) - 1))
+
+/* Prototypes. */
+void bgp_attr_init ();
+int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t,
+                   struct bgp_nlri *, struct bgp_nlri *);
+int bgp_attr_check (struct peer *, struct attr *);
+struct attr *bgp_attr_intern (struct attr *attr);
+void bgp_attr_unintern (struct attr *);
+void bgp_attr_flush (struct attr *);
+struct attr *bgp_attr_default_set (struct attr *attr, u_char);
+struct attr *bgp_attr_default_intern (u_char);
+struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set);
+bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, u_char *);
+bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, afi_t, safi_t, struct prefix_rd *, u_char *);
+void bgp_dump_routes_attr (struct stream *, struct attr *);
+unsigned int attrhash_key_make (struct attr *);
+int attrhash_cmp (struct attr *, struct attr *);
+void attr_show_all (struct vty *);
+
+/* Cluster list prototypes. */
+int cluster_loop_check (struct cluster_list *, struct in_addr);
+void cluster_unintern (struct cluster_list *);
+
+/* Transit attribute prototypes. */
+void transit_unintern (struct transit *);
diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c
new file mode 100644 (file)
index 0000000..7c70881
--- /dev/null
@@ -0,0 +1,291 @@
+/* BGP dump to ascii converter
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "zebra.h"
+#include "stream.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+
+enum MRT_MSG_TYPES {
+   MSG_NULL,
+   MSG_START,                   /* sender is starting up */
+   MSG_DIE,                     /* receiver should shut down */
+   MSG_I_AM_DEAD,               /* sender is shutting down */
+   MSG_PEER_DOWN,               /* sender's peer is down */
+   MSG_PROTOCOL_BGP,            /* msg is a BGP packet */
+   MSG_PROTOCOL_RIP,            /* msg is a RIP packet */
+   MSG_PROTOCOL_IDRP,           /* msg is an IDRP packet */
+   MSG_PROTOCOL_RIPNG,          /* msg is a RIPNG packet */
+   MSG_PROTOCOL_BGP4PLUS,       /* msg is a BGP4+ packet */
+   MSG_PROTOCOL_BGP4PLUS_01,    /* msg is a BGP4+ (draft 01) packet */
+   MSG_PROTOCOL_OSPF,           /* msg is an OSPF packet */
+   MSG_TABLE_DUMP               /* routing table dump */
+};
+
+int
+attr_parse (struct stream *s, u_int16_t len)
+{
+  u_int flag;
+  u_int type;
+  u_int16_t length;
+  u_int16_t lim;
+
+  lim = s->getp + len;
+
+  printf ("attr_parse s->getp %d, len %d, lim %d\n", s->getp, len, lim);
+
+  while (s->getp < lim)
+    {
+      flag = stream_getc (s);
+      type = stream_getc (s);
+
+      if (flag & ATTR_FLAG_EXTLEN)
+       length = stream_getw (s);
+      else
+       length = stream_getc (s);
+
+      printf ("FLAG: %d\n", flag);
+      printf ("TYPE: %d\n", type);
+      printf ("Len: %d\n", length);
+
+      switch (type)
+       {
+       case BGP_ATTR_ORIGIN:
+         {
+           u_char origin;
+           origin = stream_getc (s);
+           printf ("ORIGIN: %d\n", origin);
+         }
+         break;
+       case BGP_ATTR_AS_PATH:
+         {
+           struct aspath aspath;
+
+           aspath.data = (s->data + s->getp);
+           aspath.length = length;
+           aspath.str = aspath_make_str_count (&aspath);
+           printf ("ASPATH: %s\n", aspath.str);
+           free (aspath.str);
+           
+           stream_forward (s, length);
+         }
+         break;
+       case BGP_ATTR_NEXT_HOP: 
+         {
+           struct in_addr nexthop;
+           nexthop.s_addr = stream_get_ipv4 (s);
+           printf ("NEXTHOP: %s\n", inet_ntoa (nexthop));
+           /* stream_forward (s, length); */
+         }
+         break;
+       default:
+         stream_forward (s, length);
+         break;
+       }
+    }
+
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int ret;
+  FILE *fp;
+  struct stream *s;
+  time_t now;
+  int type;
+  int subtype;
+  int len;
+  int source_as;
+  int dest_as;
+  int ifindex;
+  int family;
+  struct in_addr sip;
+  struct in_addr dip;
+  u_int16_t viewno, seq_num;
+  struct prefix_ipv4 p;
+
+  s = stream_new (10000);
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage: %s FILENAME\n", argv[0]);
+      exit (1);
+    }
+  fp = fopen (argv[1], "r");
+  if (!fp)
+    {
+      perror ("fopen");
+      exit (1);
+    }
+  
+  while (1)
+    {
+      stream_reset (s);
+
+      ret = fread (s->data, 12, 1, fp);
+      if (feof (fp))
+       {
+         printf ("END OF FILE\n");
+         break;
+       }
+      if (ferror (fp))
+       {
+         printf ("ERROR OF FREAD\n");
+         break;
+       }
+
+      /* Extract header. */
+      now = stream_getl (s);
+      type = stream_getw (s);
+      subtype = stream_getw (s);
+      len = stream_getl (s);
+
+      printf ("TIME: %s", ctime (&now));
+
+      /* printf ("TYPE: %d/%d\n", type, subtype); */
+
+      if (type == MSG_PROTOCOL_BGP4MP)
+       printf ("TYPE: BGP4MP");
+      else if (type == MSG_TABLE_DUMP)
+       printf ("TYPE: MSG_TABLE_DUMP");
+      else
+       printf ("TYPE: Unknown %d", type);
+
+      if (type == MSG_TABLE_DUMP)
+       switch (subtype)
+         {
+         case AFI_IP:
+           printf ("/AFI_IP\n");
+           break;
+         case AFI_IP6:
+           printf ("/AFI_IP6\n");
+           break;
+         default:
+           printf ("/UNKNOWN %d", subtype);
+           break;
+         }
+      else
+       {
+         switch (subtype)
+           {
+           case BGP4MP_STATE_CHANGE:
+             printf ("/CHANGE\n");
+             break;
+           case BGP4MP_MESSAGE:
+             printf ("/MESSAGE\n");
+             break;
+           case BGP4MP_ENTRY:
+             printf ("/ENTRY\n");
+             break;
+           case BGP4MP_SNAPSHOT:
+             printf ("/SNAPSHOT\n");
+             break;
+           default:
+             printf ("/UNKNOWN %d", subtype);
+             break;
+           }
+       }
+
+      printf ("len: %d\n", len);
+
+      ret = fread (s->data + 12, len, 1, fp);
+      if (feof (fp))
+       {
+         printf ("ENDOF FILE 2\n");
+         break;
+       }
+      if (ferror (fp))
+       {
+         printf ("ERROR OF FREAD 2\n");
+         break;
+       }
+
+      /* printf ("now read %d\n", len); */
+
+      if (type == MSG_TABLE_DUMP)
+       {
+         u_char status;
+         time_t originated;
+         struct in_addr peer;
+         u_int16_t attrlen;
+
+         viewno = stream_getw (s);
+         seq_num = stream_getw (s);
+         printf ("VIEW: %d\n", viewno);
+         printf ("SEQUENCE: %d\n", seq_num);
+
+         /* start */
+         while (s->getp < len - 16)
+           {
+             p.prefix.s_addr = stream_get_ipv4 (s);
+             p.prefixlen = stream_getc (s);
+             printf ("PREFIX: %s/%d\n", inet_ntoa (p.prefix), p.prefixlen);
+
+             status = stream_getc (s);
+             originated = stream_getl (s);
+             peer.s_addr = stream_get_ipv4 (s);
+             source_as = stream_getw(s);
+
+             printf ("FROM: %s AS%d\n", inet_ntoa (peer), source_as);
+             printf ("ORIGINATED: %s", ctime (&originated));
+
+             attrlen = stream_getw (s);
+             printf ("ATTRLEN: %d\n", attrlen);
+
+             attr_parse (s, attrlen);
+
+             printf ("STATUS: 0x%x\n", status);
+           }
+       }
+      else
+       {
+         source_as = stream_getw (s);
+         dest_as = stream_getw (s);
+         printf ("source_as: %d\n", source_as);
+         printf ("dest_as: %d\n", dest_as);
+
+         ifindex = stream_getw (s);
+         family = stream_getw (s);
+
+         printf ("ifindex: %d\n", ifindex);
+         printf ("family: %d\n", family);
+
+         sip.s_addr = stream_get_ipv4 (s);
+         dip.s_addr = stream_get_ipv4 (s);
+         
+         printf ("saddr: %s\n", inet_ntoa (sip));
+         printf ("daddr: %s\n", inet_ntoa (dip));
+
+         printf ("\n");
+       }
+    }
+  fclose (fp);
+  return 0;
+}
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
new file mode 100644 (file)
index 0000000..0b6a2e8
--- /dev/null
@@ -0,0 +1,905 @@
+/* BGP community-list and extcommunity-list.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "memory.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_clist.h"
+\f
+/* Lookup master structure for community-list or
+   extcommunity-list.  */
+struct community_list_master *
+community_list_master_lookup (struct community_list_handler *ch, int style)
+{
+  if (ch)
+    switch (style)
+      {
+      case COMMUNITY_LIST_STANDARD:
+      case COMMUNITY_LIST_EXPANDED:
+      case COMMUNITY_LIST_AUTO:
+       return &ch->community_list;
+       break;
+      case EXTCOMMUNITY_LIST_STANDARD:
+      case EXTCOMMUNITY_LIST_EXPANDED:
+      case EXTCOMMUNITY_LIST_AUTO:
+       return &ch->extcommunity_list;
+      }
+  return NULL;
+}
+
+/* Allocate a new community list entry.  */
+struct community_entry *
+community_entry_new ()
+{
+  struct community_entry *new;
+
+  new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
+  memset (new, 0, sizeof (struct community_entry));
+  return new;
+}
+
+/* Free community list entry.  */
+void
+community_entry_free (struct community_entry *entry)
+{
+  switch (entry->style)
+    {
+    case COMMUNITY_LIST_STANDARD:
+      if (entry->u.com)
+       community_free (entry->u.com);
+      break;
+    case EXTCOMMUNITY_LIST_STANDARD:
+      /* In case of standard extcommunity-list, configuration string
+        is made by ecommunity_ecom2str().  */
+      if (entry->config)
+       XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
+      if (entry->u.ecom)
+       ecommunity_free (entry->u.ecom);
+      break;
+    case COMMUNITY_LIST_EXPANDED:
+    case EXTCOMMUNITY_LIST_EXPANDED:
+      if (entry->config)
+       XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
+      if (entry->reg)
+       bgp_regex_free (entry->reg);
+    default:
+      break;
+    }
+  XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
+}
+
+/* Allocate a new community-list.  */
+struct community_list *
+community_list_new ()
+{
+  struct community_list *new;
+
+  new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
+  memset (new, 0, sizeof (struct community_list));
+  return new;
+}
+
+/* Free community-list.  */
+void
+community_list_free (struct community_list *list)
+{
+  if (list->name)
+    XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
+  XFREE (MTYPE_COMMUNITY_LIST, list);
+}
+
+struct community_list *
+community_list_insert (struct community_list_handler *ch,
+                      char *name, int style)
+{
+  int i;
+  long number;
+  struct community_list *new;
+  struct community_list *point;
+  struct community_list_list *list;
+  struct community_list_master *cm;
+
+  /* Lookup community-list master.  */
+  cm = community_list_master_lookup (ch, style);
+  if (! cm)
+    return NULL;
+
+  /* Allocate new community_list and copy given name. */
+  new = community_list_new ();
+  new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
+
+  /* If name is made by all digit character.  We treat it as
+     number. */
+  for (number = 0, i = 0; i < strlen (name); i++)
+    {
+      if (isdigit ((int) name[i]))
+       number = (number * 10) + (name[i] - '0');
+      else
+       break;
+    }
+
+  /* In case of name is all digit character */
+  if (i == strlen (name))
+    {
+      new->sort = COMMUNITY_LIST_NUMBER;
+
+      /* Set access_list to number list. */
+      list = &cm->num;
+
+      for (point = list->head; point; point = point->next)
+       if (atol (point->name) >= number)
+         break;
+    }
+  else
+    {
+      new->sort = COMMUNITY_LIST_STRING;
+
+      /* Set access_list to string list. */
+      list = &cm->str;
+  
+      /* Set point to insertion point. */
+      for (point = list->head; point; point = point->next)
+       if (strcmp (point->name, name) >= 0)
+         break;
+    }
+
+  /* Link to upper list.  */
+  new->parent = list;
+
+  /* In case of this is the first element of master. */
+  if (list->head == NULL)
+    {
+      list->head = list->tail = new;
+      return new;
+    }
+
+  /* In case of insertion is made at the tail of access_list. */
+  if (point == NULL)
+    {
+      new->prev = list->tail;
+      list->tail->next = new;
+      list->tail = new;
+      return new;
+    }
+
+  /* In case of insertion is made at the head of access_list. */
+  if (point == list->head)
+    {
+      new->next = list->head;
+      list->head->prev = new;
+      list->head = new;
+      return new;
+    }
+
+  /* Insertion is made at middle of the access_list. */
+  new->next = point;
+  new->prev = point->prev;
+
+  if (point->prev)
+    point->prev->next = new;
+  point->prev = new;
+
+  return new;
+}
+
+struct community_list *
+community_list_lookup (struct community_list_handler *ch,
+                      char *name, int style)
+{
+  struct community_list *list;
+  struct community_list_master *cm;
+
+  if (! name)
+    return NULL;
+
+  cm = community_list_master_lookup (ch, style);
+  if (! cm)
+    return NULL;
+
+  for (list = cm->num.head; list; list = list->next)
+    if (strcmp (list->name, name) == 0)
+      return list;
+  for (list = cm->str.head; list; list = list->next)
+    if (strcmp (list->name, name) == 0)
+      return list;
+
+  return NULL;
+}
+
+struct community_list *
+community_list_get (struct community_list_handler *ch, char *name, int style)
+{
+  struct community_list *list;
+
+  list = community_list_lookup (ch, name, style);
+  if (! list)
+    list = community_list_insert (ch, name, style);
+  return list;
+}
+
+void
+community_list_delete (struct community_list *list)
+{
+  struct community_list_list *clist;
+  struct community_entry *entry, *next;
+
+  for (entry = list->head; entry; entry = next)
+    {
+      next = entry->next;
+      community_entry_free (entry);
+    }
+
+  clist = list->parent;
+
+  if (list->next)
+    list->next->prev = list->prev;
+  else
+    clist->tail = list->prev;
+
+  if (list->prev)
+    list->prev->next = list->next;
+  else
+    clist->head = list->next;
+
+  community_list_free (list);
+}
+
+int 
+community_list_empty_p (struct community_list *list)
+{
+  return (list->head == NULL && list->tail == NULL) ? 1 : 0;
+}
+\f
+/* Add community-list entry to the list.  */
+static void
+community_list_entry_add (struct community_list *list, 
+                         struct community_entry *entry)
+{
+  entry->next = NULL;
+  entry->prev = list->tail;
+
+  if (list->tail)
+    list->tail->next = entry;
+  else
+    list->head = entry;
+  list->tail = entry;
+}
+
+/* Delete community-list entry from the list.  */
+static void
+community_list_entry_delete (struct community_list *list,
+                            struct community_entry *entry, int style)
+{
+  if (entry->next)
+    entry->next->prev = entry->prev;
+  else
+    list->tail = entry->prev;
+
+  if (entry->prev)
+    entry->prev->next = entry->next;
+  else
+    list->head = entry->next;
+
+  community_entry_free (entry);
+
+  if (community_list_empty_p (list))
+    community_list_delete (list);
+}
+
+/* Lookup community-list entry from the list.  */
+static struct community_entry *
+community_list_entry_lookup (struct community_list *list, void *arg,
+                            int direct)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      switch (entry->style)
+       {
+       case COMMUNITY_LIST_STANDARD:
+         if (community_cmp (entry->u.com, arg))
+           return entry;
+         break;
+       case EXTCOMMUNITY_LIST_STANDARD:
+         if (ecommunity_cmp (entry->u.ecom, arg))
+           return entry;
+         break;
+       case COMMUNITY_LIST_EXPANDED:
+       case EXTCOMMUNITY_LIST_EXPANDED:
+         if (strcmp (entry->config, arg) == 0)
+           return entry;
+         break;
+       default:
+         break;
+       }
+    }
+  return NULL;
+}
+\f
+/* Internal function to perform regular expression match for community
+   attribute.  */
+static int
+community_regexp_match (struct community *com, regex_t *reg)
+{
+  char *str;
+
+  /* When there is no communities attribute it is treated as empty
+     string.  */
+  if (com == NULL || com->size == 0)
+    str = "";
+  else
+    str = community_str (com);
+
+  /* Regular expression match.  */
+  if (regexec (reg, str, 0, NULL, 0) == 0)
+    return 1;
+
+  /* No match.  */
+  return 0;
+}
+
+/* Delete community attribute using regular expression match.  Return
+   modified communites attribute.  */
+static struct community *
+community_regexp_delete (struct community *com, regex_t *reg)
+{
+  int i;
+  u_int32_t comval;
+  /* Maximum is "65535:65535" + '\0'. */
+  char c[12];
+  char *str;
+
+  if (! com)
+    return NULL;
+
+  i = 0;
+  while (i < com->size)
+    {
+      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
+      comval = ntohl (comval);
+
+      switch (comval)
+       {
+       case COMMUNITY_INTERNET:
+         str = "internet";
+         break;
+       case COMMUNITY_NO_EXPORT:
+         str = "no-export";
+         break;
+       case COMMUNITY_NO_ADVERTISE:
+         str = "no-advertise";
+         break;
+       case COMMUNITY_LOCAL_AS:
+         str = "local-AS";
+         break;
+       default:
+         sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
+         str = c;
+         break;
+       }
+
+      if (regexec (reg, str, 0, NULL, 0) == 0)
+       community_del_val (com, com_nthval (com, i));
+      else
+       i++;
+    }
+  return com;
+}
+
+/* When given community attribute matches to the community-list return
+   1 else return 0.  */
+int
+community_list_match (struct community *com, struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry->any)
+       return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+      if (entry->style == COMMUNITY_LIST_STANDARD)
+       {
+         if (community_include (entry->u.com, COMMUNITY_INTERNET))
+           return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+         if (community_match (com, entry->u.com))
+           return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+       }
+      else if (entry->style == COMMUNITY_LIST_EXPANDED)
+       {
+         if (community_regexp_match (com, entry->reg))
+           return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+       }
+    }
+  return 0;
+}
+
+/* Perform exact matching.  In case of expanded community-list, do
+   same thing as community_list_match().  */
+int
+community_list_exact_match (struct community *com, struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry->any)
+       return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+      if (entry->style == COMMUNITY_LIST_STANDARD)
+       {
+         if (community_include (entry->u.com, COMMUNITY_INTERNET))
+           return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+         if (community_cmp (com, entry->u.com))
+           return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+       }
+      else if (entry->style == COMMUNITY_LIST_EXPANDED)
+       {
+         if (community_regexp_match (com, entry->reg))
+           return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+       }
+    }
+  return 0;
+}
+
+/* Delete all permitted communities in the list from com1 */
+struct community *
+community_list_match_delete (struct community *com,
+                            struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry->any && entry->direct == COMMUNITY_PERMIT)
+       {
+         /* This is a tricky part.  Currently only
+            route_set_community_delete() uses this function.  In the
+            function com->size is zero, it free the community
+            structure.  */
+         com->size = 0;
+         return com;
+       }
+
+      if (entry->style == COMMUNITY_LIST_STANDARD)
+       {
+         if (entry->direct == COMMUNITY_PERMIT)
+           community_delete (com, entry->u.com);
+       }
+      else if (entry->style == COMMUNITY_LIST_EXPANDED)
+       {
+         if (entry->direct == COMMUNITY_PERMIT)
+           community_regexp_delete (com, entry->reg);
+       }
+    }
+  return com;
+}
+
+/* To avoid duplicated entry in the community-list, this function
+   compares specified entry to existing entry.  */
+int
+community_list_dup_check (struct community_list *list, 
+                         struct community_entry *new)
+{
+  struct community_entry *entry;
+  
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry->style != new->style)
+       continue;
+
+      if (entry->direct != new->direct)
+       continue;
+
+      if (entry->any != new->any)
+       continue;
+
+      if (entry->any)
+       return 1;
+
+      switch (entry->style)
+       {
+       case COMMUNITY_LIST_STANDARD:
+         if (community_cmp (entry->u.com, new->u.com))
+           return 1;
+         break;
+       case EXTCOMMUNITY_LIST_STANDARD:
+         if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
+           return 1;
+         break;
+       case COMMUNITY_LIST_EXPANDED:
+       case EXTCOMMUNITY_LIST_EXPANDED:
+         if (strcmp (entry->config, new->config) == 0)
+           return 1;
+         break;
+       default:
+         break;
+       }
+    }
+  return 0;
+}
+\f
+/* Set community-list.  */
+int
+community_list_set (struct community_list_handler *ch,
+                   char *name, char *str, int direct, int style)
+{
+  struct community_entry *entry;
+  struct community_list *list;
+  struct community *com;
+  regex_t *regex;
+
+  entry = NULL;
+
+  /* Get community list. */
+  list = community_list_get (ch, name, style);
+
+  /* When community-list already has entry, new entry should have same
+     style.  If you want to have mixed style community-list, you can
+     comment out this check.  */
+  if (! community_list_empty_p (list))
+    {
+      struct community_entry *first;
+
+      first = list->head;
+
+      if (style == COMMUNITY_LIST_AUTO)
+       style = first->style;
+      else if (style != first->style)
+       {
+         return (first->style == COMMUNITY_LIST_STANDARD
+                 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
+                 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
+       }
+    }
+
+  /* When str is NULL, it is matches any.  */
+  if (! str)
+    {
+      entry = community_entry_new ();
+      entry->direct = direct;
+      entry->any = 1;
+      if (style == COMMUNITY_LIST_AUTO)
+       entry->style = COMMUNITY_LIST_STANDARD;
+      else
+       entry->style = style;
+    }
+  else
+    {
+      /* Standard community-list parse.  String must be converted into
+        community structure without problem.  */
+      if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
+       {
+         com = community_str2com (str);
+         if (com)
+           {
+             entry = community_entry_new ();
+             entry->u.com = com;
+             entry->direct = direct;
+             entry->style = COMMUNITY_LIST_STANDARD;
+           }
+         else if (style == COMMUNITY_LIST_STANDARD)
+           return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+         
+         /* We can't convert string into communities value.  When
+            community-list type is auto, fall dawn to regular expression
+            match.  */
+       }
+
+      /* Expanded community-list parse.  String may include regular
+        expression.  */
+      if (! entry && (style == COMMUNITY_LIST_EXPANDED
+                     || style == COMMUNITY_LIST_AUTO))
+       {
+         regex = bgp_regcomp (str);
+         if (regex)
+           {
+             entry = community_entry_new ();
+             entry->reg = regex;
+             entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
+             entry->direct = direct;
+             entry->style = COMMUNITY_LIST_EXPANDED;
+           }
+         else
+           return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+       }
+    }
+
+  /* Do not put duplicated community entry.  */
+  if (community_list_dup_check (list, entry))
+    community_entry_free (entry);
+  else
+    community_list_entry_add (list, entry);
+
+  return 0;
+}
+
+/* Unset community-list.  When str is NULL, delete all of
+   community-list entry belongs to the specified name.  */
+int
+community_list_unset (struct community_list_handler *ch,
+                     char *name, char *str, int direct, int style)
+{
+  struct community_entry *entry;
+  struct community_list *list;
+  struct community *com;
+  regex_t *regex;
+
+  entry = NULL;
+
+  /* Lookup community list.  */
+  list = community_list_lookup (ch, name, style);
+  if (list == NULL)
+    return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+  /* Delete all of entry belongs to this community-list.  */
+  if (! str)
+    {
+      community_list_delete (list);
+      return 0;
+    }
+
+  /* Community list string is specified.  Lookup entry from community
+     list.  */
+  if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
+    {
+      com = community_str2com (str);
+      if (com)
+       {
+         entry = community_list_entry_lookup (list, com, direct);
+         community_free (com);
+       }
+      else if (style == COMMUNITY_LIST_STANDARD)
+       return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
+      /* If we can't convert string into community and community-list
+        type is auto, fall dawn to expanded community-list.  */
+    }
+
+  /* Expanded community-list parse.  String may include regular
+     expression.  */
+  if (! entry 
+      && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
+    {
+      regex = bgp_regcomp (str);
+      if (regex)
+       {
+         entry = community_list_entry_lookup (list, str, direct);
+         bgp_regex_free (regex);
+       }
+      else
+       return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+    }
+
+  if (! entry)
+    return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+  community_list_entry_delete (list, entry, style);
+
+  return 0;
+}
+
+/* Set extcommunity-list.  */
+int
+extcommunity_list_set (struct community_list_handler *ch,
+                      char *name, char *str, int direct, int style)
+{
+  struct community_entry *entry;
+  struct community_list *list;
+  struct ecommunity *ecom;
+  regex_t *regex;
+
+  entry = NULL;
+
+  /* Get community list. */
+  list = community_list_get (ch, name, style);
+
+  /* When community-list already has entry, new entry should have same
+     style.  If you want to have mixed style community-list, you can
+     comment out this check.  */
+  if (! community_list_empty_p (list))
+    {
+      struct community_entry *first;
+
+      first = list->head;
+
+      if (style == EXTCOMMUNITY_LIST_AUTO)
+       style = first->style;
+      else if (style != first->style)
+       {
+         return (first->style == EXTCOMMUNITY_LIST_STANDARD
+                 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
+                 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
+       }
+    }
+
+  /* When str is NULL, it is matches any.  */
+  if (! str)
+    {
+      entry = community_entry_new ();
+      entry->direct = direct;
+      entry->any = 1;
+      if (style == EXTCOMMUNITY_LIST_AUTO)
+       entry->style = EXTCOMMUNITY_LIST_STANDARD;
+      else
+       entry->style = style;
+    }
+  else
+    {
+      /* Standard extcommunity-list parse.  String is converted into
+        ecommunity structure.  */
+      if (style == EXTCOMMUNITY_LIST_STANDARD
+         || style == EXTCOMMUNITY_LIST_AUTO)
+       {
+         /* Type is unknown.  String includes keyword.  */
+         ecom = ecommunity_str2com (str, 0, 1);
+         if (ecom)
+           {
+             entry = community_entry_new ();
+             entry->config 
+               = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+             ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
+             entry->u.ecom = ecom;
+             entry->direct = direct;
+             entry->style = EXTCOMMUNITY_LIST_STANDARD;
+           }
+         else if (style == EXTCOMMUNITY_LIST_STANDARD)
+           return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
+         /* We can't convert string into communities value.  When
+            community-list type is auto, fall dawn to regular expression
+            match.  */
+       }
+
+      /* Expanded extcommunity-list parse.  String may include regular
+        expression.  */
+      if (! entry && (style == EXTCOMMUNITY_LIST_EXPANDED
+                     || style == EXTCOMMUNITY_LIST_AUTO))
+       {
+         regex = bgp_regcomp (str);
+         if (regex)
+           {
+             entry = community_entry_new ();
+             entry->reg = regex;
+             entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
+             entry->direct = direct;
+             entry->style = EXTCOMMUNITY_LIST_EXPANDED;
+           }
+         else
+           return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+       }
+    }
+
+  /* Do not put duplicated community entry.  */
+  if (community_list_dup_check (list, entry))
+    community_entry_free (entry);
+  else
+    community_list_entry_add (list, entry);
+
+  return 0;
+}
+
+/* Unset extcommunity-list.  When str is NULL, delete all of
+   extcommunity-list entry belongs to the specified name.  */
+int
+extcommunity_list_unset (struct community_list_handler *ch,
+                        char *name, char *str, int direct, int style)
+{
+  struct community_entry *entry;
+  struct community_list *list;
+  struct ecommunity *ecom = NULL;
+  regex_t *regex;
+
+  entry = NULL;
+
+  /* Lookup extcommunity list.  */
+  list = community_list_lookup (ch, name, style);
+  if (list == NULL)
+    return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+  /* Delete all of entry belongs to this extcommunity-list.  */
+  if (! str)
+    {
+      community_list_delete (list);
+      return 0;
+    }
+
+  /* Community list string is specified.  Lookup entry from community
+     list.  */
+  if (style == EXTCOMMUNITY_LIST_STANDARD || style == EXTCOMMUNITY_LIST_AUTO)
+    {
+      ecom = ecommunity_str2com (str, 0, 1);
+      if (ecom)
+       {
+         entry = community_list_entry_lookup (list, ecom, direct);
+         ecommunity_free (ecom);
+       }
+      else if (style == COMMUNITY_LIST_STANDARD)
+       return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
+      /* If we can't convert string into community and community-list
+        type is auto, fall dawn to expanded community-list.  */
+    }
+
+  /* Expanded community-list parse.  String may include regular
+     expression.  */
+  if (! entry 
+      && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
+    {
+      regex = bgp_regcomp (str);
+      if (regex)
+       {
+         entry = community_list_entry_lookup (list, str, direct);
+         bgp_regex_free (regex);
+       }
+      else
+       return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+    }
+
+  if (! entry)
+    return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+  community_list_entry_delete (list, entry, style);
+
+  return 0;
+}
+
+/* Initializa community-list.  Return community-list handler.  */
+struct community_list_handler *
+community_list_init ()
+{
+  struct community_list_handler *ch;
+  ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
+               sizeof (struct community_list_handler));
+  return ch;
+}
+
+/* Terminate community-list.  */
+void
+community_list_terminate (struct community_list_handler *ch)
+{
+  struct community_list_master *cm;
+  struct community_list *list;
+
+  cm = &ch->community_list;
+  while ((list = cm->num.head) != NULL)
+    community_list_delete (list);
+  while ((list = cm->str.head) != NULL)
+    community_list_delete (list);
+
+  cm = &ch->extcommunity_list;
+  while ((list = cm->num.head) != NULL)
+    community_list_delete (list);
+  while ((list = cm->str.head) != NULL)
+    community_list_delete (list);
+
+  XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
+}
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
new file mode 100644 (file)
index 0000000..ffc707c
--- /dev/null
@@ -0,0 +1,143 @@
+/* BGP Community list.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* Community-list deny and permit.  */
+#define COMMUNITY_DENY                 0
+#define COMMUNITY_PERMIT               1
+
+/* Number and string based community-list name.  */
+#define COMMUNITY_LIST_STRING          0
+#define COMMUNITY_LIST_NUMBER          1
+
+/* Community-list entry types.  */
+#define COMMUNITY_LIST_STANDARD        0 /* Standard community-list.  */
+#define COMMUNITY_LIST_EXPANDED        1 /* Expanded community-list.  */
+#define COMMUNITY_LIST_AUTO            2 /* Automatically detected.  */
+#define EXTCOMMUNITY_LIST_STANDARD     3 /* Standard extcommunity-list.  */
+#define EXTCOMMUNITY_LIST_EXPANDED     4 /* Expanded extcommunity-list.  */
+#define EXTCOMMUNITY_LIST_AUTO         5 /* Automatically detected.  */
+
+/* Community-list.  */
+struct community_list
+{
+  /* Name of the community-list.  */
+  char *name;
+
+  /* String or number.  */
+  int sort;
+
+  /* Link to upper list.  */
+  struct community_list_list *parent;
+
+  /* Linked list for other community-list.  */
+  struct community_list *next;
+  struct community_list *prev;
+
+  /* Community-list entry in this community-list.  */
+  struct community_entry *head;
+  struct community_entry *tail;
+};
+
+/* Each entry in community-list.  */
+struct community_entry
+{
+  struct community_entry *next;
+  struct community_entry *prev;
+
+  /* Permit or deny.  */
+  u_char direct;
+
+  /* Standard or expanded.  */
+  u_char style;
+
+  /* Any match.  */
+  u_char any;
+
+  /* Community structure.  */
+  union
+  {
+    struct community *com;
+    struct ecommunity *ecom;
+  } u;
+
+  /* Configuration string.  */
+  char *config;
+
+  /* Expanded community-list regular expression.  */
+  regex_t *reg;
+};
+
+/* Linked list of community-list.  */
+struct community_list_list
+{
+  struct community_list *head;
+  struct community_list *tail;
+};
+
+/* Master structure of community-list and extcommunity-list.  */
+struct community_list_master
+{
+  struct community_list_list num;
+  struct community_list_list str;
+};
+
+/* Community-list handler.  community_list_init() returns this
+   structure as handler.  */
+struct community_list_handler
+{
+  /* Community-list.  */
+  struct community_list_master community_list;
+
+  /* Exteded community-list.  */
+  struct community_list_master extcommunity_list;
+};
+
+/* Error code of community-list.  */
+#define COMMUNITY_LIST_ERR_CANT_FIND_LIST        -1
+#define COMMUNITY_LIST_ERR_MALFORMED_VAL         -2
+#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT     -3
+#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT     -4
+
+/* Handler.  */
+extern struct community_list_handler *bgp_clist;
+
+/* Prototypes.  */
+struct community_list_handler *community_list_init ();
+
+int community_list_set (struct community_list_handler *ch,
+                       char *name, char *str, int direct, int style);
+int community_list_unset (struct community_list_handler *ch,
+                         char *name, char *str, int direct, int style);
+int extcommunity_list_set (struct community_list_handler *ch,
+                          char *name, char *str, int direct, int style);
+int extcommunity_list_unset (struct community_list_handler *ch,
+                            char *name, char *str, int direct, int style);
+
+struct community_list_master *
+community_list_master_lookup (struct community_list_handler *, int);
+
+struct community_list *
+community_list_lookup (struct community_list_handler *, char *, int);
+
+int community_list_match (struct community *, struct community_list *);
+int community_list_exact_match (struct community *, struct community_list *);
+struct community *
+community_list_match_delete (struct community *,
+                            struct community_list *);
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
new file mode 100644 (file)
index 0000000..83b1cc5
--- /dev/null
@@ -0,0 +1,629 @@
+/* Community attribute related functions.
+   Copyright (C) 1998, 2001 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+
+#include "bgpd/bgp_community.h"
+
+/* Hash of community attribute. */
+struct hash *comhash;
+
+/* Allocate a new communities value.  */
+struct community *
+community_new ()
+{
+  return (struct community *) XCALLOC (MTYPE_COMMUNITY,
+                                      sizeof (struct community));
+}
+
+/* Free communities value.  */
+void
+community_free (struct community *com)
+{
+  if (com->val)
+    XFREE (MTYPE_COMMUNITY_VAL, com->val);
+  if (com->str)
+    XFREE (MTYPE_COMMUNITY_STR, com->str);
+  XFREE (MTYPE_COMMUNITY, com);
+}
+
+/* Add one community value to the community. */
+void
+community_add_val (struct community *com, u_int32_t val)
+{
+  com->size++;
+  if (com->val)
+    com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));
+  else
+    com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));
+
+  val = htonl (val);
+  memcpy (com_lastval (com), &val, sizeof (u_int32_t));
+}
+
+/* Delete one community. */
+void
+community_del_val (struct community *com, u_int32_t *val)
+{
+  int i = 0;
+  int c = 0;
+
+  if (! com->val)
+    return;
+
+  while (i < com->size)
+    {
+      if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)
+       {
+         c = com->size -i -1;
+
+         if (c > 0)
+           memcpy (com->val + i, com->val + (i + 1), c * sizeof (val));
+
+         com->size--;
+
+         if (com->size > 0)
+           com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,
+                                com_length (com));
+         else
+           {
+             XFREE (MTYPE_COMMUNITY_VAL, com->val);
+             com->val = NULL;
+           }
+         return;
+       }
+      i++;
+    }
+}
+
+/* Delete all communities listed in com2 from com1 */
+struct community *
+community_delete (struct community *com1, struct community *com2)
+{
+  int i = 0;
+
+  while(i < com2->size)
+    {
+      community_del_val (com1, com2->val + i);
+      i++;
+    }
+
+  return com1;
+}
+
+/* Callback function from qsort(). */
+int
+community_compare (const void *a1, const void *a2)
+{
+  u_int32_t v1;
+  u_int32_t v2;
+
+  memcpy (&v1, a1, sizeof (u_int32_t));
+  memcpy (&v2, a2, sizeof (u_int32_t));
+  v1 = ntohl (v1);
+  v2 = ntohl (v2);
+
+  if (v1 < v2)
+    return -1;
+  if (v1 > v2)
+    return 1;
+  return 0;
+}
+
+int
+community_include (struct community *com, u_int32_t val)
+{
+  int i;
+
+  val = htonl (val);
+
+  for (i = 0; i < com->size; i++)
+    if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)
+      return 1;
+
+  return 0;
+}
+
+u_int32_t
+community_val_get (struct community *com, int i)
+{
+  u_char *p;
+  u_int32_t val;
+
+  p = (u_char *) com->val;
+  p += (i * 4);
+
+  memcpy (&val, p, sizeof (u_int32_t));
+
+  return ntohl (val);
+}
+
+/* Sort and uniq given community. */
+struct community *
+community_uniq_sort (struct community *com)
+{
+  int i;
+  struct community *new;
+  u_int32_t val;
+
+  if (! com)
+    return NULL;
+  
+  new = community_new ();;
+  
+  for (i = 0; i < com->size; i++)
+    {
+      val = community_val_get (com, i);
+
+      if (! community_include (new, val))
+       community_add_val (new, val);
+    }
+
+  qsort (new->val, new->size, sizeof (u_int32_t), community_compare);
+
+  return new;
+}
+
+/* Convert communities attribute to string.
+
+   For Well-known communities value, below keyword is used.
+
+   0x0             "internet"    
+   0xFFFFFF01      "no-export"
+   0xFFFFFF02      "no-advertise"
+   0xFFFFFF03      "local-AS"
+
+   For other values, "AS:VAL" format is used.  */
+static char *
+community_com2str  (struct community *com)
+{
+  int i;
+  char *str;
+  char *pnt;
+  int len;
+  int first;
+  u_int32_t comval;
+  u_int16_t as;
+  u_int16_t val;
+
+  /* When communities attribute is empty.  */
+  if (com->size == 0)
+    {
+      str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
+      str[0] = '\0';
+      return str;
+    }
+
+  /* Memory allocation is time consuming work.  So we calculate
+     required string length first.  */
+  len = 0;
+
+  for (i = 0; i < com->size; i++)
+    {
+      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
+      comval = ntohl (comval);
+
+      switch (comval) 
+       {
+       case COMMUNITY_INTERNET:
+         len += strlen (" internet");
+         break;
+       case COMMUNITY_NO_EXPORT:
+         len += strlen (" no-export");
+         break;
+       case COMMUNITY_NO_ADVERTISE:
+         len += strlen (" no-advertise");
+         break;
+       case COMMUNITY_LOCAL_AS:
+         len += strlen (" local-AS");
+         break;
+       default:
+         len += strlen (" 65536:65535");
+         break;
+       }
+    }
+
+  /* Allocate memory.  */
+  str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
+  first = 1;
+
+  /* Fill in string.  */
+  for (i = 0; i < com->size; i++)
+    {
+      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
+      comval = ntohl (comval);
+
+      if (first)
+       first = 0;
+      else
+       *pnt++ = ' ';
+
+      switch (comval) 
+       {
+       case COMMUNITY_INTERNET:
+         strcpy (pnt, "internet");
+         pnt += strlen ("internet");
+         break;
+       case COMMUNITY_NO_EXPORT:
+         strcpy (pnt, "no-export");
+         pnt += strlen ("no-export");
+         break;
+       case COMMUNITY_NO_ADVERTISE:
+         strcpy (pnt, "no-advertise");
+         pnt += strlen ("no-advertise");
+         break;
+       case COMMUNITY_LOCAL_AS:
+         strcpy (pnt, "local-AS");
+         pnt += strlen ("local-AS");
+         break;
+       default:
+         as = (comval >> 16) & 0xFFFF;
+         val = comval & 0xFFFF;
+         sprintf (pnt, "%d:%d", as, val);
+         pnt += strlen (pnt);
+         break;
+       }
+    }
+  *pnt = '\0';
+
+  return str;
+}
+
+/* Intern communities attribute.  */
+struct community *
+community_intern (struct community *com)
+{
+  struct community *find;
+
+  /* Assert this community structure is not interned. */
+  assert (com->refcnt == 0);
+
+  /* Lookup community hash. */
+  find = (struct community *) hash_get (comhash, com, hash_alloc_intern);
+
+  /* Arguemnt com is allocated temporary.  So when it is not used in
+     hash, it should be freed.  */
+  if (find != com)
+    community_free (com);
+
+  /* Increment refrence counter.  */
+  find->refcnt++;
+
+  /* Make string.  */
+  if (! find->str)
+    find->str = community_com2str (find);
+
+  return find;
+}
+
+/* Free community attribute. */
+void
+community_unintern (struct community *com)
+{
+  struct community *ret;
+
+  if (com->refcnt)
+    com->refcnt--;
+
+  /* Pull off from hash.  */
+  if (com->refcnt == 0)
+    {
+      /* Community value com must exist in hash. */
+      ret = (struct community *) hash_release (comhash, com);
+      assert (ret != NULL);
+
+      community_free (com);
+    }
+}
+
+/* Create new community attribute. */
+struct community *
+community_parse (char *pnt, u_short length)
+{
+  struct community tmp;
+  struct community *new;
+
+  /* If length is malformed return NULL. */
+  if (length % 4)
+    return NULL;
+
+  /* Make temporary community for hash look up. */
+  tmp.size = length / 4;
+  tmp.val = (u_int32_t *) pnt;
+
+  new = community_uniq_sort (&tmp);
+
+  return community_intern (new);
+}
+
+struct community *
+community_dup (struct community *com)
+{
+  struct community *new;
+
+  new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));
+  new->size = com->size;
+  if (new->size)
+    {
+      new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
+      memcpy (new->val, com->val, com->size * 4);
+    }
+  else
+    new->val = NULL;
+  return new;
+}
+
+/* Retrun string representation of communities attribute. */
+char *
+community_str (struct community *com)
+{
+  if (! com->str)
+    com->str = community_com2str (com);
+  return com->str;
+}
+
+/* Make hash value of community attribute. This function is used by
+   hash package.*/
+unsigned int
+community_hash_make (struct community *com)
+{
+  int c;
+  unsigned int key;
+  unsigned char *pnt;
+
+  key = 0;
+  pnt = (unsigned char *)com->val;
+  
+  for(c = 0; c < com->size * 4; c++)
+    key += pnt[c];
+      
+  return key;
+}
+
+int
+community_match (struct community *com1, struct community *com2)
+{
+  int i = 0;
+  int j = 0;
+
+  if (com1 == NULL && com2 == NULL)
+    return 1;
+
+  if (com1 == NULL || com2 == NULL)
+    return 0;
+
+  if (com1->size < com2->size)
+    return 0;
+
+  /* Every community on com2 needs to be on com1 for this to match */
+  while (i < com1->size && j < com2->size)
+    {
+      if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)
+       j++;
+      i++;
+    }
+
+  if (j == com2->size)
+    return 1;
+  else
+    return 0;
+}
+
+/* If two aspath have same value then return 1 else return 0. This
+   function is used by hash package. */
+int
+community_cmp (struct community *com1, struct community *com2)
+{
+  if (com1 == NULL && com2 == NULL)
+    return 1;
+  if (com1 == NULL || com2 == NULL)
+    return 0;
+
+  if (com1->size == com2->size)
+    if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
+      return 1;
+  return 0;
+}
+
+/* Add com2 to the end of com1. */
+struct community *
+community_merge (struct community *com1, struct community *com2)
+{
+  if (com1->val)
+    com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val, 
+                         (com1->size + com2->size) * 4);
+  else
+    com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);
+
+  memcpy (com1->val + com1->size, com2->val, com2->size * 4);
+  com1->size += com2->size;
+
+  return com1;
+}
+
+/* Community token enum. */
+enum community_token
+{
+  community_token_val,
+  community_token_no_export,
+  community_token_no_advertise,
+  community_token_local_as,
+  community_token_unknown
+};
+
+/* Get next community token from string. */
+char *
+community_gettoken (char *buf, enum community_token *token, u_int32_t *val)
+{
+  char *p = buf;
+
+  /* Skip white space. */
+  while (isspace ((int) *p))
+    p++;
+
+  /* Check the end of the line. */
+  if (*p == '\0')
+    return NULL;
+
+  /* Well known community string check. */
+  if (isalpha ((int) *p)) 
+    {
+      if (strncmp (p, "internet", strlen ("internet")) == 0)
+       {
+         *val = COMMUNITY_INTERNET;
+         *token = community_token_no_export;
+         p += strlen ("internet");
+         return p;
+       }
+      if (strncmp (p, "no-export", strlen ("no-export")) == 0)
+       {
+         *val = COMMUNITY_NO_EXPORT;
+         *token = community_token_no_export;
+         p += strlen ("no-export");
+         return p;
+       }
+      if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)
+       {
+         *val = COMMUNITY_NO_ADVERTISE;
+         *token = community_token_no_advertise;
+         p += strlen ("no-advertise");
+         return p;
+       }
+      if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)
+       {
+         *val = COMMUNITY_LOCAL_AS;
+         *token = community_token_local_as;
+         p += strlen ("local-AS");
+         return p;
+       }
+
+      /* Unknown string. */
+      *token = community_token_unknown;
+      return p;
+    }
+
+  /* Community value. */
+  if (isdigit ((int) *p)) 
+    {
+      int separator = 0;
+      int digit = 0;
+      u_int32_t community_low = 0;
+      u_int32_t community_high = 0;
+
+      while (isdigit ((int) *p) || *p == ':') 
+       {
+         if (*p == ':') 
+           {
+             if (separator)
+               {
+                 *token = community_token_unknown;
+                 return p;
+               }
+             else
+               {
+                 separator = 1;
+                 digit = 0;
+                 community_high = community_low << 16;
+                 community_low = 0;
+               }
+           }
+         else 
+           {
+             digit = 1;
+             community_low *= 10;
+             community_low += (*p - '0');
+           }
+         p++;
+       }
+      if (! digit)
+       {
+         *token = community_token_unknown;
+         return p;
+       }
+      *val = community_high + community_low;
+      *token = community_token_val;
+      return p;
+    }
+  *token = community_token_unknown;
+  return p;
+}
+
+/* convert string to community structure */
+struct community *
+community_str2com (char *str)
+{
+  struct community *com = NULL;
+  struct community *com_sort = NULL;
+  u_int32_t val;
+  enum community_token token;
+
+  while ((str = community_gettoken (str, &token, &val))) 
+    {
+      switch (token)
+       {
+       case community_token_val:
+       case community_token_no_export:
+       case community_token_no_advertise:
+       case community_token_local_as:
+         if (com == NULL)
+           com = community_new();
+         community_add_val (com, val);
+         break;
+       case community_token_unknown:
+       default:
+         if (com)
+           community_free (com);
+         return NULL;
+         break;
+       }
+    }
+  
+  if (! com)
+    return NULL;
+
+  com_sort = community_uniq_sort (com);
+  community_free (com);
+
+  return com_sort;
+}
+
+/* Return communities hash entry count.  */
+unsigned long
+community_count ()
+{
+  return comhash->count;
+}
+
+/* Return communities hash.  */
+struct hash *
+community_hash ()
+{
+  return comhash;
+}
+
+/* Initialize comminity related hash. */
+void
+community_init ()
+{
+  comhash = hash_create (community_hash_make, community_cmp);
+}
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
new file mode 100644 (file)
index 0000000..58b3f9e
--- /dev/null
@@ -0,0 +1,68 @@
+/* Community attribute related functions.
+   Copyright (C) 1998 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* Communities attribute.  */
+struct community 
+{
+  /* Reference count of communities value.  */
+  unsigned long refcnt;
+
+  /* Communities value size.  */
+  int size;
+
+  /* Communities value.  */
+  u_int32_t *val;
+
+  /* String of community attribute.  This sring is used by vty output
+     and expanded community-list for regular expression match.  */
+  char *str;
+};
+
+/* Well-known communities value.  */
+#define COMMUNITY_INTERNET              0x0
+#define COMMUNITY_NO_EXPORT             0xFFFFFF01
+#define COMMUNITY_NO_ADVERTISE          0xFFFFFF02
+#define COMMUNITY_NO_EXPORT_SUBCONFED   0xFFFFFF03
+#define COMMUNITY_LOCAL_AS              0xFFFFFF03
+
+/* Macros of community attribute.  */
+#define com_length(X)    ((X)->size * 4)
+#define com_lastval(X)   ((X)->val + (X)->size - 1)
+#define com_nthval(X,n)  ((X)->val + (n))
+
+/* Prototypes of communities attribute functions.  */
+void community_init ();
+void community_free (struct community *);
+struct community *community_uniq_sort (struct community *);
+struct community *community_parse (char *, u_short);
+struct community *community_intern (struct community *);
+void community_unintern (struct community *);
+char *community_str (struct community *);
+unsigned int community_hash_make (struct community *);
+struct community *community_str2com (char *);
+int community_match (struct community *, struct community *);
+int community_cmp (struct community *, struct community *);
+struct community *community_merge (struct community *, struct community *);
+struct community *community_delete (struct community *, struct community *);
+struct community *community_dup (struct community *);
+int community_include (struct community *, u_int32_t);
+void community_del_val (struct community *, u_int32_t *);
+unsigned long community_count ();
+struct hash *community_hash ();
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
new file mode 100644 (file)
index 0000000..d70105f
--- /dev/null
@@ -0,0 +1,648 @@
+/* BGP flap dampening
+   Copyright (C) 2001 IP Infusion Inc.
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+#include <math.h>
+
+#include "prefix.h"
+#include "memory.h"
+#include "command.h"
+#include "log.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h" 
+#include "bgpd/bgp_advertise.h"
+
+/* Global variable to access damping configuration */
+struct bgp_damp_config bgp_damp_cfg;
+struct bgp_damp_config *damp = &bgp_damp_cfg;
+
+/* Utility macro to add and delete BGP dampening information to no
+   used list.  */
+#define BGP_DAMP_LIST_ADD(N,A)  BGP_INFO_ADD(N,A,no_reuse_list)
+#define BGP_DAMP_LIST_DEL(N,A)  BGP_INFO_DEL(N,A,no_reuse_list)
+\f
+/* Calculate reuse list index by penalty value.  */
+static int
+bgp_reuse_index (int penalty)
+{
+  int i;
+  int index;
+
+  i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor);
+  
+  if ( i >= damp->reuse_index_size )
+    i = damp->reuse_index_size - 1;
+
+  index = damp->reuse_index[i] - damp->reuse_index[0];
+
+  return (damp->reuse_offset + index) % damp->reuse_list_size;  
+}
+
+/* Add BGP dampening information to reuse list.  */
+static void 
+bgp_reuse_list_add (struct bgp_damp_info *bdi)
+{
+  int index;
+
+  index = bdi->index = bgp_reuse_index (bdi->penalty);
+
+  bdi->prev = NULL;
+  bdi->next = damp->reuse_list[index];
+  if (damp->reuse_list[index])
+    damp->reuse_list[index]->prev = bdi;
+  damp->reuse_list[index] = bdi;
+}
+
+/* Delete BGP dampening information from reuse list.  */
+static void
+bgp_reuse_list_delete (struct bgp_damp_info *bdi)
+{
+  if (bdi->next)
+    bdi->next->prev = bdi->prev;
+  if (bdi->prev)
+    bdi->prev->next = bdi->next;
+  else
+    damp->reuse_list[bdi->index] = bdi->next;
+}   
+\f
+/* Return decayed penalty value.  */
+int 
+bgp_damp_decay (time_t tdiff, int penalty)
+{
+  int i;
+
+  i = (int) ((double) tdiff / DELTA_T);
+
+  if (i == 0)
+    return penalty; 
+  
+  if (i >= damp->decay_array_size)
+    return 0;
+
+  return (int) (penalty * damp->decay_array[i]);
+}
+
+/* Handler of reuse timer event.  Each route in the current reuse-list
+   is evaluated.  RFC2439 Section 4.8.7.  */
+int
+bgp_reuse_timer (struct thread *t)
+{
+  struct bgp_damp_info *bdi;
+  struct bgp_damp_info *next;
+  time_t t_now, t_diff;
+  struct bgp *bgp;
+  int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
+
+  damp->t_reuse = NULL;
+  damp->t_reuse =
+    thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
+
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return 0;
+
+  t_now = time (NULL);
+
+  /* 1.  save a pointer to the current zeroth queue head and zero the
+     list head entry.  */
+  bdi = damp->reuse_list[damp->reuse_offset];
+  damp->reuse_list[damp->reuse_offset] = NULL;
+
+  /* 2.  set offset = modulo reuse-list-size ( offset + 1 ), thereby
+     rotating the circular queue of list-heads.  */
+  damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
+
+  /* 3. if ( the saved list head pointer is non-empty ) */
+  for (; bdi; bdi = next)
+    {
+      next = bdi->next;
+
+      /* Set t-diff = t-now - t-updated.  */
+      t_diff = t_now - bdi->t_updated;
+
+      /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
+      bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);   
+
+      /* Set t-updated = t-now.  */
+      bdi->t_updated = t_now;
+
+      /* if (figure-of-merit < reuse).  */
+      if (bdi->penalty < damp->reuse_limit)
+       {
+         /* Reuse the route.  */
+         UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED);
+         bdi->suppress_time = 0;
+
+         if (bdi->lastrecord == BGP_RECORD_UPDATE)
+           {
+             UNSET_FLAG (bdi->binfo->flags, BGP_INFO_HISTORY);
+             bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
+                                      bdi->afi, bdi->safi);   
+             bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
+           }
+
+         if (bdi->penalty <= damp->reuse_limit / 2.0)
+           bgp_damp_info_free (bdi, 1);
+         else
+           BGP_DAMP_LIST_ADD (damp, bdi);
+       }
+      else
+       /* Re-insert into another list (See RFC2439 Section 4.8.6).  */
+       bgp_reuse_list_add (bdi);
+    }
+
+  return 0;
+}
+
+/* A route becomes unreachable (RFC2439 Section 4.8.2).  */
+int
+bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
+                  afi_t afi, safi_t safi, int attr_change)
+{
+  time_t t_now;
+  struct bgp_damp_info *bdi;
+  double last_penalty = 0;
+  
+  t_now = time (NULL);
+
+  /* Processing Unreachable Messages.  */
+  bdi = binfo->damp_info;
+
+  if (bdi == NULL)
+    {
+      /* If there is no previous stability history. */
+
+      /* RFC2439 said:
+        1. allocate a damping structure.
+         2. set figure-of-merit = 1.
+         3. withdraw the route.  */
+
+      bdi =  XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
+      bdi->binfo = binfo;
+      bdi->rn = rn;
+      bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
+      bdi->flap = 1;
+      bdi->start_time = t_now;
+      bdi->suppress_time = 0;
+      bdi->index = -1;
+      bdi->afi = afi;
+      bdi->safi = safi;
+      binfo->damp_info = bdi;
+      BGP_DAMP_LIST_ADD (damp, bdi);
+    }
+  else
+    {
+      last_penalty = bdi->penalty;
+
+      /* 1. Set t-diff = t-now - t-updated.  */
+      bdi->penalty = 
+       (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty) 
+        + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
+
+      if (bdi->penalty > damp->ceiling)
+       bdi->penalty = damp->ceiling;
+
+      bdi->flap++;
+    }
+  
+  bdi->lastrecord = BGP_RECORD_WITHDRAW;
+  bdi->t_updated = t_now;
+
+  /* Make this route as historical status.  */
+  SET_FLAG (binfo->flags, BGP_INFO_HISTORY);
+
+  /* Remove the route from a reuse list if it is on one.  */
+  if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED))
+    {
+      /* If decay rate isn't equal to 0, reinsert brn. */  
+      if (bdi->penalty != last_penalty)
+       {
+         bgp_reuse_list_delete (bdi);
+         bgp_reuse_list_add (bdi);  
+       }
+      return BGP_DAMP_SUPPRESSED; 
+    }
+
+  /* If not suppressed before, do annonunce this withdraw and
+     insert into reuse_list.  */
+  if (bdi->penalty >= damp->suppress_value)
+    {
+      SET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED);
+      bdi->suppress_time = t_now;
+      BGP_DAMP_LIST_DEL (damp, bdi);
+      bgp_reuse_list_add (bdi);
+    }
+
+  return BGP_DAMP_USED;
+}
+
+int
+bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn, 
+                afi_t afi, safi_t safi)
+{
+  time_t t_now;
+  struct bgp_damp_info *bdi;
+  int status;
+
+  bdi = binfo->damp_info;
+  if (! bdi)
+    return BGP_DAMP_USED;
+
+  t_now = time (NULL);
+  UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); 
+
+  bdi->lastrecord = BGP_RECORD_UPDATE;
+  bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
+
+  if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
+      && (bdi->penalty < damp->suppress_value))
+    status = BGP_DAMP_USED;
+  else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
+          && (bdi->penalty < damp->reuse_limit) )
+    {
+      UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED);
+      bgp_reuse_list_delete (bdi);
+      BGP_DAMP_LIST_ADD (damp, bdi);
+      bdi->suppress_time = 0;
+      status = BGP_DAMP_USED;
+    }
+  else
+    status = BGP_DAMP_SUPPRESSED;  
+
+  if (bdi->penalty > damp->reuse_limit / 2.0)
+    bdi->t_updated = t_now;
+  else
+    bgp_damp_info_free (bdi, 0);
+       
+  return status;
+}
+
+/* Remove dampening information and history route.  */
+int 
+bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
+{
+  time_t t_now, t_diff;
+  struct bgp_damp_info *bdi;
+
+  t_now = time (NULL);
+  bdi = binfo->damp_info;
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+    {
+      t_diff = t_now - bdi->suppress_time;
+
+      if (t_diff >= damp->max_suppress_time)
+        {
+          UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED);
+          bgp_reuse_list_delete (bdi);
+         BGP_DAMP_LIST_ADD (damp, bdi);
+          bdi->penalty = damp->reuse_limit;
+          bdi->suppress_time = 0;
+          bdi->t_updated = t_now;
+          
+          /* Need to announce UPDATE once this binfo is usable again. */
+          if (bdi->lastrecord == BGP_RECORD_UPDATE)
+            return 1;
+          else
+            return 0;
+        }
+    }
+  else
+    {
+      t_diff = t_now - bdi->t_updated;
+      bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
+
+      if (bdi->penalty <= damp->reuse_limit / 2.0)
+        {
+          /* release the bdi, bdi->binfo. */  
+          bgp_damp_info_free (bdi, 1);
+          return 0;
+        }            
+      else
+        bdi->t_updated = t_now;
+    }       
+  return 0;
+}
+
+void
+bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
+{
+  struct bgp_info *binfo;
+  void bgp_info_delete (struct bgp_node *, struct bgp_info *);
+  void bgp_info_free (struct bgp_info *);
+
+  if (! bdi)
+    return;
+
+  binfo = bdi->binfo;
+  binfo->damp_info = NULL;
+
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+    bgp_reuse_list_delete (bdi);
+  else
+    BGP_DAMP_LIST_DEL (damp, bdi);
+
+  UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED);
+  UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY);
+
+  if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
+    {
+      bgp_info_delete (bdi->rn, binfo);
+      bgp_info_free (binfo);
+      bgp_unlock_node (bdi->rn);
+    }
+  XFREE (MTYPE_BGP_DAMP_INFO, bdi);
+}
+
+void
+bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
+{
+  double reuse_max_ratio;
+  int i;
+  double j;
+       
+  damp->suppress_value = sup;
+  damp->half_life = hlife;
+  damp->reuse_limit = reuse;
+  damp->max_suppress_time = maxsup;
+
+  /* Initialize params per bgp_damp_config. */
+  damp->reuse_index_size = REUSE_ARRAY_SIZE;
+
+  damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life))); 
+
+  /* Decay-array computations */
+  damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
+  damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
+                              sizeof(double) * (damp->decay_array_size));
+  damp->decay_array[0] = 1.0;
+  damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5));
+
+  /* Calculate decay values for all possible times */
+  for (i = 2; i < damp->decay_array_size; i++)
+    damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
+       
+  /* Reuse-list computations */
+  i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
+  if (i > REUSE_LIST_SIZE || i == 0)
+    i = REUSE_LIST_SIZE;
+  damp->reuse_list_size = i; 
+
+  damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY, 
+                             damp->reuse_list_size 
+                             * sizeof (struct bgp_reuse_node *));
+  memset (damp->reuse_list, 0x00, 
+          damp->reuse_list_size * sizeof (struct bgp_reuse_node *));  
+
+  /* Reuse-array computations */
+  damp->reuse_index = XMALLOC (MTYPE_BGP_DAMP_ARRAY, 
+                              sizeof(int) * damp->reuse_index_size);
+  memset (damp->reuse_index, 0x00,
+          damp->reuse_list_size * sizeof (int));
+
+  reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
+  j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
+  if ( reuse_max_ratio > j && j != 0 )
+    reuse_max_ratio = j;
+
+  damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
+
+  for (i = 0; i < damp->reuse_index_size; i++)
+    {
+      damp->reuse_index[i] = 
+       (int)(((double)damp->half_life / DELTA_REUSE)
+             * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
+    }
+}
+
+int
+bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, int half,
+                int reuse, int suppress, int max)
+{
+  if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
+    {
+      if (damp->half_life == half
+         && damp->reuse_limit == reuse
+         && damp->suppress_value == suppress
+         && damp->max_suppress_time == max)
+       return 0;
+      bgp_damp_disable (bgp, afi, safi);
+    }
+
+  SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
+  bgp_damp_parameter_set (half, reuse, suppress, max);
+
+  /* Register reuse timer.  */
+  if (! damp->t_reuse)
+    damp->t_reuse = 
+      thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
+
+  return 0;
+}
+
+void
+bgp_damp_config_clean (struct bgp_damp_config *damp)
+{
+  /* Free decay array */
+  XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
+
+  /* Free reuse index array */
+  XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
+
+  /* Free reuse list array. */
+  XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
+}
+
+/* Clean all the bgp_damp_info stored in reuse_list. */
+void
+bgp_damp_info_clean ()
+{
+  int i;
+  struct bgp_damp_info *bdi, *next;
+
+  damp->reuse_offset = 0;
+
+  for (i = 0; i < damp->reuse_list_size; i++)
+    {
+      if (! damp->reuse_list[i])
+       continue;
+
+      for (bdi = damp->reuse_list[i]; bdi; bdi = next)
+       {
+         next = bdi->next;
+         bgp_damp_info_free (bdi, 1);
+       }
+      damp->reuse_list[i] = NULL;
+    }
+
+  for (bdi = damp->no_reuse_list; bdi; bdi = next)
+    {
+      next = bdi->next;
+      bgp_damp_info_free (bdi, 1);
+    }
+  damp->no_reuse_list = NULL;
+}
+
+int
+bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
+{
+  /* Cancel reuse thread. */
+  if (damp->t_reuse )
+    thread_cancel (damp->t_reuse);
+  damp->t_reuse = NULL;
+
+  /* Clean BGP dampening information.  */
+  bgp_damp_info_clean ();
+
+  /* Clear configuration */
+  bgp_damp_config_clean (&bgp_damp_cfg);
+
+  UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
+  return 0;
+}
+
+int
+bgp_config_write_damp (struct vty *vty)
+{
+  if (&bgp_damp_cfg)
+    {
+      if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60
+         && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
+         && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
+         && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
+       vty_out (vty, " bgp dampening%s", VTY_NEWLINE);
+      else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
+              && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
+              && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
+              && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
+       vty_out (vty, " bgp dampening %d%s",
+                bgp_damp_cfg.half_life/60,
+                VTY_NEWLINE);
+      else
+       vty_out (vty, " bgp dampening %d %d %d %d%s",
+                bgp_damp_cfg.half_life/60,
+                bgp_damp_cfg.reuse_limit,
+                bgp_damp_cfg.suppress_value,
+                bgp_damp_cfg.max_suppress_time/60,
+                VTY_NEWLINE);
+      return 1;
+    }
+  return 0;
+}
+
+#define BGP_UPTIME_LEN 25
+
+char *
+bgp_get_reuse_time (int penalty, char *buf, size_t len)
+{
+  time_t reuse_time = 0;
+  struct tm *tm = NULL;
+
+  if (penalty > damp->reuse_limit)
+    {
+      reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1])))); 
+
+      if (reuse_time > damp->max_suppress_time)
+       reuse_time = damp->max_suppress_time;
+
+      tm = gmtime (&reuse_time);
+    }
+  else 
+    reuse_time = 0;
+
+  /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+  if (reuse_time == 0)
+    snprintf (buf, len, "00:00:00");
+  else if (reuse_time < ONE_DAY_SECOND)
+    snprintf (buf, len, "%02d:%02d:%02d", 
+              tm->tm_hour, tm->tm_min, tm->tm_sec);
+  else if (reuse_time < ONE_WEEK_SECOND)
+    snprintf (buf, len, "%dd%02dh%02dm", 
+              tm->tm_yday, tm->tm_hour, tm->tm_min);
+  else
+    snprintf (buf, len, "%02dw%dd%02dh", 
+              tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); 
+
+  return buf;
+}
+void
+bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)  
+{
+  struct bgp_damp_info *bdi;
+  time_t t_now, t_diff;
+  char timebuf[BGP_UPTIME_LEN];
+  int penalty;
+
+  /* BGP dampening information.  */
+  bdi = binfo->damp_info;
+
+  /* If dampening is not enabled or there is no dampening information,
+     return immediately.  */
+  if (! damp || ! bdi)
+    return;
+
+  /* Calculate new penalty.  */
+  t_now = time (NULL);
+  t_diff = t_now - bdi->t_updated;
+  penalty = bgp_damp_decay (t_diff, bdi->penalty);
+
+  vty_out (vty, "      Dampinfo: penalty %d, flapped %d times in %s",
+           penalty, bdi->flap,
+          peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
+
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
+      && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, ", reuse in %s",
+            bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+char *
+bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo)
+{
+  struct bgp_damp_info *bdi;
+  time_t t_now, t_diff;
+  char timebuf[BGP_UPTIME_LEN];
+  int penalty;
+
+  /* BGP dampening information.  */
+  bdi = binfo->damp_info;
+
+  /* If dampening is not enabled or there is no dampening information,
+     return immediately.  */
+  if (! damp || ! bdi)
+    return NULL;
+
+  /* Calculate new penalty.  */
+  t_now = time (NULL);
+  t_diff = t_now - bdi->t_updated;
+  penalty = bgp_damp_decay (t_diff, bdi->penalty);
+
+  return  bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN);
+}
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
new file mode 100644 (file)
index 0000000..f3b9bd6
--- /dev/null
@@ -0,0 +1,141 @@
+/* BGP flap dampening
+   Copyright (C) 2001 IP Infusion Inc.
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* Structure maintained on a per-route basis. */
+struct bgp_damp_info
+{
+  /* Doubly linked list.  This information must be linked to
+     reuse_list or no_reuse_list.  */
+  struct bgp_damp_info *next;
+  struct bgp_damp_info *prev;
+
+  /* Figure-of-merit.  */
+  int penalty;
+
+  /* Number of flapping.  */
+  int flap;
+       
+  /* First flap time  */
+  time_t start_time;
+  /* Last time penalty was updated.  */
+  time_t t_updated;
+
+  /* Time of route start to be suppressed.  */
+  time_t suppress_time;
+
+  /* Back reference to bgp_info. */
+  struct bgp_info *binfo;
+
+  /* Back reference to bgp_node. */
+  struct bgp_node *rn;
+
+  /* Current index in the reuse_list. */
+  int index;
+
+  /* Last time message type. */
+  u_char lastrecord;
+#define BGP_RECORD_UPDATE      1
+#define BGP_RECORD_WITHDRAW    2
+
+  afi_t afi;
+  safi_t safi;
+};
+
+/* Specified parameter set configuration. */
+struct bgp_damp_config
+{
+  /* Value over which routes suppressed.  */
+  int suppress_value;
+
+  /* Value below which suppressed routes reused.  */
+  int reuse_limit;    
+
+  /* Max time a route can be suppressed.  */
+  int max_suppress_time;      
+
+  /* Time during which accumulated penalty reduces by half.  */
+  int half_life; 
+
+  /* Non-configurable parameters but fixed at implementation time.
+   * To change this values, init_bgp_damp() should be modified.
+   */
+  int tmax;              /* Max time previous instability retained */
+  int reuse_list_size;         /* Number of reuse lists */
+  int reuse_index_size;                /* Size of reuse index array */
+
+  /* Non-configurable parameters.  Most of these are calculated from
+   * the configurable parameters above.
+   */
+  unsigned int ceiling;                /* Max value a penalty can attain */
+  int decay_rate_per_tick;     /* Calculated from half-life */
+  int decay_array_size;                /* Calculated using config parameters */
+  double scale_factor;
+  int reuse_scale_factor; 
+         
+  /* Decay array per-set based. */ 
+  double *decay_array; 
+
+  /* Reuse index array per-set based. */ 
+  int *reuse_index;
+
+  /* Reuse list array per-set based. */  
+  struct bgp_damp_info **reuse_list;
+  int reuse_offset;
+        
+  /* All dampening information which is not on reuse list.  */
+  struct bgp_damp_info *no_reuse_list;
+
+  /* Reuse timer thread per-set base. */
+  struct thread* t_reuse;
+};
+
+#define BGP_DAMP_NONE           0
+#define BGP_DAMP_USED          1
+#define BGP_DAMP_SUPPRESSED    2
+
+/* Time granularity for reuse lists */
+#define DELTA_REUSE              10
+
+/* Time granularity for decay arrays */
+#define DELTA_T                   5
+
+#define DEFAULT_PENALTY         1000
+
+#define DEFAULT_HALF_LIFE         15
+#define DEFAULT_REUSE           750
+#define DEFAULT_SUPPRESS       2000
+
+#define REUSE_LIST_SIZE          256
+#define REUSE_ARRAY_SIZE        1024
+
+int bgp_damp_enable (struct bgp *, afi_t, safi_t, int, int, int, int);
+int bgp_damp_disable (struct bgp *, afi_t, safi_t);
+int bgp_damp_withdraw (struct bgp_info *, struct bgp_node *,
+                      afi_t, safi_t, int);
+int bgp_damp_update (struct bgp_info *, struct bgp_node *, afi_t, safi_t);
+int bgp_damp_scan (struct bgp_info *, afi_t, safi_t);
+void bgp_damp_info_free (struct bgp_damp_info *, int);
+void bgp_damp_info_clean ();
+char * bgp_get_reuse_time (int, char*, size_t);
+int bgp_damp_decay (time_t, int);
+int bgp_config_write_damp (struct vty *);
+void bgp_damp_info_vty (struct vty *, struct bgp_info *);
+char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *);
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
new file mode 100644 (file)
index 0000000..bb1a610
--- /dev/null
@@ -0,0 +1,732 @@
+/* BGP-4, BGP-4+ packet debug routine
+   Copyright (C) 1996, 97, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "version.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "stream.h"
+#include "command.h"
+#include "str.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_community.h"
+
+unsigned long conf_bgp_debug_fsm;
+unsigned long conf_bgp_debug_events;
+unsigned long conf_bgp_debug_packet;
+unsigned long conf_bgp_debug_filter;
+unsigned long conf_bgp_debug_keepalive;
+unsigned long conf_bgp_debug_update;
+unsigned long conf_bgp_debug_normal;
+
+unsigned long term_bgp_debug_fsm;
+unsigned long term_bgp_debug_events;
+unsigned long term_bgp_debug_packet;
+unsigned long term_bgp_debug_filter;
+unsigned long term_bgp_debug_keepalive;
+unsigned long term_bgp_debug_update;
+unsigned long term_bgp_debug_normal;
+
+/* messages for BGP-4 status */
+struct message bgp_status_msg[] = 
+{
+  { 0, "null" },
+  { Idle, "Idle" },
+  { Connect, "Connect" },
+  { Active, "Active" },
+  { OpenSent, "OpenSent" },
+  { OpenConfirm, "OpenConfirm" },
+  { Established, "Established" },
+};
+int bgp_status_msg_max = BGP_STATUS_MAX;
+
+/* BGP message type string. */
+char *bgp_type_str[] =
+{
+  NULL,
+  "OPEN",
+  "UPDATE",
+  "NOTIFICATION",
+  "KEEPALIVE",
+  "ROUTE-REFRESH",
+  "CAPABILITY"
+};
+
+/* message for BGP-4 Notify */
+struct message bgp_notify_msg[] = 
+{
+  { 0, "" },
+  { BGP_NOTIFY_HEADER_ERR, "Message Header Error"},
+  { BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"},
+  { BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"},
+  { BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"},
+  { BGP_NOTIFY_FSM_ERR, "Finite State Machine Error"},
+  { BGP_NOTIFY_CEASE, "Cease"},
+  { BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"},
+};
+int bgp_notify_msg_max = BGP_NOTIFY_MAX;
+
+struct message bgp_notify_head_msg[] = 
+{
+  { 0, "null"},
+  { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized."},
+  { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length."},
+  { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type."}
+};
+int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX;
+
+struct message bgp_notify_open_msg[] = 
+{
+  { 0, "null" },
+  { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number." },
+  { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS."},
+  { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier."},
+  { BGP_NOTIFY_OPEN_UNSUP_PARAM, "/Unsupported Optional Parameter."},
+  { BGP_NOTIFY_OPEN_AUTH_FAILURE, "/Authentication Failure."},
+  { BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, "/Unacceptable Hold Time."}, 
+  { BGP_NOTIFY_OPEN_UNSUP_CAPBL, "/Unsupported Capability."},
+};
+int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX;
+
+struct message bgp_notify_update_msg[] = 
+{
+  { 0, "null"}, 
+  { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List."},
+  { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute."},
+  { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute."},
+  { BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, "/Attribute Flags Error."},
+  { BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, "/Attribute Length Error."},
+  { BGP_NOTIFY_UPDATE_INVAL_ORIGIN, "/Invalid ORIGIN Attribute."},
+  { BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP, "/AS Routing Loop."},
+  { BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, "/Invalid NEXT_HOP Attribute."},
+  { BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error."},
+  { BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field."},
+  { BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH."},
+};
+int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX;
+
+struct message bgp_notify_cease_msg[] =
+{
+  { 0, ""},
+  { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached."},
+  { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown."},
+  { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured."},
+  { BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administratively Reset."},
+  { BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected."},
+  { BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change."},
+};
+int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX;
+
+struct message bgp_notify_capability_msg[] = 
+{
+  { 0, "null" },
+  { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value." },
+  { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length."},
+  { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value."},
+};
+int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX;
+
+/* Origin strings. */
+char *bgp_origin_str[] = {"i","e","?"};
+char *bgp_origin_long_str[] = {"IGP","EGP","incomplete"};
+
+/* Dump attribute. */
+void
+bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
+{
+
+  if (! attr)
+    return;
+
+  snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop));
+  snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s",
+           bgp_origin_str[attr->origin]);
+
+#ifdef HAVE_IPV6
+  {
+    char addrbuf[BUFSIZ];
+
+    /* Add MP case. */
+    if (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32)
+      snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s",
+               inet_ntop (AF_INET6, &attr->mp_nexthop_global, 
+                          addrbuf, BUFSIZ));
+
+    if (attr->mp_nexthop_len == 32)
+      snprintf (buf + strlen (buf), size - strlen (buf), "(%s)",
+               inet_ntop (AF_INET6, &attr->mp_nexthop_local, 
+                          addrbuf, BUFSIZ));
+  }
+#endif /* HAVE_IPV6 */
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %d",
+             attr->local_pref);
+
+  if (attr->med)
+    snprintf (buf + strlen (buf), size - strlen (buf), ", metric %d",
+             attr->med);
+
+  if (attr->community) 
+    snprintf (buf + strlen (buf), size - strlen (buf), ", community %s",
+             community_str (attr->community));
+
+  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
+    snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate");
+
+  if (attr->aggregator_as)
+    snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %d %s",
+             attr->aggregator_as, inet_ntoa (attr->aggregator_addr));
+
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
+    snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s",
+             inet_ntoa (attr->originator_id));
+
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST))
+    {
+      int i;
+
+      snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist ");
+      for (i = 0; i < attr->cluster->length / 4; i++)
+       snprintf (buf + strlen (buf), size - strlen (buf), "%s",
+                 inet_ntoa (attr->cluster->list[i]));
+    }
+
+  if (attr->aspath) 
+    snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
+             aspath_print (attr->aspath));
+}
+
+/* dump notify packet */
+void
+bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, char *direct)
+{
+  char *subcode_str;
+
+  subcode_str = "";
+
+  switch (bgp_notify->code) 
+    {
+    case BGP_NOTIFY_HEADER_ERR:
+      subcode_str = LOOKUP (bgp_notify_head_msg, bgp_notify->subcode);
+      break;
+    case BGP_NOTIFY_OPEN_ERR:
+      subcode_str = LOOKUP (bgp_notify_open_msg, bgp_notify->subcode);
+      break;
+    case BGP_NOTIFY_UPDATE_ERR:
+      subcode_str = LOOKUP (bgp_notify_update_msg, bgp_notify->subcode);
+      break;
+    case BGP_NOTIFY_HOLD_ERR:
+      subcode_str = "";
+      break;
+    case BGP_NOTIFY_FSM_ERR:
+      subcode_str = "";
+      break;
+    case BGP_NOTIFY_CEASE:
+      subcode_str = LOOKUP (bgp_notify_cease_msg, bgp_notify->subcode);
+      break;
+    case BGP_NOTIFY_CAPABILITY_ERR:
+      subcode_str = LOOKUP (bgp_notify_capability_msg, bgp_notify->subcode);
+      break;
+    }
+  if (BGP_DEBUG (normal, NORMAL))
+    plog_info (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
+              peer ? peer->host : "",
+              direct, bgp_notify->code, bgp_notify->subcode,
+              LOOKUP (bgp_notify_msg, bgp_notify->code),
+              subcode_str, bgp_notify->length,
+              bgp_notify->data ? bgp_notify->data : "");
+}
+\f
+/* Debug option setting interface. */
+unsigned long bgp_debug_option = 0;
+
+int  
+debug (unsigned int option)
+{
+  return bgp_debug_option & option; 
+}
+
+DEFUN (debug_bgp_fsm,
+       debug_bgp_fsm_cmd,
+       "debug bgp fsm",
+       DEBUG_STR
+       BGP_STR
+       "BGP Finite State Machine\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_ON (fsm, FSM);
+  else
+    {
+      TERM_DEBUG_ON (fsm, FSM);
+      vty_out (vty, "BGP fsm debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_fsm,
+       no_debug_bgp_fsm_cmd,
+       "no debug bgp fsm",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "Finite State Machine\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (fsm, FSM);
+  else
+    {
+      TERM_DEBUG_OFF (fsm, FSM);
+      vty_out (vty, "BGP fsm debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_fsm,
+       undebug_bgp_fsm_cmd,
+       "undebug bgp fsm",
+       UNDEBUG_STR
+       DEBUG_STR
+       BGP_STR
+       "Finite State Machine\n")
+
+DEFUN (debug_bgp_events,
+       debug_bgp_events_cmd,
+       "debug bgp events",
+       DEBUG_STR
+       BGP_STR
+       "BGP events\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_ON (events, EVENTS);
+  else
+    {
+      TERM_DEBUG_ON (events, EVENTS);
+      vty_out (vty, "BGP events debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_events,
+       no_debug_bgp_events_cmd,
+       "no debug bgp events",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP events\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (events, EVENTS);
+  else
+    {
+      TERM_DEBUG_OFF (events, EVENTS);
+      vty_out (vty, "BGP events debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_events,
+       undebug_bgp_events_cmd,
+       "undebug bgp events",
+       UNDEBUG_STR
+       BGP_STR
+       "BGP events\n")
+
+DEFUN (debug_bgp_filter,
+       debug_bgp_filter_cmd,
+       "debug bgp filters",
+       DEBUG_STR
+       BGP_STR
+       "BGP filters\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_ON (filter, FILTER);
+  else
+    {
+      TERM_DEBUG_ON (filter, FILTER);
+      vty_out (vty, "BGP filters debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_filter,
+       no_debug_bgp_filter_cmd,
+       "no debug bgp filters",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP filters\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (filter, FILTER);
+  else
+    {
+      TERM_DEBUG_OFF (filter, FILTER);
+      vty_out (vty, "BGP filters debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_filter,
+       undebug_bgp_filter_cmd,
+       "undebug bgp filters",
+       UNDEBUG_STR
+       BGP_STR
+       "BGP filters\n")
+
+DEFUN (debug_bgp_keepalive,
+       debug_bgp_keepalive_cmd,
+       "debug bgp keepalives",
+       DEBUG_STR
+       BGP_STR
+       "BGP keepalives\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_ON (keepalive, KEEPALIVE);
+  else
+    {
+      TERM_DEBUG_ON (keepalive, KEEPALIVE);
+      vty_out (vty, "BGP keepalives debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_keepalive,
+       no_debug_bgp_keepalive_cmd,
+       "no debug bgp keepalives",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP keepalives\n")
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (keepalive, KEEPALIVE);
+  else
+    {
+      TERM_DEBUG_OFF (keepalive, KEEPALIVE);
+      vty_out (vty, "BGP keepalives debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_keepalive,
+       undebug_bgp_keepalive_cmd,
+       "undebug bgp keepalives",
+       UNDEBUG_STR
+       BGP_STR
+       "BGP keepalives\n")
+
+DEFUN (debug_bgp_update,
+       debug_bgp_update_cmd,
+       "debug bgp updates",
+       DEBUG_STR
+       BGP_STR
+       "BGP updates\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      DEBUG_ON (update, UPDATE_IN);
+      DEBUG_ON (update, UPDATE_OUT);
+    }
+  else
+    {
+      TERM_DEBUG_ON (update, UPDATE_IN);
+      TERM_DEBUG_ON (update, UPDATE_OUT);
+      vty_out (vty, "BGP updates debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_bgp_update_direct,
+       debug_bgp_update_direct_cmd,
+       "debug bgp updates (in|out)",
+       DEBUG_STR
+       BGP_STR
+       "BGP updates\n"
+       "Inbound updates\n"
+       "Outbound updates\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (strncmp ("i", argv[0], 1) == 0)
+       {
+         DEBUG_OFF (update, UPDATE_OUT);
+         DEBUG_ON (update, UPDATE_IN);
+       }
+      else
+       {       
+         DEBUG_OFF (update, UPDATE_IN);
+         DEBUG_ON (update, UPDATE_OUT);
+       }
+    }
+  else
+    {
+      if (strncmp ("i", argv[0], 1) == 0)
+       {
+         TERM_DEBUG_OFF (update, UPDATE_OUT);
+         TERM_DEBUG_ON (update, UPDATE_IN);
+         vty_out (vty, "BGP updates debugging is on (inbound)%s", VTY_NEWLINE);
+       }
+      else
+       {
+         TERM_DEBUG_OFF (update, UPDATE_IN);
+         TERM_DEBUG_ON (update, UPDATE_OUT);
+         vty_out (vty, "BGP updates debugging is on (outbound)%s", VTY_NEWLINE);
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_update,
+       no_debug_bgp_update_cmd,
+       "no debug bgp updates",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP updates\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      DEBUG_OFF (update, UPDATE_IN);
+      DEBUG_OFF (update, UPDATE_OUT);
+    }
+  else
+    {
+      TERM_DEBUG_OFF (update, UPDATE_IN);
+      TERM_DEBUG_OFF (update, UPDATE_OUT);
+      vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_update,
+       undebug_bgp_update_cmd,
+       "undebug bgp updates",
+       UNDEBUG_STR
+       BGP_STR
+       "BGP updates\n")
+
+DEFUN (debug_bgp_normal,
+       debug_bgp_normal_cmd,
+       "debug bgp",
+       DEBUG_STR
+       BGP_STR)
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_ON (normal, NORMAL);
+  else
+    {
+      TERM_DEBUG_ON (normal, NORMAL);
+      vty_out (vty, "BGP debugging is on%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_normal,
+       no_debug_bgp_normal_cmd,
+       "no debug bgp",
+       NO_STR
+       DEBUG_STR
+       BGP_STR)
+{
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (normal, NORMAL);
+  else
+    {
+      TERM_DEBUG_OFF (normal, NORMAL);
+      vty_out (vty, "BGP debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_normal,
+       undebug_bgp_normal_cmd,
+       "undebug bgp",
+       UNDEBUG_STR
+       BGP_STR)
+
+DEFUN (no_debug_bgp_all,
+       no_debug_bgp_all_cmd,
+       "no debug all bgp",
+       NO_STR
+       DEBUG_STR
+       "Enable all debugging\n"
+       BGP_STR)
+{
+  TERM_DEBUG_OFF (normal, NORMAL);
+  TERM_DEBUG_OFF (events, EVENTS);
+  TERM_DEBUG_OFF (keepalive, KEEPALIVE);
+  TERM_DEBUG_OFF (update, UPDATE_IN);
+  TERM_DEBUG_OFF (update, UPDATE_OUT);
+  TERM_DEBUG_OFF (fsm, FSM);
+  TERM_DEBUG_OFF (filter, FILTER);
+  vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE);
+      
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_bgp_all,
+       undebug_bgp_all_cmd,
+       "undebug all bgp",
+       UNDEBUG_STR
+       "Enable all debugging\n"
+       BGP_STR)
+
+DEFUN (show_debugging_bgp,
+       show_debugging_bgp_cmd,
+       "show debugging bgp",
+       SHOW_STR
+       DEBUG_STR
+       BGP_STR)
+{
+  vty_out (vty, "BGP debugging status:%s", VTY_NEWLINE);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    vty_out (vty, "  BGP debugging is on%s", VTY_NEWLINE);
+  if (BGP_DEBUG (events, EVENTS))
+    vty_out (vty, "  BGP events debugging is on%s", VTY_NEWLINE);
+  if (BGP_DEBUG (keepalive, KEEPALIVE))
+    vty_out (vty, "  BGP keepalives debugging is on%s", VTY_NEWLINE);
+  if (BGP_DEBUG (update, UPDATE_IN) && BGP_DEBUG (update, UPDATE_OUT))
+    vty_out (vty, "  BGP updates debugging is on%s", VTY_NEWLINE);
+  else if (BGP_DEBUG (update, UPDATE_IN))
+    vty_out (vty, "  BGP updates debugging is on (inbound)%s", VTY_NEWLINE);
+  else if (BGP_DEBUG (update, UPDATE_OUT))
+    vty_out (vty, "  BGP updates debugging is on (outbound)%s", VTY_NEWLINE);
+  if (BGP_DEBUG (fsm, FSM))
+    vty_out (vty, "  BGP fsm debugging is on%s", VTY_NEWLINE);
+  if (BGP_DEBUG (filter, FILTER))
+    vty_out (vty, "  BGP filter debugging is on%s", VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+int
+bgp_config_write_debug (struct vty *vty)
+{
+  int write = 0;
+
+  if (CONF_BGP_DEBUG (normal, NORMAL))
+    {
+      vty_out (vty, "debug bgp%s", VTY_NEWLINE);
+      write++;
+    }
+
+  if (CONF_BGP_DEBUG (events, EVENTS))
+    {
+      vty_out (vty, "debug bgp events%s", VTY_NEWLINE);
+      write++;
+    }
+
+  if (CONF_BGP_DEBUG (keepalive, KEEPALIVE))
+    {
+      vty_out (vty, "debug bgp keepalives%s", VTY_NEWLINE);
+      write++;
+    }
+
+  if (CONF_BGP_DEBUG (update, UPDATE_IN) && CONF_BGP_DEBUG (update, UPDATE_OUT))
+    {
+      vty_out (vty, "debug bgp updates%s", VTY_NEWLINE);
+      write++;
+    }
+  else if (CONF_BGP_DEBUG (update, UPDATE_IN))
+    {
+      vty_out (vty, "debug bgp updates in%s", VTY_NEWLINE);
+      write++;
+    }
+  else if (CONF_BGP_DEBUG (update, UPDATE_OUT))
+    {
+      vty_out (vty, "debug bgp updates out%s", VTY_NEWLINE);
+      write++;
+    }
+
+  if (CONF_BGP_DEBUG (fsm, FSM))
+    {
+      vty_out (vty, "debug bgp fsm%s", VTY_NEWLINE);
+      write++;
+    }
+
+  if (CONF_BGP_DEBUG (filter, FILTER))
+    {
+      vty_out (vty, "debug bgp filters%s", VTY_NEWLINE);
+      write++;
+    }
+
+  return write;
+}
+
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  "",
+  1
+};
+
+void
+bgp_debug_init ()
+{
+  install_node (&debug_node, bgp_config_write_debug);
+
+  install_element (ENABLE_NODE, &show_debugging_bgp_cmd);
+
+  install_element (ENABLE_NODE, &debug_bgp_fsm_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_events_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_events_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_filter_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_filter_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_update_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_update_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_normal_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_normal_cmd);
+
+  install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_events_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_events_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_events_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_filter_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_update_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_update_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_update_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_normal_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_all_cmd);
+  install_element (ENABLE_NODE, &undebug_bgp_all_cmd);
+}
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
new file mode 100644 (file)
index 0000000..06ba075
--- /dev/null
@@ -0,0 +1,113 @@
+/* BGP message debug header.
+   Copyright (C) 1996, 97, 98 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* sort of packet direction */
+#define DUMP_ON        1
+#define DUMP_SEND      2
+#define DUMP_RECV      4
+
+/* for dump_update */
+#define DUMP_WITHDRAW  8
+#define DUMP_NLRI     16
+
+/* dump detail */
+#define DUMP_DETAIL   32
+
+extern int dump_open;
+extern int dump_update;
+extern int dump_keepalive;
+extern int dump_notify;
+
+extern int Debug_Event;
+extern int Debug_Keepalive;
+extern int Debug_Update;
+extern int Debug_Radix;
+
+#define        NLRI     1
+#define        WITHDRAW 2
+#define        NO_OPT   3
+#define        SEND     4
+#define        RECV     5
+#define        DETAIL   6
+
+/* Prototypes. */
+void bgp_debug_init ();
+void bgp_packet_dump (struct stream *);
+
+int debug (unsigned int option);
+
+extern unsigned long conf_bgp_debug_fsm;
+extern unsigned long conf_bgp_debug_events;
+extern unsigned long conf_bgp_debug_packet;
+extern unsigned long conf_bgp_debug_filter;
+extern unsigned long conf_bgp_debug_keepalive;
+extern unsigned long conf_bgp_debug_update;
+extern unsigned long conf_bgp_debug_normal;
+
+extern unsigned long term_bgp_debug_fsm;
+extern unsigned long term_bgp_debug_events;
+extern unsigned long term_bgp_debug_packet;
+extern unsigned long term_bgp_debug_filter;
+extern unsigned long term_bgp_debug_keepalive;
+extern unsigned long term_bgp_debug_update;
+extern unsigned long term_bgp_debug_normal;
+
+#define BGP_DEBUG_FSM                 0x01
+#define BGP_DEBUG_EVENTS              0x01
+#define BGP_DEBUG_PACKET              0x01
+#define BGP_DEBUG_FILTER              0x01
+#define BGP_DEBUG_KEEPALIVE           0x01
+#define BGP_DEBUG_UPDATE_IN           0x01
+#define BGP_DEBUG_UPDATE_OUT          0x02
+#define BGP_DEBUG_NORMAL              0x01
+
+#define BGP_DEBUG_PACKET_SEND         0x01
+#define BGP_DEBUG_PACKET_SEND_DETAIL  0x02
+
+#define BGP_DEBUG_PACKET_RECV         0x01
+#define BGP_DEBUG_PACKET_RECV_DETAIL  0x02
+
+#define CONF_DEBUG_ON(a, b)    (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
+#define CONF_DEBUG_OFF(a, b)   (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
+
+#define TERM_DEBUG_ON(a, b)    (term_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
+#define TERM_DEBUG_OFF(a, b)   (term_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
+
+#define DEBUG_ON(a, b) \
+    do { \
+       CONF_DEBUG_ON(a, b); \
+       TERM_DEBUG_ON(a, b); \
+    } while (0)
+#define DEBUG_OFF(a, b) \
+    do { \
+       CONF_DEBUG_OFF(a, b); \
+       TERM_DEBUG_OFF(a, b); \
+    } while (0)
+
+#define BGP_DEBUG(a, b)                (term_bgp_debug_ ## a & BGP_DEBUG_ ## b)
+#define CONF_BGP_DEBUG(a, b)    (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
+
+extern char *bgp_type_str[];
+
+void bgp_dump_attr (struct peer *, struct attr *, char *, size_t);
+void bgp_notify_print (struct peer *, struct bgp_notify *, char *);
+
+extern struct message bgp_status_msg[];
+extern int bgp_status_msg_max;
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
new file mode 100644 (file)
index 0000000..fca51ed
--- /dev/null
@@ -0,0 +1,741 @@
+/* BGP-4 dump routine
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "stream.h"
+#include "sockunion.h"
+#include "command.h"
+#include "prefix.h"
+#include "thread.h"
+#include "bgpd/bgp_table.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_dump.h"
+\f
+enum bgp_dump_type
+{
+  BGP_DUMP_ALL,
+  BGP_DUMP_UPDATES,
+  BGP_DUMP_ROUTES
+};
+
+enum MRT_MSG_TYPES {
+   MSG_NULL,
+   MSG_START,                   /* sender is starting up */
+   MSG_DIE,                     /* receiver should shut down */
+   MSG_I_AM_DEAD,               /* sender is shutting down */
+   MSG_PEER_DOWN,               /* sender's peer is down */
+   MSG_PROTOCOL_BGP,            /* msg is a BGP packet */
+   MSG_PROTOCOL_RIP,            /* msg is a RIP packet */
+   MSG_PROTOCOL_IDRP,           /* msg is an IDRP packet */
+   MSG_PROTOCOL_RIPNG,          /* msg is a RIPNG packet */
+   MSG_PROTOCOL_BGP4PLUS,       /* msg is a BGP4+ packet */
+   MSG_PROTOCOL_BGP4PLUS_01,    /* msg is a BGP4+ (draft 01) packet */
+   MSG_PROTOCOL_OSPF,           /* msg is an OSPF packet */
+   MSG_TABLE_DUMP               /* routing table dump */
+};
+
+struct bgp_dump
+{
+  enum bgp_dump_type type;
+
+  char *filename;
+
+  FILE *fp;
+
+  unsigned int interval;
+
+  char *interval_str;
+
+  struct thread *t_interval;
+};
+
+/* BGP packet dump output buffer. */
+struct stream *bgp_dump_obuf;
+
+/* BGP dump strucuture for 'dump bgp all' */
+struct bgp_dump bgp_dump_all;
+
+/* BGP dump structure for 'dump bgp updates' */
+struct bgp_dump bgp_dump_updates;
+
+/* BGP dump structure for 'dump bgp routes' */
+struct bgp_dump bgp_dump_routes;
+
+/* Dump whole BGP table is very heavy process.  */
+struct thread *t_bgp_dump_routes;
+\f
+/* Some define for BGP packet dump. */
+FILE *
+bgp_dump_open_file (struct bgp_dump *bgp_dump)
+{
+  int ret;
+  time_t clock;
+  struct tm *tm;
+  char fullpath[MAXPATHLEN];
+  char realpath[MAXPATHLEN];
+
+  time (&clock);
+  tm = localtime (&clock);
+
+  if (bgp_dump->filename[0] != DIRECTORY_SEP)
+    {
+      sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
+      ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
+    }
+  else
+    ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
+
+  if (ret == 0)
+    {
+      zlog_warn ("bgp_dump_open_file: strftime error");
+      return NULL;
+    }
+
+  if (bgp_dump->fp)
+    fclose (bgp_dump->fp);
+
+
+  bgp_dump->fp = fopen (realpath, "w");
+
+  if (bgp_dump->fp == NULL)
+    return NULL;
+
+  return bgp_dump->fp;
+}
+
+int
+bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
+{
+  int bgp_dump_interval_func (struct thread *);
+
+  bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, 
+                                          bgp_dump, interval);
+  return 0;
+}
+
+/* Dump common header. */
+void
+bgp_dump_header (struct stream *obuf, int type, int subtype)
+{
+  time_t now;
+
+  /* Set header. */
+  time (&now);
+
+  /* Put dump packet header. */
+  stream_putl (obuf, now);     
+  stream_putw (obuf, type);
+  stream_putw (obuf, subtype);
+
+  stream_putl (obuf, 0);       /* len */
+}
+
+void
+bgp_dump_set_size (struct stream *s, int type)
+{
+  stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE);
+}
+
+void
+bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi,
+                      int type, unsigned int seq)
+{
+  struct stream *obuf;
+  struct attr *attr;
+  struct peer *peer;
+  int plen;
+  int safi = 0;
+
+  /* Make dump stream. */
+  obuf = bgp_dump_obuf;
+  stream_reset (obuf);
+
+  attr = info->attr;
+  peer = info->peer;
+
+  /* We support MRT's old format. */
+  if (type == MSG_TABLE_DUMP)
+    {
+      bgp_dump_header (obuf, MSG_TABLE_DUMP, afi);
+      stream_putw (obuf, 0);   /* View # */
+      stream_putw (obuf, seq); /* Sequence number. */
+    }
+  else
+    {
+      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY);
+      
+      stream_putl (obuf, info->uptime); /* Time Last Change */
+      stream_putw (obuf, afi); /* Address Family */
+      stream_putc (obuf, safi);        /* SAFI */
+    }
+
+  if (afi == AFI_IP)
+    {
+      if (type == MSG_TABLE_DUMP)
+       {
+         /* Prefix */
+         stream_put_in_addr (obuf, &p->u.prefix4);
+         stream_putc (obuf, p->prefixlen);
+
+         /* Status */
+         stream_putc (obuf, 1);
+
+         /* Originated */
+         stream_putl (obuf, info->uptime);
+
+         /* Peer's IP address */
+         stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
+
+         /* Peer's AS number. */
+         stream_putw (obuf, peer->as);
+
+         /* Dump attribute. */
+         bgp_dump_routes_attr (obuf, attr);
+       }
+      else
+       {
+         /* Next-Hop-Len */
+         stream_putc (obuf, IPV4_MAX_BYTELEN);
+         stream_put_in_addr (obuf, &attr->nexthop);
+         stream_putc (obuf, p->prefixlen);
+         plen = PSIZE (p->prefixlen);
+         stream_put (obuf, &p->u.prefix4, plen);
+         bgp_dump_routes_attr (obuf, attr);
+       }
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      if (type == MSG_TABLE_DUMP)
+       {
+         /* Prefix */
+         stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
+         stream_putc (obuf, p->prefixlen);
+
+         /* Status */
+         stream_putc (obuf, 1);
+
+         /* Originated */
+         stream_putl (obuf, info->uptime);
+
+         /* Peer's IP address */
+         stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
+                       IPV6_MAX_BYTELEN);
+
+         /* Peer's AS number. */
+         stream_putw (obuf, peer->as);
+
+         /* Dump attribute. */
+         bgp_dump_routes_attr (obuf, attr);
+       }
+      else
+       {
+         ;
+       }
+    }
+#endif /* HAVE_IPV6 */
+
+  /* Set length. */
+  bgp_dump_set_size (obuf, type);
+
+  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp);
+  fflush (bgp_dump_routes.fp);
+}
+
+/* Runs under child process. */
+void
+bgp_dump_routes_func (int afi)
+{
+  struct stream *obuf;
+  struct bgp_node *rn;
+  struct bgp_info *info;
+  struct bgp *bgp;
+  struct bgp_table *table;
+  unsigned int seq = 0;
+
+  obuf = bgp_dump_obuf;
+
+  bgp = bgp_get_default ();
+  if (!bgp)
+    return;
+
+  if (bgp_dump_routes.fp == NULL)
+    return;
+
+  /* Walk down each BGP route. */
+  table = bgp->rib[afi][SAFI_UNICAST];
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    for (info = rn->info; info; info = info->next)
+      bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++);
+}
+
+int
+bgp_dump_interval_func (struct thread *t)
+{
+  struct bgp_dump *bgp_dump;
+
+  bgp_dump = THREAD_ARG (t);
+  bgp_dump->t_interval = NULL;
+
+  if (bgp_dump_open_file (bgp_dump) == NULL)
+    return 0;
+
+  /* In case of bgp_dump_routes, we need special route dump function. */
+  if (bgp_dump->type == BGP_DUMP_ROUTES)
+    {
+      bgp_dump_routes_func (AFI_IP);
+      bgp_dump_routes_func (AFI_IP6);
+    }
+
+  bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
+  
+  return 0;
+}
+
+/* Dump common information. */
+void
+bgp_dump_common (struct stream *obuf, struct peer *peer)
+{
+  char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+  /* Source AS number and Destination AS number. */
+  stream_putw (obuf, peer->as);
+  stream_putw (obuf, peer->local_as);
+
+  if (peer->afc[AFI_IP][SAFI_UNICAST])
+    {
+      stream_putw (obuf, peer->ifindex);
+      stream_putw (obuf, AFI_IP);
+
+      stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
+
+      if (peer->su_local)
+       stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
+      else
+       stream_put (obuf, empty, IPV4_MAX_BYTELEN);
+    }
+#ifdef HAVE_IPV6
+  else if (peer->afc[AFI_IP6][SAFI_UNICAST])
+    {
+      /* Interface Index and Address family. */
+      stream_putw (obuf, peer->ifindex);
+      stream_putw (obuf, AFI_IP6);
+
+      /* Source IP Address and Destination IP Address. */
+      stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
+
+      if (peer->su_local)
+       stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
+      else
+       stream_put (obuf, empty, IPV6_MAX_BYTELEN);
+    }
+#endif /* HAVE_IPV6 */
+}
+
+/* Dump BGP status change. */
+void
+bgp_dump_state (struct peer *peer, int status_old, int status_new)
+{
+  struct stream *obuf;
+
+  /* If dump file pointer is disabled return immediately. */
+  if (bgp_dump_all.fp == NULL)
+    return;
+
+  /* Make dump stream. */
+  obuf = bgp_dump_obuf;
+  stream_reset (obuf);
+
+  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE);
+  bgp_dump_common (obuf, peer);
+
+  stream_putw (obuf, status_old);
+  stream_putw (obuf, status_new);
+
+  /* Set length. */
+  bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
+
+  /* Write to the stream. */
+  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp);
+  fflush (bgp_dump_all.fp);
+}
+
+void
+bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
+                     struct stream *packet)
+{
+  struct stream *obuf;
+
+  /* If dump file pointer is disabled return immediately. */
+  if (bgp_dump->fp == NULL)
+    return;
+
+  /* Make dump stream. */
+  obuf = bgp_dump_obuf;
+  stream_reset (obuf);
+
+  /* Dump header and common part. */
+  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
+  bgp_dump_common (obuf, peer);
+
+  /* Packet contents. */
+  stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
+  
+  /* Set length. */
+  bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
+
+  /* Write to the stream. */
+  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp);
+  fflush (bgp_dump->fp);
+}
+
+/* Called from bgp_packet.c when BGP packet is received. */
+void
+bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
+{
+  /* bgp_dump_all. */
+  bgp_dump_packet_func (&bgp_dump_all, peer, packet);
+
+  /* bgp_dump_updates. */
+  if (type == BGP_MSG_UPDATE)
+    bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
+}
+\f
+unsigned int
+bgp_dump_parse_time (char *str)
+{
+  int i;
+  int len;
+  int seen_h;
+  int seen_m;
+  int time;
+  unsigned int total;
+
+  time = 0;
+  total = 0;
+  seen_h = 0;
+  seen_m = 0;
+  len = strlen (str);
+
+  for (i = 0; i < len; i++)
+    {
+      if (isdigit ((int) str[i]))
+       {
+         time *= 10;
+         time += str[i] - '0';
+       }
+      else if (str[i] == 'H' || str[i] == 'h')
+       {
+         if (seen_h)
+           return 0;
+         if (seen_m)
+           return 0;
+         total += time * 60 *60;
+         time = 0;
+         seen_h = 1;
+       }
+      else if (str[i] == 'M' || str[i] == 'm')
+       {
+         if (seen_m)
+           return 0;
+         total += time * 60;
+         time = 0;
+         seen_h = 1;
+       }
+      else
+       return 0;
+    }
+  return total + time;
+}
+
+int
+bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
+             char *path, char *interval_str)
+{
+  if (interval_str)
+    {
+      unsigned int interval;
+
+      /* Check interval string. */
+      interval = bgp_dump_parse_time (interval_str);
+      if (interval == 0)
+       {
+         vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      /* Set interval. */
+      bgp_dump->interval = interval;
+      if (bgp_dump->interval_str)
+       free (bgp_dump->interval_str);
+      bgp_dump->interval_str = strdup (interval_str);
+
+      /* Create interval thread. */
+      bgp_dump_interval_add (bgp_dump, interval);
+    }
+
+  /* Set type. */
+  bgp_dump->type = type;
+
+  /* Set file name. */
+  if (bgp_dump->filename)
+    free (bgp_dump->filename);
+  bgp_dump->filename = strdup (path);
+
+  /* This should be called when interval is expired. */
+  bgp_dump_open_file (bgp_dump);
+
+  return CMD_SUCCESS;
+}
+
+int
+bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
+{
+  /* Set file name. */
+  if (bgp_dump->filename)
+    {
+      free (bgp_dump->filename);
+      bgp_dump->filename = NULL;
+    }
+
+  /* This should be called when interval is expired. */
+  if (bgp_dump->fp)
+    {
+      fclose (bgp_dump->fp);
+      bgp_dump->fp = NULL;
+    }
+
+  /* Create interval thread. */
+  if (bgp_dump->t_interval)
+    {
+      thread_cancel (bgp_dump->t_interval);
+      bgp_dump->t_interval = NULL;
+    }
+
+  bgp_dump->interval = 0;
+
+  if (bgp_dump->interval_str)
+    {
+      free (bgp_dump->interval_str);
+      bgp_dump->interval_str = NULL;
+    }
+  
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (dump_bgp_all,
+       dump_bgp_all_cmd,
+       "dump bgp all PATH",
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump all BGP packets\n"
+       "Output filename\n")
+{
+  return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
+}
+
+DEFUN (dump_bgp_all_interval,
+       dump_bgp_all_interval_cmd,
+       "dump bgp all PATH INTERVAL",
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump all BGP packets\n"
+       "Output filename\n"
+       "Interval of output\n")
+{
+  return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
+}
+
+DEFUN (no_dump_bgp_all,
+       no_dump_bgp_all_cmd,
+       "no dump bgp all [PATH] [INTERVAL]",
+       NO_STR
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump all BGP packets\n")
+{
+  return bgp_dump_unset (vty, &bgp_dump_all);
+}
+
+DEFUN (dump_bgp_updates,
+       dump_bgp_updates_cmd,
+       "dump bgp updates PATH",
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump BGP updates only\n"
+       "Output filename\n")
+{
+  return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
+}
+
+DEFUN (dump_bgp_updates_interval,
+       dump_bgp_updates_interval_cmd,
+       "dump bgp updates PATH INTERVAL",
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump BGP updates only\n"
+       "Output filename\n"
+       "Interval of output\n")
+{
+  return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
+}
+
+DEFUN (no_dump_bgp_updates,
+       no_dump_bgp_updates_cmd,
+       "no dump bgp updates [PATH] [INTERVAL]",
+       NO_STR
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump BGP updates only\n")
+{
+  return bgp_dump_unset (vty, &bgp_dump_updates);
+}
+
+DEFUN (dump_bgp_routes,
+       dump_bgp_routes_cmd,
+       "dump bgp routes-mrt PATH",
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump whole BGP routing table\n"
+       "Output filename\n")
+{
+  return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
+}
+
+DEFUN (dump_bgp_routes_interval,
+       dump_bgp_routes_interval_cmd,
+       "dump bgp routes-mrt PATH INTERVAL",
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump whole BGP routing table\n"
+       "Output filename\n"
+       "Interval of output\n")
+{
+  return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
+}
+
+DEFUN (no_dump_bgp_routes,
+       no_dump_bgp_routes_cmd,
+       "no dump bgp routes-mrt [PATH] [INTERVAL]",
+       NO_STR
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump whole BGP routing table\n")
+{
+  return bgp_dump_unset (vty, &bgp_dump_routes);
+}
+
+/* BGP node structure. */
+struct cmd_node bgp_dump_node =
+{
+  DUMP_NODE,
+  "",
+};
+
+#if 0
+char *
+config_time2str (unsigned int interval)
+{
+  static char buf[BUFSIZ];
+
+  buf[0] = '\0';
+
+  if (interval / 3600)
+    {
+      sprintf (buf, "%dh", interval / 3600);
+      interval %= 3600;
+    }
+  if (interval / 60)
+    {
+      sprintf (buf + strlen (buf), "%dm", interval /60);
+      interval %= 60;
+    }
+  if (interval)
+    {
+      sprintf (buf + strlen (buf), "%d", interval);
+    }
+  return buf;
+}
+#endif
+
+int
+config_write_bgp_dump (struct vty *vty)
+{
+  if (bgp_dump_all.filename)
+    {
+      if (bgp_dump_all.interval_str)
+       vty_out (vty, "dump bgp all %s %s%s", 
+                bgp_dump_all.filename, bgp_dump_all.interval_str,
+                VTY_NEWLINE);
+      else
+       vty_out (vty, "dump bgp all %s%s", 
+                bgp_dump_all.filename, VTY_NEWLINE);
+    }
+  if (bgp_dump_updates.filename)
+    {
+      if (bgp_dump_updates.interval_str)
+       vty_out (vty, "dump bgp updates %s %s%s", 
+                bgp_dump_updates.filename, bgp_dump_updates.interval_str,
+                VTY_NEWLINE);
+      else
+       vty_out (vty, "dump bgp updates %s%s", 
+                bgp_dump_updates.filename, VTY_NEWLINE);
+    }
+  if (bgp_dump_routes.filename)
+    {
+      if (bgp_dump_routes.interval_str)
+       vty_out (vty, "dump bgp routes-mrt %s %s%s", 
+                bgp_dump_routes.filename, bgp_dump_routes.interval_str,
+                VTY_NEWLINE);
+      else
+       vty_out (vty, "dump bgp routes-mrt %s%s", 
+                bgp_dump_routes.filename, VTY_NEWLINE);
+    }
+  return 0;
+}
+\f
+/* Initialize BGP packet dump functionality. */
+void
+bgp_dump_init ()
+{
+  memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
+  memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
+  memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
+
+  bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE);
+
+  install_node (&bgp_dump_node, config_write_bgp_dump);
+
+  install_element (CONFIG_NODE, &dump_bgp_all_cmd);
+  install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
+  install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
+  install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
+  install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
+  install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
+  install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
+  install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
+  install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
+}
diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h
new file mode 100644 (file)
index 0000000..d2f96a9
--- /dev/null
@@ -0,0 +1,34 @@
+/* BGP dump routine.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* MRT compatible packet dump values.  */
+/* type value */
+#define MSG_PROTOCOL_BGP4MP  16
+/* subtype value */
+#define BGP4MP_STATE_CHANGE   0
+#define BGP4MP_MESSAGE        1
+#define BGP4MP_ENTRY          2
+#define BGP4MP_SNAPSHOT       3
+
+#define BGP_DUMP_HEADER_SIZE 12
+
+void bgp_dump_init ();
+void bgp_dump_state (struct peer *, int, int);
+void bgp_dump_packet (struct peer *, int, struct stream *);
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
new file mode 100644 (file)
index 0000000..2f9cc94
--- /dev/null
@@ -0,0 +1,641 @@
+/* BGP Extended Communities Attribute
+   Copyright (C) 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.  */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_ecommunity.h"
+
+/* Hash of community attribute. */
+struct hash *ecomhash;
+\f
+/* Allocate a new ecommunities.  */
+struct ecommunity *
+ecommunity_new ()
+{
+  return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
+                                       sizeof (struct ecommunity));
+}
+
+/* Allocate ecommunities.  */
+void
+ecommunity_free (struct ecommunity *ecom)
+{
+  if (ecom->val)
+    XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val);
+  if (ecom->str)
+    XFREE (MTYPE_ECOMMUNITY_STR, ecom->str);
+  XFREE (MTYPE_ECOMMUNITY, ecom);
+}
+
+/* Add a new Extended Communities value to Extended Communities
+   Attribute structure.  When the value is already exists in the
+   structure, we don't add the value.  Newly added value is sorted by
+   numerical order.  When the value is added to the structure return 1
+   else return 0.  */
+static int
+ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
+{
+  u_char *p;
+  int ret;
+  int c;
+
+  /* When this is fist value, just add it.  */
+  if (ecom->val == NULL)
+    {
+      ecom->size++;
+      ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
+      memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
+      return 1;
+    }
+
+  /* If the value already exists in the structure return 0.  */
+  c = 0;
+  for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
+    {
+      ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
+      if (ret == 0)
+        return 0;
+      if (ret > 0)
+        break;
+    }
+
+  /* Add the value to the structure with numerical sorting.  */
+  ecom->size++;
+  ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
+
+  memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
+          ecom->val + c * ECOMMUNITY_SIZE,
+          (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
+  memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
+
+  return 1;
+}
+
+/* This function takes pointer to Extended Communites strucutre then
+   create a new Extended Communities structure by uniq and sort each
+   Exteneded Communities value.  */
+struct ecommunity *
+ecommunity_uniq_sort (struct ecommunity *ecom)
+{
+  int i;
+  struct ecommunity *new;
+  struct ecommunity_val *eval;
+  
+  if (! ecom)
+    return NULL;
+  
+  new = ecommunity_new ();;
+  
+  for (i = 0; i < ecom->size; i++)
+    {
+      eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
+      ecommunity_add_val (new, eval);
+    }
+  return new;
+}
+
+/* Parse Extended Communites Attribute in BGP packet.  */
+struct ecommunity *
+ecommunity_parse (char *pnt, u_short length)
+{
+  struct ecommunity tmp;
+  struct ecommunity *new;
+
+  /* Length check.  */
+  if (length % ECOMMUNITY_SIZE)
+    return NULL;
+
+  /* Prepare tmporary structure for making a new Extended Communities
+     Attribute.  */
+  tmp.size = length / ECOMMUNITY_SIZE;
+  tmp.val = pnt;
+
+  /* Create a new Extended Communities Attribute by uniq and sort each
+     Extended Communities value  */
+  new = ecommunity_uniq_sort (&tmp);
+
+  return ecommunity_intern (new);
+}
+
+/* Duplicate the Extended Communities Attribute structure.  */
+struct ecommunity *
+ecommunity_dup (struct ecommunity *ecom)
+{
+  struct ecommunity *new;
+
+  new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
+  new->size = ecom->size;
+  if (new->size)
+    {
+      new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
+      memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
+    }
+  else
+    new->val = NULL;
+  return new;
+}
+
+/* Merge two Extended Communities Attribute structure.  */
+struct ecommunity *
+ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
+{
+  if (ecom1->val)
+    ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val, 
+                          (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
+  else
+    ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
+                         (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
+
+  memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
+         ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
+  ecom1->size += ecom2->size;
+
+  return ecom1;
+}
+
+/* Intern Extended Communities Attribute.  */
+struct ecommunity *
+ecommunity_intern (struct ecommunity *ecom)
+{
+  struct ecommunity *find;
+
+  assert (ecom->refcnt == 0);
+
+  find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
+
+  if (find != ecom)
+    ecommunity_free (ecom);
+
+  find->refcnt++;
+
+  if (! find->str)
+    find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
+
+  return find;
+}
+
+/* Unintern Extended Communities Attribute.  */
+void
+ecommunity_unintern (struct ecommunity *ecom)
+{
+  struct ecommunity *ret;
+
+  if (ecom->refcnt)
+    ecom->refcnt--;
+
+  /* Pull off from hash.  */
+  if (ecom->refcnt == 0)
+    {
+      /* Extended community must be in the hash.  */
+      ret = (struct ecommunity *) hash_release (ecomhash, ecom);
+      assert (ret != NULL);
+
+      ecommunity_free (ecom);
+    }
+}
+
+/* Utinity function to make hash key.  */
+unsigned int
+ecommunity_hash_make (struct ecommunity *ecom)
+{
+  int c;
+  unsigned int key;
+  unsigned char *pnt;
+
+  key = 0;
+  pnt = ecom->val;
+  
+  for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++)
+    key += pnt[c];
+
+  return key;
+}
+
+/* Compare two Extended Communities Attribute structure.  */
+int
+ecommunity_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2)
+{
+  if (ecom1->size == ecom2->size
+      && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0)
+    return 1;
+  return 0;
+}
+
+/* Initialize Extended Comminities related hash. */
+void
+ecommunity_init ()
+{
+  ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
+}
+\f
+/* Extended Communities token enum. */
+enum ecommunity_token
+{
+  ecommunity_token_rt,
+  ecommunity_token_soo,
+  ecommunity_token_val,
+  ecommunity_token_unknown
+};
+
+/* Get next Extended Communities token from the string. */
+char *
+ecommunity_gettoken (char *str, struct ecommunity_val *eval,
+                    enum ecommunity_token *token)
+{
+  int ret;
+  int dot = 0;
+  int digit = 0;
+  int separator = 0;
+  u_int32_t val_low = 0;
+  u_int32_t val_high = 0;
+  char *p = str;
+  struct in_addr ip;
+  char ipstr[INET_ADDRSTRLEN + 1];
+
+  /* Skip white space. */
+  while (isspace ((int) *p))
+    {
+      p++;
+      str++;
+    }
+
+  /* Check the end of the line. */
+  if (*p == '\0')
+    return NULL;
+
+  /* "rt" and "soo" keyword parse. */
+  if (! isdigit ((int) *p)) 
+    {
+      /* "rt" match check.  */
+      if (tolower ((int) *p) == 'r')
+       {
+         p++;
+         if (tolower ((int) *p) == 't')
+           {
+             p++;
+             *token = ecommunity_token_rt;
+             return p;
+           }
+         if (isspace ((int) *p) || *p == '\0')
+           {
+             *token = ecommunity_token_rt;
+             return p;
+           }
+         goto error;
+       }
+      /* "soo" match check.  */
+      else if (tolower ((int) *p) == 's')
+       {
+         p++;
+         if (tolower ((int) *p) == 'o')
+           {
+             p++;
+             if (tolower ((int) *p) == 'o')
+               {
+                 p++;
+                 *token = ecommunity_token_soo;
+                 return p;
+               }
+             if (isspace ((int) *p) || *p == '\0')
+               {
+                 *token = ecommunity_token_soo;
+                 return p;
+               }
+             goto error;
+           }
+         if (isspace ((int) *p) || *p == '\0')
+           {
+             *token = ecommunity_token_soo;
+             return p;
+           }
+         goto error;
+       }
+      goto error;
+    }
+  
+  while (isdigit ((int) *p) || *p == ':' || *p == '.') 
+    {
+      if (*p == ':') 
+       {
+         if (separator)
+           goto error;
+
+         separator = 1;
+         digit = 0;
+
+         if (dot)
+           {
+             if ((p - str) > INET_ADDRSTRLEN)
+               goto error;
+
+             memset (ipstr, 0, INET_ADDRSTRLEN + 1);
+             memcpy (ipstr, str, p - str);
+
+             ret = inet_aton (ipstr, &ip);
+             if (ret == 0)
+               goto error;
+           }
+         else
+           val_high = val_low;
+
+         val_low = 0;
+       }
+      else if (*p == '.')
+       {
+         if (separator)
+           goto error;
+         dot++;
+         if (dot > 4)
+           goto error;
+       }
+      else
+       {
+         digit = 1;
+         val_low *= 10;
+         val_low += (*p - '0');
+       }
+      p++;
+    }
+
+  /* Low digit part must be there. */
+  if (! digit || ! separator)
+    goto error;
+
+  /* Encode result into routing distinguisher.  */
+  if (dot)
+    {
+      eval->val[0] = ECOMMUNITY_ENCODE_IP;
+      eval->val[1] = 0;
+      memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
+      eval->val[6] = (val_low >> 8) & 0xff;
+      eval->val[7] = val_low & 0xff;
+    }
+  else
+    {
+      eval->val[0] = ECOMMUNITY_ENCODE_AS;
+      eval->val[1] = 0;
+      eval->val[2] = (val_high >>8) & 0xff;
+      eval->val[3] = val_high & 0xff;
+      eval->val[4] = (val_low >>24) & 0xff;
+      eval->val[5] = (val_low >>16) & 0xff;
+      eval->val[6] = (val_low >>8) & 0xff;
+      eval->val[7] = val_low & 0xff;
+    }
+  *token = ecommunity_token_val;
+  return p;
+
+ error:
+  *token = ecommunity_token_unknown;
+  return p;
+}
+
+/* Convert string to extended community attribute. 
+
+   When type is already known, please specify both str and type.  str
+   should not include keyword such as "rt" and "soo".  Type is
+   ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
+   keyword_included should be zero.
+
+   For example route-map's "set extcommunity" command case:
+
+   "rt 100:1 100:2 100:3"        -> str = "100:1 100:2 100:3"
+                                    type = ECOMMUNITY_ROUTE_TARGET
+                                    keyword_included = 0
+
+   "soo 100:1"                   -> str = "100:1"
+                                    type = ECOMMUNITY_SITE_ORIGIN
+                                    keyword_included = 0
+
+   When string includes keyword for each extended community value.
+   Please specify keyword_included as non-zero value.
+
+   For example standard extcommunity-list case:
+
+   "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
+                                    type = 0
+                                    keyword_include = 1
+*/
+struct ecommunity *
+ecommunity_str2com (char *str, int type, int keyword_included)
+{
+  struct ecommunity *ecom = NULL;
+  enum ecommunity_token token;
+  struct ecommunity_val eval;
+  int keyword = 0;
+
+  while ((str = ecommunity_gettoken (str, &eval, &token)))
+    {
+      switch (token)
+       {
+       case ecommunity_token_rt:
+       case ecommunity_token_soo:
+         if (! keyword_included || keyword)
+           {
+             if (ecom)
+               ecommunity_free (ecom);
+             return NULL;
+           }
+         keyword = 1;
+
+         if (token == ecommunity_token_rt)
+           {
+             type = ECOMMUNITY_ROUTE_TARGET;
+           }
+         if (token == ecommunity_token_soo)
+           {
+             type = ECOMMUNITY_SITE_ORIGIN;
+           }
+         break;
+       case ecommunity_token_val:
+         if (keyword_included)
+           {
+             if (! keyword)
+               {
+                 if (ecom)
+                   ecommunity_free (ecom);
+                 return NULL;
+               }
+             keyword = 0;
+           }
+         if (ecom == NULL)
+           ecom = ecommunity_new ();
+         eval.val[1] = type;
+         ecommunity_add_val (ecom, &eval);
+         break;
+       case ecommunity_token_unknown:
+       default:
+         if (ecom)
+           ecommunity_free (ecom);
+         return NULL;
+         break;
+       }
+    }
+  return ecom;
+}
+
+/* Convert extended community attribute to string.  
+
+   Due to historical reason of industry standard implementation, there
+   are three types of format.
+
+   route-map set extcommunity format
+        "rt 100:1 100:2"
+        "soo 100:3"
+
+   extcommunity-list
+        "rt 100:1 rt 100:2 soo 100:3"
+
+   "show ip bgp" and extcommunity-list regular expression matching
+        "RT:100:1 RT:100:2 SoO:100:3"
+
+   For each formath please use below definition for format:
+
+   ECOMMUNITY_FORMAT_ROUTE_MAP
+   ECOMMUNITY_FORMAT_COMMUNITY_LIST
+   ECOMMUNITY_FORMAT_DISPLAY
+*/
+char *
+ecommunity_ecom2str (struct ecommunity *ecom, int format)
+{
+  int i;
+  u_char *pnt;
+  int encode = 0;
+  int type = 0;
+#define ECOMMUNITY_STR_DEFAULT_LEN  26
+  int str_size;
+  int str_pnt;
+  u_char *str_buf;
+  char *prefix;
+  int len = 0;
+  int first = 1;
+
+  /* For parse Extended Community attribute tupple. */
+  struct ecommunity_as
+  {
+    as_t as;
+    u_int32_t val;
+  } eas;
+
+  struct ecommunity_ip
+  {
+    struct in_addr ip;
+    u_int16_t val;
+  } eip;
+
+  if (ecom->size == 0)
+    {
+      str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
+      str_buf[0] = '\0';
+      return str_buf;
+    }
+
+  /* Prepare buffer.  */
+  str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
+  str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
+  str_pnt = 0;
+
+  for (i = 0; i < ecom->size; i++)
+    {
+      pnt = ecom->val + (i * 8);
+
+      /* High-order octet of type. */
+      encode = *pnt++;
+      if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP)
+       {
+         if (str_buf)
+           XFREE (MTYPE_ECOMMUNITY_STR, str_buf);
+         return "Unknown";
+       }
+      
+      /* Low-order octet of type. */
+      type = *pnt++;
+      if (type !=  ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
+       {
+         if (str_buf)
+           XFREE (MTYPE_ECOMMUNITY_STR, str_buf);
+         return "Unknown";
+       }
+
+      switch (format)
+       {
+       case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
+         prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
+         break;
+       case ECOMMUNITY_FORMAT_DISPLAY:
+         prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
+         break;
+       case ECOMMUNITY_FORMAT_ROUTE_MAP:
+         prefix = "";
+         break;
+       default:
+         if (str_buf)
+           XFREE (MTYPE_ECOMMUNITY_STR, str_buf);
+         return "Unknown";
+         break;
+       }
+
+      /* Make it sure size is enough.  */
+      while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
+       {
+         str_size *= 2;
+         str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
+       }
+
+      /* Space between each value.  */
+      if (! first)
+       str_buf[str_pnt++] = ' ';
+
+      /* Put string into buffer.  */
+      if (encode == ECOMMUNITY_ENCODE_AS)
+       {
+         eas.as = (*pnt++ << 8);
+         eas.as |= (*pnt++);
+
+         eas.val = (*pnt++ << 24);
+         eas.val |= (*pnt++ << 16);
+         eas.val |= (*pnt++ << 8);
+         eas.val |= (*pnt++);
+
+         len = sprintf (str_buf + str_pnt, "%s%d:%d", prefix,
+                        eas.as, eas.val);
+         str_pnt += len;
+         first = 0;
+       }
+      else if (encode == ECOMMUNITY_ENCODE_IP)
+       {
+         memcpy (&eip.ip, pnt, 4);
+         pnt += 4;
+         eip.val = (*pnt++ << 8);
+         eip.val |= (*pnt++);
+
+         len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
+                        inet_ntoa (eip.ip), eip.val);
+         str_pnt += len;
+         first = 0;
+       }
+    }
+  return str_buf;
+}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
new file mode 100644 (file)
index 0000000..678d130
--- /dev/null
@@ -0,0 +1,72 @@
+/* BGP Extended Communities Attribute.
+   Copyright (C) 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.  */
+
+/* High-order octet of the Extended Communities type field.  */
+#define ECOMMUNITY_ENCODE_AS                0x00
+#define ECOMMUNITY_ENCODE_IP                0x01
+
+/* Low-order octet of the Extended Communityes type field.  */
+#define ECOMMUNITY_ROUTE_TARGET             0x02
+#define ECOMMUNITY_SITE_ORIGIN              0x03
+
+/* Extended communities attribute string format.  */
+#define ECOMMUNITY_FORMAT_ROUTE_MAP            0
+#define ECOMMUNITY_FORMAT_COMMUNITY_LIST       1
+#define ECOMMUNITY_FORMAT_DISPLAY              2
+
+/* Extended Communities value is eight octet long.  */
+#define ECOMMUNITY_SIZE                        8
+
+/* Extended Communities attribute.  */
+struct ecommunity
+{
+  /* Reference counter.  */
+  unsigned long refcnt;
+
+  /* Size of Extended Communities attribute.  */
+  int size;
+
+  /* Extended Communities value.  */
+  u_char *val;
+
+  /* Human readable format string.  */
+  char *str;
+};
+
+/* Extended community value is eight octet.  */
+struct ecommunity_val
+{
+  char val[ECOMMUNITY_SIZE];
+};
+
+#define ecom_length(X)    ((X)->size * ECOMMUNITY_SIZE)
+
+void ecommunity_init (void);
+void ecommunity_free (struct ecommunity *);
+struct ecommunity *ecommunity_new (void);
+struct ecommunity *ecommunity_parse (char *, u_short);
+struct ecommunity *ecommunity_dup (struct ecommunity *);
+struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);
+struct ecommunity *ecommunity_intern (struct ecommunity *);
+int ecommunity_cmp (struct ecommunity *, struct ecommunity *);
+void ecommunity_unintern (struct ecommunity *);
+unsigned int ecommunity_hash_make (struct ecommunity *);
+struct ecommunity *ecommunity_str2com (char *, int, int);
+char *ecommunity_ecom2str (struct ecommunity *, int);
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
new file mode 100644 (file)
index 0000000..b544c71
--- /dev/null
@@ -0,0 +1,658 @@
+/* AS path filter list.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "buffer.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_filter.h"
+
+/* List of AS filter list. */
+struct as_list_list
+{
+  struct as_list *head;
+  struct as_list *tail;
+};
+
+/* AS path filter master. */
+struct as_list_master
+{
+  /* List of access_list which name is number. */
+  struct as_list_list num;
+
+  /* List of access_list which name is string. */
+  struct as_list_list str;
+
+  /* Hook function which is executed when new access_list is added. */
+  void (*add_hook) ();
+
+  /* Hook function which is executed when access_list is deleted. */
+  void (*delete_hook) ();
+};
+
+/* Element of AS path filter. */
+struct as_filter
+{
+  struct as_filter *next;
+  struct as_filter *prev;
+
+  enum as_filter_type type;
+
+  regex_t *reg;
+  char *reg_str;
+};
+
+enum as_list_type
+{
+  ACCESS_TYPE_STRING,
+  ACCESS_TYPE_NUMBER
+};
+
+/* AS path filter list. */
+struct as_list
+{
+  char *name;
+
+  enum as_list_type type;
+
+  struct as_list *next;
+  struct as_list *prev;
+
+  struct as_filter *head;
+  struct as_filter *tail;
+};
+\f
+/* ip as-path access-list 10 permit AS1. */
+
+static struct as_list_master as_list_master =
+{
+  {NULL, NULL},
+  {NULL, NULL},
+  NULL,
+  NULL
+};
+
+/* Allocate new AS filter. */
+struct as_filter *
+as_filter_new ()
+{
+  struct as_filter *new;
+
+  new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
+  memset (new, 0, sizeof (struct as_filter));
+  return new;
+}
+
+/* Free allocated AS filter. */
+void
+as_filter_free (struct as_filter *asfilter)
+{
+  if (asfilter->reg)
+    bgp_regex_free (asfilter->reg);
+  if (asfilter->reg_str)
+    XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
+  XFREE (MTYPE_AS_FILTER, asfilter);
+}
+
+/* Make new AS filter. */
+struct as_filter *
+as_filter_make (regex_t *reg, char *reg_str, enum as_filter_type type)
+{
+  struct as_filter *asfilter;
+
+  asfilter = as_filter_new ();
+  asfilter->reg = reg;
+  asfilter->type = type;
+  asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
+
+  return asfilter;
+}
+
+struct as_filter *
+as_filter_lookup (struct as_list *aslist, char *reg_str,
+                 enum as_filter_type type)
+{
+  struct as_filter *asfilter;
+
+  for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
+    if (strcmp (reg_str, asfilter->reg_str) == 0)
+      return asfilter;
+  return NULL;
+}
+
+void
+as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
+{
+  asfilter->next = NULL;
+  asfilter->prev = aslist->tail;
+
+  if (aslist->tail)
+    aslist->tail->next = asfilter;
+  else
+    aslist->head = asfilter;
+  aslist->tail = asfilter;
+}
+
+/* Lookup as_list from list of as_list by name. */
+struct as_list *
+as_list_lookup (char *name)
+{
+  struct as_list *aslist;
+
+  if (name == NULL)
+    return NULL;
+
+  for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
+    if (strcmp (aslist->name, name) == 0)
+      return aslist;
+
+  for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
+    if (strcmp (aslist->name, name) == 0)
+      return aslist;
+
+  return NULL;
+}
+
+struct as_list *
+as_list_new ()
+{
+  struct as_list *new;
+
+  new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
+  memset (new, 0, sizeof (struct as_list));
+  return new;
+}
+
+void
+as_list_free (struct as_list *aslist)
+{
+  XFREE (MTYPE_AS_LIST, aslist);
+}
+
+/* Insert new AS list to list of as_list.  Each as_list is sorted by
+   the name. */
+struct as_list *
+as_list_insert (char *name)
+{
+  int i;
+  long number;
+  struct as_list *aslist;
+  struct as_list *point;
+  struct as_list_list *list;
+
+  /* Allocate new access_list and copy given name. */
+  aslist = as_list_new ();
+  aslist->name = strdup (name);
+
+  /* If name is made by all digit character.  We treat it as
+     number. */
+  for (number = 0, i = 0; i < strlen (name); i++)
+    {
+      if (isdigit ((int) name[i]))
+       number = (number * 10) + (name[i] - '0');
+      else
+       break;
+    }
+
+  /* In case of name is all digit character */
+  if (i == strlen (name))
+    {
+      aslist->type = ACCESS_TYPE_NUMBER;
+
+      /* Set access_list to number list. */
+      list = &as_list_master.num;
+
+      for (point = list->head; point; point = point->next)
+       if (atol (point->name) >= number)
+         break;
+    }
+  else
+    {
+      aslist->type = ACCESS_TYPE_STRING;
+
+      /* Set access_list to string list. */
+      list = &as_list_master.str;
+  
+      /* Set point to insertion point. */
+      for (point = list->head; point; point = point->next)
+       if (strcmp (point->name, name) >= 0)
+         break;
+    }
+
+  /* In case of this is the first element of master. */
+  if (list->head == NULL)
+    {
+      list->head = list->tail = aslist;
+      return aslist;
+    }
+
+  /* In case of insertion is made at the tail of access_list. */
+  if (point == NULL)
+    {
+      aslist->prev = list->tail;
+      list->tail->next = aslist;
+      list->tail = aslist;
+      return aslist;
+    }
+
+  /* In case of insertion is made at the head of access_list. */
+  if (point == list->head)
+    {
+      aslist->next = list->head;
+      list->head->prev = aslist;
+      list->head = aslist;
+      return aslist;
+    }
+
+  /* Insertion is made at middle of the access_list. */
+  aslist->next = point;
+  aslist->prev = point->prev;
+
+  if (point->prev)
+    point->prev->next = aslist;
+  point->prev = aslist;
+
+  return aslist;
+}
+
+struct as_list *
+as_list_get (char *name)
+{
+  struct as_list *aslist;
+
+  aslist = as_list_lookup (name);
+  if (aslist == NULL)
+    {
+      aslist = as_list_insert (name);
+
+      /* Run hook function. */
+      if (as_list_master.add_hook)
+       (*as_list_master.add_hook) ();
+    }
+
+  return aslist;
+}
+
+static char *
+filter_type_str (enum as_filter_type type)
+{
+  switch (type)
+    {
+    case AS_FILTER_PERMIT:
+      return "permit";
+      break;
+    case AS_FILTER_DENY:
+      return "deny";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+void
+as_list_delete (struct as_list *aslist)
+{
+  struct as_list_list *list;
+  struct as_filter *filter, *next;
+
+  for (filter = aslist->head; filter; filter = next)
+    {
+      next = filter->next;
+      as_filter_free (filter);
+    }
+
+  if (aslist->type == ACCESS_TYPE_NUMBER)
+    list = &as_list_master.num;
+  else
+    list = &as_list_master.str;
+
+  if (aslist->next)
+    aslist->next->prev = aslist->prev;
+  else
+    list->tail = aslist->prev;
+
+  if (aslist->prev)
+    aslist->prev->next = aslist->next;
+  else
+    list->head = aslist->next;
+
+  as_list_free (aslist);
+}
+
+static int
+as_list_empty (struct as_list *aslist)
+{
+  if (aslist->head == NULL && aslist->tail == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+void
+as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
+{
+  if (asfilter->next)
+    asfilter->next->prev = asfilter->prev;
+  else
+    aslist->tail = asfilter->prev;
+
+  if (asfilter->prev)
+    asfilter->prev->next = asfilter->next;
+  else
+    aslist->head = asfilter->next;
+
+  as_filter_free (asfilter);
+
+  /* If access_list becomes empty delete it from access_master. */
+  if (as_list_empty (aslist))
+    as_list_delete (aslist);
+
+  /* Run hook function. */
+  if (as_list_master.delete_hook)
+    (*as_list_master.delete_hook) ();
+}
+\f
+static int
+as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
+{
+  if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
+    return 1;
+  return 0;
+}
+
+/* Apply AS path filter to AS. */
+enum as_filter_type
+as_list_apply (struct as_list *aslist, void *object)
+{
+  struct as_filter *asfilter;
+  struct aspath *aspath;
+
+  aspath = (struct aspath *) object;
+
+  if (aslist == NULL)
+    return AS_FILTER_DENY;
+
+  for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
+    {
+      if (as_filter_match (asfilter, aspath))
+       return asfilter->type;
+    }
+  return AS_FILTER_DENY;
+}
+
+/* Add hook function. */
+void
+as_list_add_hook (void (*func) ())
+{
+  as_list_master.add_hook = func;
+}
+
+/* Delete hook function. */
+void
+as_list_delete_hook (void (*func) ())
+{
+  as_list_master.delete_hook = func;
+}
+\f
+int
+as_list_dup_check (struct as_list *aslist, struct as_filter *new)
+{
+  struct as_filter *asfilter;
+
+  for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
+    {
+      if (asfilter->type == new->type
+         && strcmp (asfilter->reg_str, new->reg_str) == 0)
+       return 1;
+    }
+  return 0;
+}
+
+DEFUN (ip_as_path, ip_as_path_cmd,
+       "ip as-path access-list WORD (deny|permit) .LINE",
+       IP_STR
+       "BGP autonomous system path filter\n"
+       "Specify an access list name\n"
+       "Regular expression access list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  enum as_filter_type type;
+  struct as_filter *asfilter;
+  struct as_list *aslist;
+  regex_t *regex;
+  struct buffer *b;
+  int i;
+  char *regstr;
+  int first = 0;
+
+  /* Check the filter type. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    type = AS_FILTER_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    type = AS_FILTER_DENY;
+  else
+    {
+      vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check AS path regex. */
+  b = buffer_new (1024);
+  for (i = 2; i < argc; i++)
+    {
+      if (first)
+       buffer_putc (b, ' ');
+      else
+       first = 1;
+
+      buffer_putstr (b, argv[i]);
+    }
+  buffer_putc (b, '\0');
+
+  regstr = buffer_getstr (b);
+  buffer_free (b);
+
+  regex = bgp_regcomp (regstr);
+  if (!regex)
+    {
+      free (regstr);
+      vty_out (vty, "can't compile regexp %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  asfilter = as_filter_make (regex, regstr, type);
+  
+  free (regstr);
+
+  /* Install new filter to the access_list. */
+  aslist = as_list_get (argv[0]);
+
+  /* Duplicate insertion check. */;
+  if (as_list_dup_check (aslist, asfilter))
+    as_filter_free (asfilter);
+  else
+    as_list_filter_add (aslist, asfilter);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_as_path,
+       no_ip_as_path_cmd,
+       "no ip as-path access-list WORD (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       "BGP autonomous system path filter\n"
+       "Specify an access list name\n"
+       "Regular expression access list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  enum as_filter_type type;
+  struct as_filter *asfilter;
+  struct as_list *aslist;
+  struct buffer *b;
+  int i;
+  int first = 0;
+  char *regstr;
+  regex_t *regex;
+
+  /* Lookup AS list from AS path list. */
+  aslist = as_list_lookup (argv[0]);
+  if (aslist == NULL)
+    {
+      vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check the filter type. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    type = AS_FILTER_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    type = AS_FILTER_DENY;
+  else
+    {
+      vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  /* Compile AS path. */
+  b = buffer_new (1024);
+  for (i = 2; i < argc; i++)
+    {
+      if (first)
+       buffer_putc (b, ' ');
+      else
+       first = 1;
+
+      buffer_putstr (b, argv[i]);
+    }
+  buffer_putc (b, '\0');
+
+  regstr = buffer_getstr (b);
+  buffer_free (b);
+
+  regex = bgp_regcomp (regstr);
+  if (!regex)
+    {
+      free (regstr);
+      vty_out (vty, "can't compile regexp %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Lookup asfilter. */
+  asfilter = as_filter_lookup (aslist, regstr, type);
+
+  free (regstr);
+  bgp_regex_free (regex);
+
+  if (asfilter == NULL)
+    {
+      vty_out (vty, "%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  as_list_filter_delete (aslist, asfilter);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_as_path_all,
+       no_ip_as_path_all_cmd,
+       "no ip as-path access-list WORD",
+       NO_STR
+       IP_STR
+       "BGP autonomous system path filter\n"
+       "Specify an access list name\n"
+       "Regular expression access list name\n")
+{
+  struct as_list *aslist;
+
+  aslist = as_list_lookup (argv[0]);
+  if (aslist == NULL)
+    {
+      vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  as_list_delete (aslist);
+
+  return CMD_SUCCESS;
+}
+
+int
+config_write_as_list (struct vty *vty)
+{
+  struct as_list *aslist;
+  struct as_filter *asfilter;
+  int write = 0;
+
+  for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
+    for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
+      {
+       vty_out (vty, "ip as-path access-list %s %s %s%s",
+                aslist->name, filter_type_str (asfilter->type), 
+                asfilter->reg_str,
+                VTY_NEWLINE);
+       write++;
+      }
+
+  for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
+    for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
+      {
+       vty_out (vty, "ip as-path access-list %s %s %s%s",
+                aslist->name, filter_type_str (asfilter->type), 
+                asfilter->reg_str,
+                VTY_NEWLINE);
+       write++;
+      }
+  return write;
+}
+
+struct cmd_node as_list_node =
+{
+  AS_LIST_NODE,
+  "",
+  1
+};
+
+/* Register functions. */
+void
+bgp_filter_init ()
+{
+  install_node (&as_list_node, config_write_as_list);
+
+  install_element (CONFIG_NODE, &ip_as_path_cmd);
+  install_element (CONFIG_NODE, &no_ip_as_path_cmd);
+  install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
+}
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
new file mode 100644 (file)
index 0000000..8d55a22
--- /dev/null
@@ -0,0 +1,31 @@
+/* AS path filter list.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+enum as_filter_type
+{
+  AS_FILTER_DENY,
+  AS_FILTER_PERMIT
+};
+
+enum as_filter_type as_list_apply (struct as_list *, void *);
+
+struct as_list *as_list_lookup (char *);
+void as_list_add_hook (void (*func) ());
+void as_list_delete_hook (void (*func) ());
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
new file mode 100644 (file)
index 0000000..64a4c1b
--- /dev/null
@@ -0,0 +1,864 @@
+/* BGP-4 Finite State Machine   
+   From RFC1771 [A Border Gateway Protocol 4 (BGP-4)]
+   Copyright (C) 1996, 97, 98 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "thread.h"
+#include "log.h"
+#include "stream.h"
+#include "memory.h"
+#include "plist.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_open.h"
+#ifdef HAVE_SNMP
+#include "bgpd/bgp_snmp.h"
+#endif /* HAVE_SNMP */
+\f
+/* BGP FSM (finite state machine) has three types of functions.  Type
+   one is thread functions.  Type two is event functions.  Type three
+   is FSM functions.  Timer functions are set by bgp_timer_set
+   function. */
+
+/* BGP event function. */
+int bgp_event (struct thread *);
+
+/* BGP thread functions. */
+static int bgp_start_timer (struct thread *);
+static int bgp_connect_timer (struct thread *);
+static int bgp_holdtime_timer (struct thread *);
+static int bgp_keepalive_timer (struct thread *);
+
+/* BGP FSM functions. */
+static int bgp_start (struct peer *);
+
+/* BGP start timer jitter. */
+int
+bgp_start_jitter (int time)
+{
+  return ((rand () % (time + 1)) - (time / 2));
+}
+
+/* Hook function called after bgp event is occered.  And vty's
+   neighbor command invoke this function after making neighbor
+   structure. */
+void
+bgp_timer_set (struct peer *peer)
+{
+  int jitter = 0;
+
+  switch (peer->status)
+    {
+    case Idle:
+      /* First entry point of peer's finite state machine.  In Idle
+        status start timer is on unless peer is shutdown or peer is
+        inactive.  All other timer must be turned off */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
+         || CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)
+         || ! peer_active (peer))
+       {
+         BGP_TIMER_OFF (peer->t_start);
+       }
+      else
+       {
+         jitter = bgp_start_jitter (peer->v_start);
+         BGP_TIMER_ON (peer->t_start, bgp_start_timer,
+                       peer->v_start + jitter);
+       }
+      BGP_TIMER_OFF (peer->t_connect);
+      BGP_TIMER_OFF (peer->t_holdtime);
+      BGP_TIMER_OFF (peer->t_keepalive);
+      BGP_TIMER_OFF (peer->t_asorig);
+      BGP_TIMER_OFF (peer->t_routeadv);
+      break;
+
+    case Connect:
+      /* After start timer is expired, the peer moves to Connnect
+         status.  Make sure start timer is off and connect timer is
+         on. */
+      BGP_TIMER_OFF (peer->t_start);
+      BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect);
+      BGP_TIMER_OFF (peer->t_holdtime);
+      BGP_TIMER_OFF (peer->t_keepalive);
+      BGP_TIMER_OFF (peer->t_asorig);
+      BGP_TIMER_OFF (peer->t_routeadv);
+      break;
+
+    case Active:
+      /* Active is waiting connection from remote peer.  And if
+         connect timer is expired, change status to Connect. */
+      BGP_TIMER_OFF (peer->t_start);
+      /* If peer is passive mode, do not set connect timer. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
+       {
+         BGP_TIMER_OFF (peer->t_connect);
+       }
+      else
+       {
+         BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect);
+       }
+      BGP_TIMER_OFF (peer->t_holdtime);
+      BGP_TIMER_OFF (peer->t_keepalive);
+      BGP_TIMER_OFF (peer->t_asorig);
+      BGP_TIMER_OFF (peer->t_routeadv);
+      break;
+
+    case OpenSent:
+      /* OpenSent status. */
+      BGP_TIMER_OFF (peer->t_start);
+      BGP_TIMER_OFF (peer->t_connect);
+      if (peer->v_holdtime != 0)
+       {
+         BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, 
+                       peer->v_holdtime);
+       }
+      else
+       {
+         BGP_TIMER_OFF (peer->t_holdtime);
+       }
+      BGP_TIMER_OFF (peer->t_keepalive);
+      BGP_TIMER_OFF (peer->t_asorig);
+      BGP_TIMER_OFF (peer->t_routeadv);
+      break;
+
+    case OpenConfirm:
+      /* OpenConfirm status. */
+      BGP_TIMER_OFF (peer->t_start);
+      BGP_TIMER_OFF (peer->t_connect);
+
+      /* If the negotiated Hold Time value is zero, then the Hold Time
+         timer and KeepAlive timers are not started. */
+      if (peer->v_holdtime == 0)
+       {
+         BGP_TIMER_OFF (peer->t_holdtime);
+         BGP_TIMER_OFF (peer->t_keepalive);
+       }
+      else
+       {
+         BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
+                       peer->v_holdtime);
+         BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, 
+                       peer->v_keepalive);
+       }
+      BGP_TIMER_OFF (peer->t_asorig);
+      BGP_TIMER_OFF (peer->t_routeadv);
+      break;
+
+    case Established:
+      /* In Established status start and connect timer is turned
+         off. */
+      BGP_TIMER_OFF (peer->t_start);
+      BGP_TIMER_OFF (peer->t_connect);
+
+      /* Same as OpenConfirm, if holdtime is zero then both holdtime
+         and keepalive must be turned off. */
+      if (peer->v_holdtime == 0)
+       {
+         BGP_TIMER_OFF (peer->t_holdtime);
+         BGP_TIMER_OFF (peer->t_keepalive);
+       }
+      else
+       {
+         BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
+                       peer->v_holdtime);
+         BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer,
+                       peer->v_keepalive);
+       }
+      BGP_TIMER_OFF (peer->t_asorig);
+      break;
+    }
+}
+
+/* BGP start timer.  This function set BGP_Start event to thread value
+   and process event. */
+static int
+bgp_start_timer (struct thread *thread)
+{
+  struct peer *peer;
+
+  peer = THREAD_ARG (thread);
+  peer->t_start = NULL;
+
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG,
+         "%s [FSM] Timer (start timer expire).", peer->host);
+
+  THREAD_VAL (thread) = BGP_Start;
+  bgp_event (thread);
+
+  return 0;
+}
+
+/* BGP connect retry timer. */
+static int
+bgp_connect_timer (struct thread *thread)
+{
+  struct peer *peer;
+
+  peer = THREAD_ARG (thread);
+  peer->t_connect = NULL;
+
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)",
+         peer->host);
+
+  THREAD_VAL (thread) = ConnectRetry_timer_expired;
+  bgp_event (thread);
+
+  return 0;
+}
+
+/* BGP holdtime timer. */
+static int
+bgp_holdtime_timer (struct thread *thread)
+{
+  struct peer *peer;
+
+  peer = THREAD_ARG (thread);
+  peer->t_holdtime = NULL;
+
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG,
+         "%s [FSM] Timer (holdtime timer expire)",
+         peer->host);
+
+  THREAD_VAL (thread) = Hold_Timer_expired;
+  bgp_event (thread);
+
+  return 0;
+}
+
+/* BGP keepalive fire ! */
+static int
+bgp_keepalive_timer (struct thread *thread)
+{
+  struct peer *peer;
+
+  peer = THREAD_ARG (thread);
+  peer->t_keepalive = NULL;
+
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG,
+         "%s [FSM] Timer (keepalive timer expire)",
+         peer->host);
+
+  THREAD_VAL (thread) = KeepAlive_timer_expired;
+  bgp_event (thread);
+
+  return 0;
+}
+
+int
+bgp_routeadv_timer (struct thread *thread)
+{
+  struct peer *peer;
+
+  peer = THREAD_ARG (thread);
+  peer->t_routeadv = NULL;
+
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG,
+         "%s [FSM] Timer (routeadv timer expire)",
+         peer->host);
+
+  peer->synctime = time (NULL);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+
+  BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer,
+               peer->v_routeadv);
+
+  return 0;
+}
+
+/* Reset bgp update timer */
+static void
+bgp_uptime_reset (struct peer *peer)
+{
+  peer->uptime = time (NULL);
+}
+
+/* Administrative BGP peer stop event. */
+int
+bgp_stop (struct peer *peer)
+{
+  int established = 0;
+  afi_t afi;
+  safi_t safi;
+  char orf_name[BUFSIZ];
+
+  /* Increment Dropped count. */
+  if (peer->status == Established)
+    {
+      established = 1;
+      peer->dropped++;
+      bgp_fsm_change_status (peer, Idle);
+#ifdef HAVE_SNMP
+      bgpTrapBackwardTransition (peer);
+#endif /* HAVE_SNMP */
+    }
+
+  /* Reset uptime. */
+  bgp_uptime_reset (peer);
+
+  /* Need of clear of peer. */
+  if (established)
+    bgp_clear_route_all (peer);
+
+  /* Stop read and write threads when exists. */
+  BGP_READ_OFF (peer->t_read);
+  BGP_WRITE_OFF (peer->t_write);
+
+  /* Stop all timers. */
+  BGP_TIMER_OFF (peer->t_start);
+  BGP_TIMER_OFF (peer->t_connect);
+  BGP_TIMER_OFF (peer->t_holdtime);
+  BGP_TIMER_OFF (peer->t_keepalive);
+  BGP_TIMER_OFF (peer->t_asorig);
+  BGP_TIMER_OFF (peer->t_routeadv);
+
+  /* Delete all existing events of the peer. */
+  BGP_EVENT_DELETE (peer);
+
+  /* Stream reset. */
+  peer->packet_size = 0;
+
+  /* Clear input and output buffer.  */
+  if (peer->ibuf)
+    stream_reset (peer->ibuf);
+  if (peer->work)
+    stream_reset (peer->work);
+  stream_fifo_clean (peer->obuf);
+
+  /* Close of file descriptor. */
+  if (peer->fd >= 0)
+    {
+      close (peer->fd);
+      peer->fd = -1;
+    }
+
+  /* Connection information. */
+  if (peer->su_local)
+    {
+      XFREE (MTYPE_SOCKUNION, peer->su_local);
+      peer->su_local = NULL;
+    }
+
+  if (peer->su_remote)
+    {
+      XFREE (MTYPE_SOCKUNION, peer->su_remote);
+      peer->su_remote = NULL;
+    }
+
+  /* Clear remote router-id. */
+  peer->remote_id.s_addr = 0;
+
+  /* Reset all negotiated variables */
+  peer->afc_nego[AFI_IP][SAFI_UNICAST] = 0;
+  peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 0;
+  peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 0;
+  peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 0;
+  peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 0;
+  peer->afc_adv[AFI_IP][SAFI_UNICAST] = 0;
+  peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 0;
+  peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 0;
+  peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 0;
+  peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 0;
+  peer->afc_recv[AFI_IP][SAFI_UNICAST] = 0;
+  peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 0;
+  peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 0;
+  peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 0;
+  peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 0;
+
+  /* Reset route refresh flag. */
+  UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
+  UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+  UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+  UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
+  UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
+
+  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+      {
+       /* peer address family capability flags*/
+       peer->af_cap[afi][safi] = 0;
+       /* peer address family status flags*/
+       peer->af_sflags[afi][safi] = 0;
+       /* Received ORF prefix-filter */
+       peer->orf_plist[afi][safi] = NULL;
+        /* ORF received prefix-filter pnt */
+        sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
+        prefix_bgp_orf_remove_all (orf_name);
+      }
+
+  /* Reset keepalive and holdtime */
+  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
+    {
+      peer->v_keepalive = peer->keepalive;
+      peer->v_holdtime = peer->holdtime;
+    }
+  else
+    {
+      peer->v_keepalive = peer->bgp->default_keepalive;
+      peer->v_holdtime = peer->bgp->default_holdtime;
+    }
+
+  peer->update_time = 0;
+
+  /* Until we are sure that there is no problem about prefix count
+     this should be commented out.*/
+#if 0
+  /* Reset prefix count */
+  peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
+  peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
+  peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
+  peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
+  peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
+#endif /* 0 */
+
+  return 0;
+}
+
+/* BGP peer is stoped by the error. */
+int
+bgp_stop_with_error (struct peer *peer)
+{
+  /* Double start timer. */
+  peer->v_start *= 2;
+
+  /* Overflow check. */
+  if (peer->v_start >= (60 * 2))
+    peer->v_start = (60 * 2);
+
+  bgp_stop (peer);
+
+  return 0;
+}
+
+/* TCP connection open.  Next we send open message to remote peer. And
+   add read thread for reading open message. */
+int
+bgp_connect_success (struct peer *peer)
+{
+  if (peer->fd < 0)
+    {
+      zlog_err ("bgp_connect_success peer's fd is negative value %d",
+               peer->fd);
+      return -1;
+    }
+  BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
+
+  /* bgp_getsockname (peer); */
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+    bgp_open_send (peer);
+
+  return 0;
+}
+
+/* TCP connect fail */
+int
+bgp_connect_fail (struct peer *peer)
+{
+  bgp_stop (peer);
+  return 0;
+}
+
+/* This function is the first starting point of all BGP connection. It
+   try to connect to remote peer with non-blocking IO. */
+int
+bgp_start (struct peer *peer)
+{
+  int status;
+
+  /* If the peer is passive mode, force to move to Active mode. */
+  if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
+    {
+      BGP_EVENT_ADD (peer, TCP_connection_open_failed);
+      return 0;
+    }
+
+  status = bgp_connect (peer);
+
+  switch (status)
+    {
+    case connect_error:
+      if (BGP_DEBUG (fsm, FSM))
+       plog_info (peer->log, "%s [FSM] Connect error", peer->host);
+      BGP_EVENT_ADD (peer, TCP_connection_open_failed);
+      break;
+    case connect_success:
+      if (BGP_DEBUG (fsm, FSM))
+       plog_info (peer->log, "%s [FSM] Connect immediately success",
+                  peer->host);
+      BGP_EVENT_ADD (peer, TCP_connection_open);
+      break;
+    case connect_in_progress:
+      /* To check nonblocking connect, we wait until socket is
+         readable or writable. */
+      if (BGP_DEBUG (fsm, FSM))
+       plog_info (peer->log, "%s [FSM] Non blocking connect waiting result",
+                  peer->host);
+      if (peer->fd < 0)
+       {
+         zlog_err ("bgp_start peer's fd is negative value %d",
+                   peer->fd);
+         return -1;
+       }
+      BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
+      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+      break;
+    }
+  return 0;
+}
+
+/* Connect retry timer is expired when the peer status is Connect. */
+int
+bgp_reconnect (struct peer *peer)
+{
+  bgp_stop (peer);
+  bgp_start (peer);
+  return 0;
+}
+
+int
+bgp_fsm_open (struct peer *peer)
+{
+  /* Send keepalive and make keepalive timer */
+  bgp_keepalive_send (peer);
+
+  /* Reset holdtimer value. */
+  BGP_TIMER_OFF (peer->t_holdtime);
+
+  return 0;
+}
+
+/* Called after event occured, this function change status and reset
+   read/write and timer thread. */
+void
+bgp_fsm_change_status (struct peer *peer, int status)
+{
+  bgp_dump_state (peer, peer->status, status);
+
+  /* Preserve old status and change into new status. */
+  peer->ostatus = peer->status;
+  peer->status = status;
+}
+
+/* Keepalive send to peer. */
+int
+bgp_fsm_keepalive_expire (struct peer *peer)
+{
+  bgp_keepalive_send (peer);
+  return 0;
+}
+
+/* Hold timer expire.  This is error of BGP connection. So cut the
+   peer and change to Idle status. */
+int
+bgp_fsm_holdtime_expire (struct peer *peer)
+{
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host);
+
+  /* Send notify to remote peer. */
+  bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0);
+
+  /* Sweep if it is temporary peer. */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+    {
+      zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host);
+      peer_delete (peer);
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Status goes to Established.  Send keepalive packet then make first
+   update information. */
+int
+bgp_establish (struct peer *peer)
+{
+  struct bgp_notify *notify;
+  afi_t afi;
+  safi_t safi;
+
+  /* Reset capability open status flag. */
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
+    SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+
+  /* Clear last notification data. */
+  notify = &peer->notify;
+  if (notify->data)
+    XFREE (MTYPE_TMP, notify->data);
+  memset (notify, 0, sizeof (struct bgp_notify));
+
+  /* Clear start timer value to default. */
+  peer->v_start = BGP_INIT_START_TIMER;
+
+  /* Increment established count. */
+  peer->established++;
+  bgp_fsm_change_status (peer, Established);
+#ifdef HAVE_SNMP
+  bgpTrapEstablished (peer);
+#endif /* HAVE_SNMP */
+
+  /* Reset uptime, send keepalive, send current table. */
+  bgp_uptime_reset (peer);
+
+  /* Send route-refresh when ORF is enabled */
+  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV))
+       {
+         if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
+           bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX,
+                                   REFRESH_IMMEDIATE, 0);
+         else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
+           bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD,
+                                   REFRESH_IMMEDIATE, 0);
+       }
+
+  if (peer->v_keepalive)
+    bgp_keepalive_send (peer);
+
+  /* First update is deferred until ORF or ROUTE-REFRESH is received */
+  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV))
+       if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
+           || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
+         SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
+
+  bgp_announce_route_all (peer);
+
+  BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
+
+  return 0;
+}
+
+/* Keepalive packet is received. */
+int
+bgp_fsm_keepalive (struct peer *peer)
+{
+  /* peer count update */
+  peer->keepalive_in++;
+
+  BGP_TIMER_OFF (peer->t_holdtime);
+  return 0;
+}
+
+/* Update packet is received. */
+int
+bgp_fsm_update (struct peer *peer)
+{
+  BGP_TIMER_OFF (peer->t_holdtime);
+  return 0;
+}
+
+/* This is empty event. */
+int
+bgp_ignore (struct peer *peer)
+{
+  if (BGP_DEBUG (fsm, FSM))
+    zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host);
+  return 0;
+}
+\f
+/* Finite State Machine structure */
+struct {
+  int (*func) ();
+  int next_state;
+} FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = 
+{
+  {
+    /* Idle state: In Idle state, all events other than BGP_Start is
+       ignored.  With BGP_Start event, finite state machine calls
+       bgp_start(). */
+    {bgp_start,  Connect},     /* BGP_Start                    */
+    {bgp_stop,   Idle},                /* BGP_Stop                     */
+    {bgp_stop,   Idle},                /* TCP_connection_open          */
+    {bgp_stop,   Idle},                /* TCP_connection_closed        */
+    {bgp_ignore, Idle},                /* TCP_connection_open_failed   */
+    {bgp_stop,   Idle},                /* TCP_fatal_error              */
+    {bgp_ignore, Idle},                /* ConnectRetry_timer_expired   */
+    {bgp_ignore, Idle},                /* Hold_Timer_expired           */
+    {bgp_ignore, Idle},                /* KeepAlive_timer_expired      */
+    {bgp_ignore, Idle},                /* Receive_OPEN_message         */
+    {bgp_ignore, Idle},                /* Receive_KEEPALIVE_message    */
+    {bgp_ignore, Idle},                /* Receive_UPDATE_message       */
+    {bgp_ignore, Idle},                /* Receive_NOTIFICATION_message */
+  },
+  {
+    /* Connect */
+    {bgp_ignore,  Connect},    /* BGP_Start                    */
+    {bgp_stop,    Idle},       /* BGP_Stop                     */
+    {bgp_connect_success, OpenSent}, /* TCP_connection_open          */
+    {bgp_stop, Idle},          /* TCP_connection_closed        */
+    {bgp_connect_fail, Active}, /* TCP_connection_open_failed   */
+    {bgp_connect_fail, Idle},  /* TCP_fatal_error              */
+    {bgp_reconnect, Connect},  /* ConnectRetry_timer_expired   */
+    {bgp_ignore,  Idle},       /* Hold_Timer_expired           */
+    {bgp_ignore,  Idle},       /* KeepAlive_timer_expired      */
+    {bgp_ignore,  Idle},       /* Receive_OPEN_message         */
+    {bgp_ignore,  Idle},       /* Receive_KEEPALIVE_message    */
+    {bgp_ignore,  Idle},       /* Receive_UPDATE_message       */
+    {bgp_stop,    Idle},       /* Receive_NOTIFICATION_message */
+  },
+  {
+    /* Active, */
+    {bgp_ignore,  Active},     /* BGP_Start                    */
+    {bgp_stop,    Idle},       /* BGP_Stop                     */
+    {bgp_connect_success, OpenSent}, /* TCP_connection_open          */
+    {bgp_stop,    Idle},       /* TCP_connection_closed        */
+    {bgp_ignore,  Active},     /* TCP_connection_open_failed   */
+    {bgp_ignore,  Idle},       /* TCP_fatal_error              */
+    {bgp_start,   Connect},    /* ConnectRetry_timer_expired   */
+    {bgp_ignore,  Idle},       /* Hold_Timer_expired           */
+    {bgp_ignore,  Idle},       /* KeepAlive_timer_expired      */
+    {bgp_ignore,  Idle},       /* Receive_OPEN_message         */
+    {bgp_ignore,  Idle},       /* Receive_KEEPALIVE_message    */
+    {bgp_ignore,  Idle},       /* Receive_UPDATE_message       */
+    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
+  },
+  {
+    /* OpenSent, */
+    {bgp_ignore,  OpenSent},   /* BGP_Start                    */
+    {bgp_stop,    Idle},       /* BGP_Stop                     */
+    {bgp_stop,    Idle},       /* TCP_connection_open          */
+    {bgp_stop,    Active},     /* TCP_connection_closed        */
+    {bgp_ignore,  Idle},       /* TCP_connection_open_failed   */
+    {bgp_stop,    Idle},       /* TCP_fatal_error              */
+    {bgp_ignore,  Idle},       /* ConnectRetry_timer_expired   */
+    {bgp_fsm_holdtime_expire, Idle},   /* Hold_Timer_expired           */
+    {bgp_ignore,  Idle},       /* KeepAlive_timer_expired      */
+    {bgp_fsm_open,    OpenConfirm},    /* Receive_OPEN_message         */
+    {bgp_ignore,  Idle},       /* Receive_KEEPALIVE_message    */
+    {bgp_ignore,  Idle},       /* Receive_UPDATE_message       */
+    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
+  },
+  {
+    /* OpenConfirm, */
+    {bgp_ignore,  OpenConfirm},        /* BGP_Start                    */
+    {bgp_stop,    Idle},       /* BGP_Stop                     */
+    {bgp_stop,    Idle},       /* TCP_connection_open          */
+    {bgp_stop,    Idle},       /* TCP_connection_closed        */
+    {bgp_stop,    Idle},       /* TCP_connection_open_failed   */
+    {bgp_stop,    Idle},       /* TCP_fatal_error              */
+    {bgp_ignore,  Idle},       /* ConnectRetry_timer_expired   */
+    {bgp_fsm_holdtime_expire, Idle},   /* Hold_Timer_expired           */
+    {bgp_ignore,  OpenConfirm},        /* KeepAlive_timer_expired      */
+    {bgp_ignore,  Idle},       /* Receive_OPEN_message         */
+    {bgp_establish, Established}, /* Receive_KEEPALIVE_message    */
+    {bgp_ignore,  Idle},       /* Receive_UPDATE_message       */
+    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
+  },
+  {
+    /* Established, */
+    {bgp_ignore,  Established},        /* BGP_Start                    */
+    {bgp_stop,    Idle},       /* BGP_Stop                     */
+    {bgp_stop,    Idle},       /* TCP_connection_open          */
+    {bgp_stop,    Idle},       /* TCP_connection_closed        */
+    {bgp_ignore,  Idle},       /* TCP_connection_open_failed   */
+    {bgp_stop,    Idle},       /* TCP_fatal_error              */
+    {bgp_ignore,  Idle},       /* ConnectRetry_timer_expired   */
+    {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired           */
+    {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired      */
+    {bgp_stop, Idle},          /* Receive_OPEN_message         */
+    {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message    */
+    {bgp_fsm_update,   Established}, /* Receive_UPDATE_message       */
+    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
+  },
+};
+
+static char *bgp_event_str[] =
+{
+  NULL,
+  "BGP_Start",
+  "BGP_Stop",
+  "TCP_connection_open",
+  "TCP_connection_closed",
+  "TCP_connection_open_failed",
+  "TCP_fatal_error",
+  "ConnectRetry_timer_expired",
+  "Hold_Timer_expired",
+  "KeepAlive_timer_expired",
+  "Receive_OPEN_message",
+  "Receive_KEEPALIVE_message",
+  "Receive_UPDATE_message",
+  "Receive_NOTIFICATION_message"
+};
+
+/* Execute event process. */
+int
+bgp_event (struct thread *thread)
+{
+  int ret;
+  int event;
+  int next;
+  struct peer *peer;
+
+  peer = THREAD_ARG (thread);
+  event = THREAD_VAL (thread);
+
+  /* Logging this event. */
+  next = FSM [peer->status -1][event - 1].next_state;
+
+  if (BGP_DEBUG (fsm, FSM))
+    plog_info (peer->log, "%s [FSM] %s (%s->%s)", peer->host, 
+              bgp_event_str[event],
+              LOOKUP (bgp_status_msg, peer->status),
+              LOOKUP (bgp_status_msg, next));
+  if (BGP_DEBUG (normal, NORMAL)
+      && strcmp (LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)))
+    zlog_info ("%s went from %s to %s",
+              peer->host,
+              LOOKUP (bgp_status_msg, peer->status),
+              LOOKUP (bgp_status_msg, next));
+
+  /* Call function. */
+  ret = (*(FSM [peer->status - 1][event - 1].func))(peer);
+
+  /* When function do not want proceed next job return -1. */
+  if (ret < 0)
+    return ret;
+    
+  /* If status is changed. */
+  if (next != peer->status)
+    bgp_fsm_change_status (peer, next);
+
+  /* Make sure timer is set. */
+  bgp_timer_set (peer);
+
+  return 0;
+}
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
new file mode 100644 (file)
index 0000000..f051aaa
--- /dev/null
@@ -0,0 +1,42 @@
+/* BGP-4 Finite State Machine   
+   From RFC1771 [A Border Gateway Protocol 4 (BGP-4)]
+   Copyright (C) 1998 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* Macro for BGP read, write and timer thread.  */
+#define BGP_READ_ON(T,F,V)   THREAD_READ_ON(master,T,F,peer,V)
+#define BGP_READ_OFF(X)      THREAD_READ_OFF(X)
+
+#define BGP_WRITE_ON(T,F,V)  THREAD_WRITE_ON(master,T,F,peer,V)
+#define BGP_WRITE_OFF(X)     THREAD_WRITE_OFF(X)
+
+#define BGP_TIMER_ON(T,F,V)  THREAD_TIMER_ON(master,T,F,peer,V)
+#define BGP_TIMER_OFF(X)     THREAD_TIMER_OFF(X)
+
+#define BGP_EVENT_ADD(P,E) \
+    thread_add_event (master, bgp_event, (P), (E))
+
+#define BGP_EVENT_DELETE(P) \
+    thread_cancel_event (master, (P))
+
+/* Prototypes. */
+int bgp_event (struct thread *);
+int bgp_stop (struct peer *peer);
+void bgp_timer_set (struct peer *);
+void bgp_fsm_change_status (struct peer *peer, int status);
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
new file mode 100644 (file)
index 0000000..7fc68fa
--- /dev/null
@@ -0,0 +1,285 @@
+/* Main routine of bgpd.
+   Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "getopt.h"
+#include "thread.h"
+#include "version.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+/* bgpd options, we use GNU getopt library. */
+struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "bgp_port",    required_argument, NULL, 'p'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "retain",      no_argument,       NULL, 'r'},
+  { "no_kernel",   no_argument,       NULL, 'n'},
+  { "version",     no_argument,       NULL, 'v'},
+  { "help",        no_argument,       NULL, 'h'},
+  { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = BGP_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG;
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Manually specified configuration file name.  */
+char *config_file = NULL;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_BGPD_PID;
+
+/* VTY port number and address.  */
+int vty_port = BGP_VTY_PORT;
+char *vty_addr = NULL;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages kernel routing table management and \
+redistribution between different routing protocols.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-p, --bgp_port     Set bgp protocol's port number\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-r, --retain       When program terminates, retain added route by bgpd.\n\
+-n, --no_kernel    Do not install route to kernel.\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+
+  exit (status);
+}
+\f
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog (NULL, LOG_INFO, "SIGHUP received");
+
+  /* Terminate all thread. */
+  bgp_terminate ();
+  bgp_reset ();
+  zlog_info ("bgpd restarting!");
+
+  /* Reload config file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Create VTY's socket */
+  vty_serv_sock (vty_addr, vty_port ? vty_port : BGP_VTY_PORT, BGP_VTYSH_PATH);
+
+  /* Try to return to normal operation. */
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog (NULL, LOG_INFO, "Terminating on signal");
+
+  if (! retain_mode)
+    bgp_terminate ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+  signal_set (SIGUSR1, sigusr1);
+}
+\f
+/* Main routine of bgpd. Treatment of argument and start bgp finite
+   state machine is handled at here. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  int opt;
+  int daemon_mode = 0;
+  char *progname;
+  struct thread thread;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* Preserve name of myself. */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_BGP,
+                          LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  /* BGP master init. */
+  bgp_master_init ();
+
+  /* Command line argument treatment. */
+  while (1) 
+    {
+      opt = getopt_long (argc, argv, "df:hp:A:P:rnv", longopts, 0);
+    
+      if (opt == EOF)
+       break;
+
+      switch (opt) 
+       {
+       case 0:
+         break;
+       case 'd':
+         daemon_mode = 1;
+         break;
+       case 'f':
+         config_file = optarg;
+         break;
+        case 'i':
+          pid_file = optarg;
+          break;
+       case 'p':
+         bm->port = atoi (optarg);
+         break;
+       case 'A':
+         vty_addr = optarg;
+         break;
+       case 'P':
+         vty_port = atoi (optarg);
+         break;
+       case 'r':
+         retain_mode = 1;
+         break;
+       case 'n':
+         bgp_option_set (BGP_OPT_NO_FIB);
+         break;
+       case 'v':
+         print_version (progname);
+         exit (0);
+         break;
+       case 'h':
+         usage (progname, 0);
+         break;
+       default:
+         usage (progname, 1);
+         break;
+       }
+    }
+
+  /* Make thread master. */
+  master = bm->master;
+
+  /* Initializations. */
+  srand (time (NULL));
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  memory_init ();
+
+  /* BGP related initialization.  */
+  bgp_init ();
+
+  /* Sort CLI commands. */
+  sort_node ();
+
+  /* Parse config file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Turn into daemon if daemon_mode is set. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Process ID file creation. */
+  pid_output (pid_file);
+
+  /* Make bgp vty socket. */
+  vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH);
+
+  /* Print banner. */
+  zlog_info ("BGPd %s starting: vty@%d, bgp@%d", ZEBRA_VERSION,
+            vty_port, bm->port);
+
+  /* Start finite state machine, here we go! */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached. */
+  exit (0);
+}
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
new file mode 100644 (file)
index 0000000..e820cab
--- /dev/null
@@ -0,0 +1,741 @@
+/* MPLS-VPN
+   Copyright (C) 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.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+int route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t);
+int route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t);
+void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t);
+
+u_int16_t
+decode_rd_type (u_char *pnt)
+{
+  u_int16_t v;
+  
+  v = ((u_int16_t) *pnt++ << 8);
+  v |= (u_int16_t) *pnt;
+  return v;
+}
+
+u_int32_t
+decode_label (u_char *pnt)
+{
+  u_int32_t l;
+
+  l = ((u_int32_t) *pnt++ << 12);
+  l |= (u_int32_t) *pnt++ << 4;
+  l |= (u_int32_t) ((*pnt & 0xf0) >> 4);
+  return l;
+}
+
+void
+decode_rd_as (u_char *pnt, struct rd_as *rd_as)
+{
+  rd_as->as = (u_int16_t) *pnt++ << 8;
+  rd_as->as |= (u_int16_t) *pnt++;
+  
+  rd_as->val = ((u_int32_t) *pnt++ << 24);
+  rd_as->val |= ((u_int32_t) *pnt++ << 16);
+  rd_as->val |= ((u_int32_t) *pnt++ << 8);
+  rd_as->val |= (u_int32_t) *pnt;
+}
+
+void
+decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
+{
+  memcpy (&rd_ip->ip, pnt, 4);
+  pnt += 4;
+  
+  rd_ip->val = ((u_int16_t) *pnt++ << 8);
+  rd_ip->val |= (u_int16_t) *pnt;
+}
+
+int bgp_update (struct peer *, struct prefix *, struct attr *, 
+               afi_t, safi_t, int, int, struct prefix_rd *, u_char *);
+
+int bgp_withdraw (struct peer *, struct prefix *, struct attr *, 
+                 int, int, int, int, struct prefix_rd *, u_char *);
+int
+bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, 
+                     struct bgp_nlri *packet)
+{
+  u_char *pnt;
+  u_char *lim;
+  struct prefix p;
+  int psize;
+  int prefixlen;
+  u_int32_t label;
+  u_int16_t type;
+  struct rd_as rd_as;
+  struct rd_ip rd_ip;
+  struct prefix_rd prd;
+  u_char *tagpnt;
+
+  /* Check peer status. */
+  if (peer->status != Established)
+    return 0;
+  
+  /* Make prefix_rd */
+  prd.family = AF_UNSPEC;
+  prd.prefixlen = 64;
+
+  pnt = packet->nlri;
+  lim = pnt + packet->length;
+
+  for (; pnt < lim; pnt += psize)
+    {
+      /* Clear prefix structure. */
+      memset (&p, 0, sizeof (struct prefix));
+
+      /* Fetch prefix length. */
+      prefixlen = *pnt++;
+      p.family = AF_INET;
+      psize = PSIZE (prefixlen);
+
+      if (prefixlen < 88)
+       {
+         zlog_err ("prefix length is less than 88: %d", prefixlen);
+         return -1;
+       }
+
+      label = decode_label (pnt);
+
+      /* Copyr label to prefix. */
+      tagpnt = pnt;;
+
+      /* Copy routing distinguisher to rd. */
+      memcpy (&prd.val, pnt + 3, 8);
+
+      /* Decode RD type. */
+      type = decode_rd_type (pnt + 3);
+
+      /* Decode RD value. */
+      if (type == RD_TYPE_AS)
+       decode_rd_as (pnt + 5, &rd_as);
+      else if (type == RD_TYPE_IP)
+       decode_rd_ip (pnt + 5, &rd_ip);
+      else
+       {
+         zlog_err ("Invalid RD type %d", type);
+         return -1;
+       }
+
+      p.prefixlen = prefixlen - 88;
+      memcpy (&p.u.prefix, pnt + 11, psize - 11);
+
+#if 0
+      if (type == RD_TYPE_AS)
+       zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val,
+                  inet_ntoa (p.u.prefix4), p.prefixlen);
+      else if (type == RD_TYPE_IP)
+       zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip),
+                  rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen);
+#endif /* 0 */
+
+      if (pnt + psize > lim)
+       return -1;
+
+      if (attr)
+       bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
+                   ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+      else
+       bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
+                     ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+    }
+
+  /* Packet length consistency check. */
+  if (pnt != lim)
+    return -1;
+
+  return 0;
+}
+
+int
+str2prefix_rd (u_char *str, struct prefix_rd *prd)
+{
+  int ret;
+  u_char *p;
+  u_char *p2;
+  struct stream *s;
+  u_char *half;
+  struct in_addr addr;
+
+  s = stream_new (8);
+
+  prd->family = AF_UNSPEC;
+  prd->prefixlen = 64;
+
+  p = strchr (str, ':');
+  if (! p)
+    return 0;
+
+  if (! all_digit (p + 1))
+    return 0;
+
+  half = XMALLOC (MTYPE_TMP, (p - str) + 1);
+  memcpy (half, str, (p - str));
+  half[p - str] = '\0';
+
+  p2 = strchr (str, '.');
+
+  if (! p2)
+    {
+      if (! all_digit (half))
+       {
+         XFREE (MTYPE_TMP, half);
+         return 0;
+       }
+      stream_putw (s, RD_TYPE_AS);
+      stream_putw (s, atoi (half));
+      stream_putl (s, atol (p + 1));
+    }
+  else
+    {
+      ret = inet_aton (half, &addr);
+      if (! ret)
+       {
+         XFREE (MTYPE_TMP, half);
+         return 0;
+       }
+      stream_putw (s, RD_TYPE_IP);
+      stream_put_in_addr (s, &addr);
+      stream_putw (s, atol (p + 1));
+    }
+  memcpy (prd->val, s->data, 8);
+
+  return 1;
+}
+
+int
+str2tag (u_char *str, u_char *tag)
+{
+  u_int32_t l;
+
+  l = atol (str);
+
+  tag[0] = (u_char)(l >> 12);
+  tag[1] = (u_char)(l >> 4);
+  tag[2] = (u_char)(l << 4);
+
+  return 1;
+}
+
+char *
+prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size)
+{
+  u_char *pnt;
+  u_int16_t type;
+  struct rd_as rd_as;
+  struct rd_ip rd_ip;
+
+  if (size < RD_ADDRSTRLEN)
+    return NULL;
+
+  pnt = prd->val;
+
+  type = decode_rd_type (pnt);
+
+  if (type == RD_TYPE_AS)
+    {
+      decode_rd_as (pnt + 2, &rd_as);
+      snprintf (buf, size, "%d:%d", rd_as.as, rd_as.val);
+      return buf;
+    }
+  else if (type == RD_TYPE_IP)
+    {
+      decode_rd_ip (pnt + 2, &rd_ip);
+      snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+      return buf;
+    }
+
+  return NULL;
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN (vpnv4_network,
+       vpnv4_network_cmd,
+       "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify Route Distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "BGP tag\n"
+       "tag value\n")
+{
+  return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]);
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN (no_vpnv4_network,
+       no_vpnv4_network_cmd,
+       "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify Route Distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "BGP tag\n"
+       "tag value\n")
+{
+  return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]);
+}
+
+int
+show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd)
+{
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct attr *attr;
+  int rd_header;
+  int header = 1;
+  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s";
+
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn;
+       rn = bgp_route_next (rn))
+    {
+      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+        continue;
+
+      if ((table = rn->info) != NULL)
+        {
+          rd_header = 1;
+
+          for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+            if ((attr = rm->info) != NULL)
+              {
+                if (header)
+                  {
+                    vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+                             inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                    vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+                             VTY_NEWLINE);
+                    vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+                             VTY_NEWLINE, VTY_NEWLINE);
+                    vty_out (vty, v4_header, VTY_NEWLINE);
+                    header = 0;
+                  }
+
+                if (rd_header)
+                  {
+                    u_int16_t type;
+                    struct rd_as rd_as;
+                    struct rd_ip rd_ip;
+                    u_char *pnt;
+
+                    pnt = rn->p.u.val;
+
+                    /* Decode RD type. */
+                    type = decode_rd_type (pnt);
+                    /* Decode RD value. */
+                    if (type == RD_TYPE_AS)
+                      decode_rd_as (pnt + 2, &rd_as);
+                    else if (type == RD_TYPE_IP)
+                      decode_rd_ip (pnt + 2, &rd_ip);
+
+                    vty_out (vty, "Route Distinguisher: ");
+
+                    if (type == RD_TYPE_AS)
+                      vty_out (vty, "%d:%d", rd_as.as, rd_as.val);
+                    else if (type == RD_TYPE_IP)
+                      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+
+                    vty_out (vty, "%s", VTY_NEWLINE);
+                    rd_header = 0;
+                  }
+                route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN);
+              }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+enum bgp_show_type
+{
+  bgp_show_type_normal,
+  bgp_show_type_regexp,
+  bgp_show_type_prefix_list,
+  bgp_show_type_filter_list,
+  bgp_show_type_neighbor,
+  bgp_show_type_cidr_only,
+  bgp_show_type_prefix_longer,
+  bgp_show_type_community_all,
+  bgp_show_type_community,
+  bgp_show_type_community_exact,
+  bgp_show_type_community_list,
+  bgp_show_type_community_list_exact
+};
+
+int
+bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type,
+                  void *output_arg, int tags)
+{
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp_info *ri;
+  int rd_header;
+  int header = 1;
+  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s";
+  char v4_header_tag[] = "   Network          Next Hop      In tag/Out tag%s";
+
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn))
+    {
+      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+       continue;
+
+      if ((table = rn->info) != NULL)
+       {
+         rd_header = 1;
+
+         for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+           for (ri = rm->info; ri; ri = ri->next)
+             {
+               if (type == bgp_show_type_neighbor)
+                 {
+                   union sockunion *su = output_arg;
+
+                   if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
+                     continue;
+                 }
+               if (header)
+                 {
+                   if (tags)
+                     vty_out (vty, v4_header_tag, VTY_NEWLINE);
+                   else
+                     {
+                       vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+                                inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                       vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+                                VTY_NEWLINE);
+                       vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+                                VTY_NEWLINE, VTY_NEWLINE);
+                       vty_out (vty, v4_header, VTY_NEWLINE);
+                     }
+                   header = 0;
+                 }
+
+               if (rd_header)
+                 {
+                   u_int16_t type;
+                   struct rd_as rd_as;
+                   struct rd_ip rd_ip;
+                   u_char *pnt;
+
+                   pnt = rn->p.u.val;
+
+                   /* Decode RD type. */
+                   type = decode_rd_type (pnt);
+                   /* Decode RD value. */
+                   if (type == RD_TYPE_AS)
+                     decode_rd_as (pnt + 2, &rd_as);
+                   else if (type == RD_TYPE_IP)
+                     decode_rd_ip (pnt + 2, &rd_ip);
+
+                   vty_out (vty, "Route Distinguisher: ");
+
+                   if (type == RD_TYPE_AS)
+                     vty_out (vty, "%d:%d", rd_as.as, rd_as.val);
+                   else if (type == RD_TYPE_IP)
+                     vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+                 
+                   vty_out (vty, "%s", VTY_NEWLINE);             
+                   rd_header = 0;
+                 }
+               if (tags)
+                 route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN);
+               else
+                 route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN);
+             }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_vpnv4_all,
+       show_ip_bgp_vpnv4_all_cmd,
+       "show ip bgp vpnv4 all",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n")
+{
+  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd,
+       show_ip_bgp_vpnv4_rd_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_tags,
+       show_ip_bgp_vpnv4_all_tags_cmd,
+       "show ip bgp vpnv4 all tags",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Display BGP tags for prefixes\n")
+{
+  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL,  1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_tags,
+       show_ip_bgp_vpnv4_rd_tags_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Display BGP tags for prefixes\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes,
+       show_ip_bgp_vpnv4_all_neighbor_routes_cmd,
+       "show ip bgp vpnv4 all neighbors A.B.C.D routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  union sockunion *su;
+  struct peer *peer;
+  
+  su = sockunion_str2su (argv[0]);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
+               return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes,
+       show_ip_bgp_vpnv4_rd_neighbor_routes_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  int ret;
+  union sockunion *su;
+  struct peer *peer;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  su = sockunion_str2su (argv[1]);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
+               return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes,
+       show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd,
+       "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+  union sockunion su;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return show_adj_route_vpn (vty, peer, NULL);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes,
+       show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+  struct prefix_rd prd;
+  union sockunion su;
+
+  ret = str2sockunion (argv[1], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return show_adj_route_vpn (vty, peer, &prd);
+}
+
+void
+bgp_mplsvpn_init ()
+{
+  install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd);
+  install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd);
+
+
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd);
+
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd);
+}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
new file mode 100644 (file)
index 0000000..cd861a8
--- /dev/null
@@ -0,0 +1,45 @@
+/* MPLS-VPN
+   Copyright (C) 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 RD_TYPE_AS      0
+#define RD_TYPE_IP      1
+
+#define RD_ADDRSTRLEN  28
+
+struct rd_as
+{
+  u_int16_t type;
+  as_t as;
+  u_int32_t val;
+};
+
+struct rd_ip
+{
+  u_int16_t type;
+  struct in_addr ip;
+  u_int16_t val;
+};
+
+void bgp_mplsvpn_init ();
+int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *);
+u_int32_t decode_label (u_char *);
+int str2prefix_rd (u_char *, struct prefix_rd *);
+int str2tag (u_char *, u_char *);
+char *prefix_rd2str (struct prefix_rd *, char *, size_t);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
new file mode 100644 (file)
index 0000000..40e9cdb
--- /dev/null
@@ -0,0 +1,381 @@
+/* BGP network related fucntions
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "log.h"
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_network.h"
+\f
+/* Accept bgp connection. */
+static int
+bgp_accept (struct thread *thread)
+{
+  int bgp_sock;
+  int accept_sock;
+  union sockunion su;
+  struct peer *peer;
+  struct peer *peer1;
+  struct bgp *bgp;
+  char buf[SU_ADDRSTRLEN];
+
+  /* Regiser accept thread. */
+  accept_sock = THREAD_FD (thread);
+  bgp = THREAD_ARG (thread);
+
+  if (accept_sock < 0)
+    {
+      zlog_err ("accept_sock is nevative value %d", accept_sock);
+      return -1;
+    }
+  thread_add_read (master, bgp_accept, bgp, accept_sock);
+
+  /* Accept client connection. */
+  bgp_sock = sockunion_accept (accept_sock, &su);
+  if (bgp_sock < 0)
+    {
+      zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno));
+      return -1;
+    }
+
+  if (BGP_DEBUG (events, EVENTS))
+    zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
+  
+  /* Check remote IP address */
+  peer1 = peer_lookup (bgp, &su);
+  if (! peer1 || peer1->status == Idle)
+    {
+      if (BGP_DEBUG (events, EVENTS))
+       {
+         if (! peer1)
+           zlog_info ("[Event] BGP connection IP address %s is not configured",
+                      inet_sutop (&su, buf));
+         else
+           zlog_info ("[Event] BGP connection IP address %s is Idle state",
+                      inet_sutop (&su, buf));
+       }
+      close (bgp_sock);
+      return -1;
+    }
+
+  /* In case of peer is EBGP, we should set TTL for this connection.  */
+  if (peer_sort (peer1) == BGP_PEER_EBGP)
+    sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl);
+
+  if (! bgp)
+    bgp = peer1->bgp;
+
+  /* Make dummy peer until read Open packet. */
+  if (BGP_DEBUG (events, EVENTS))
+    zlog_info ("[Event] Make dummy peer structure until read Open packet");
+
+  {
+    char buf[SU_ADDRSTRLEN + 1];
+
+    peer = peer_create_accept (bgp);
+    SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
+    peer->su = su;
+    peer->fd = bgp_sock;
+    peer->status = Active;
+    peer->local_id = peer1->local_id;
+
+    /* Make peer's address string. */
+    sockunion2str (&su, buf, SU_ADDRSTRLEN);
+    peer->host = strdup (buf);
+  }
+
+  BGP_EVENT_ADD (peer, TCP_connection_open);
+
+  return 0;
+}
+
+/* BGP socket bind. */
+int
+bgp_bind (struct peer *peer)
+{
+#ifdef SO_BINDTODEVICE
+  int ret;
+  struct ifreq ifreq;
+
+  if (! peer->ifname)
+    return 0;
+
+  strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name));
+
+  ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE, 
+                   &ifreq, sizeof (ifreq));
+  if (ret < 0)
+    {
+      zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname);
+      return ret;
+    }
+#endif /* SO_BINDTODEVICE */
+  return 0;
+}
+
+int
+bgp_bind_address (int sock, struct in_addr *addr)
+{
+  int ret;
+  struct sockaddr_in local;
+
+  memset (&local, 0, sizeof (struct sockaddr_in));
+  local.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  local.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
+
+  ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
+  if (ret < 0)
+    ;
+  return 0;
+}
+
+struct in_addr *
+bgp_update_address (struct interface *ifp)
+{
+  struct prefix_ipv4 *p;
+  struct connected *connected;
+  listnode node;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      connected = getdata (node);
+
+      p = (struct prefix_ipv4 *) connected->address;
+
+      if (p->family == AF_INET)
+       return &p->prefix;
+    }
+  return NULL;
+}
+
+/* Update source selection.  */
+void
+bgp_update_source (struct peer *peer)
+{
+  struct interface *ifp;
+  struct in_addr *addr;
+
+  /* Source is specified with interface name.  */
+  if (peer->update_if)
+    {
+      ifp = if_lookup_by_name (peer->update_if);
+      if (! ifp)
+       return;
+
+      addr = bgp_update_address (ifp);
+      if (! addr)
+       return;
+
+      bgp_bind_address (peer->fd, addr);
+    }
+
+  /* Source is specified with IP address.  */
+  if (peer->update_source)
+    sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source);
+}
+
+/* BGP try to connect to the peer.  */
+int
+bgp_connect (struct peer *peer)
+{
+  unsigned int ifindex = 0;
+
+  /* Make socket for the peer. */
+  peer->fd = sockunion_socket (&peer->su);
+  if (peer->fd < 0)
+    return -1;
+
+  /* If we can get socket for the peer, adjest TTL and make connection. */
+  if (peer_sort (peer) == BGP_PEER_EBGP)
+    sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
+
+  sockopt_reuseaddr (peer->fd);
+  sockopt_reuseport (peer->fd);
+
+  /* Bind socket. */
+  bgp_bind (peer);
+
+  /* Update source bind. */
+  bgp_update_source (peer);
+
+#ifdef HAVE_IPV6
+  if (peer->ifname)
+    ifindex = if_nametoindex (peer->ifname);
+#endif /* HAVE_IPV6 */
+
+  if (BGP_DEBUG (events, EVENTS))
+    plog_info (peer->log, "%s [Event] Connect start to %s fd %d",
+              peer->host, peer->host, peer->fd);
+
+  /* Connect to the remote peer. */
+  return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex);
+}
+
+/* After TCP connection is established.  Get local address and port. */
+void
+bgp_getsockname (struct peer *peer)
+{
+  if (peer->su_local)
+    {
+      XFREE (MTYPE_TMP, peer->su_local);
+      peer->su_local = NULL;
+    }
+
+  if (peer->su_remote)
+    {
+      XFREE (MTYPE_TMP, peer->su_remote);
+      peer->su_remote = NULL;
+    }
+
+  peer->su_local = sockunion_getsockname (peer->fd);
+  peer->su_remote = sockunion_getpeername (peer->fd);
+
+  bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
+}
+
+/* IPv6 supported version of BGP server socket setup.  */
+#if defined (HAVE_IPV6) && ! defined (NRL)
+int
+bgp_socket (struct bgp *bgp, unsigned short port)
+{
+  int ret;
+  struct addrinfo req;
+  struct addrinfo *ainfo;
+  struct addrinfo *ainfo_save;
+  int sock = 0;
+  char port_str[BUFSIZ];
+
+  memset (&req, 0, sizeof (struct addrinfo));
+
+  req.ai_flags = AI_PASSIVE;
+  req.ai_family = AF_UNSPEC;
+  req.ai_socktype = SOCK_STREAM;
+  sprintf (port_str, "%d", port);
+  port_str[sizeof (port_str) - 1] = '\0';
+
+  ret = getaddrinfo (NULL, port_str, &req, &ainfo);
+  if (ret != 0)
+    {
+      zlog_err ("getaddrinfo: %s", gai_strerror (ret));
+      return -1;
+    }
+
+  ainfo_save = ainfo;
+
+  do
+    {
+      if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
+       continue;
+     
+      sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
+      if (sock < 0)
+       {
+         zlog_err ("socket: %s", strerror (errno));
+         continue;
+       }
+
+      sockopt_reuseaddr (sock);
+      sockopt_reuseport (sock);
+
+      ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
+      if (ret < 0)
+       {
+         zlog_err ("bind: %s", strerror (errno));
+         close (sock);
+         continue;
+       }
+      ret = listen (sock, 3);
+      if (ret < 0) 
+       {
+         zlog_err ("listen: %s", strerror (errno));
+         close (sock);
+         continue;
+       }
+
+      thread_add_read (master, bgp_accept, bgp, sock);
+    }
+  while ((ainfo = ainfo->ai_next) != NULL);
+
+  freeaddrinfo (ainfo_save);
+
+  return sock;
+}
+#else
+/* Traditional IPv4 only version.  */
+int
+bgp_socket (struct bgp *bgp, unsigned short port)
+{
+  int sock;
+  int socklen;
+  struct sockaddr_in sin;
+  int ret;
+
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      zlog_err ("socket: %s", strerror (errno));
+      return sock;
+    }
+
+  sockopt_reuseaddr (sock);
+  sockopt_reuseport (sock);
+
+  memset (&sin, 0, sizeof (struct sockaddr_in));
+
+  sin.sin_family = AF_INET;
+  sin.sin_port = htons (port);
+  socklen = sizeof (struct sockaddr_in);
+#ifdef HAVE_SIN_LEN
+  sin.sin_len = socklen;
+#endif /* HAVE_SIN_LEN */
+
+  ret = bind (sock, (struct sockaddr *) &sin, socklen);
+  if (ret < 0)
+    {
+      zlog_err ("bind: %s", strerror (errno));
+      close (sock);
+      return ret;
+    }
+  ret = listen (sock, 3);
+  if (ret < 0) 
+    {
+      zlog_err ("listen: %s", strerror (errno));
+      close (sock);
+      return ret;
+    }
+
+  thread_add_read (bm->master, bgp_accept, bgp, sock);
+
+  return sock;
+}
+#endif /* HAVE_IPV6 && !NRL */
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
new file mode 100644 (file)
index 0000000..b994987
--- /dev/null
@@ -0,0 +1,23 @@
+/* BGP network related header
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+int bgp_socket (struct bgp *, unsigned short);
+int bgp_connect (struct peer *);
+void bgp_getsockname (struct peer *);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
new file mode 100644 (file)
index 0000000..24a113d
--- /dev/null
@@ -0,0 +1,1405 @@
+/* BGP nexthop scan
+   Copyright (C) 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "thread.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
+#include "log.h"
+#include "memory.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_damp.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"       /* For ZEBRA_SERV_PATH. */
+
+struct bgp_nexthop_cache *zlookup_query (struct in_addr);
+#ifdef HAVE_IPV6
+struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
+#endif /* HAVE_IPV6 */
+\f
+/* Only one BGP scan thread are activated at the same time. */
+struct thread *bgp_scan_thread = NULL;
+
+/* BGP import thread */
+struct thread *bgp_import_thread = NULL;
+
+/* BGP scan interval. */
+int bgp_scan_interval;
+
+/* BGP import interval. */
+int bgp_import_interval;
+
+/* Route table for next-hop lookup cache. */
+struct bgp_table *bgp_nexthop_cache_ipv4;
+struct bgp_table *cache1;
+struct bgp_table *cache2;
+
+/* Route table for next-hop lookup cache. */
+struct bgp_table *bgp_nexthop_cache_ipv6;
+struct bgp_table *cache6_1;
+struct bgp_table *cache6_2;
+
+/* Route table for connected route. */
+struct bgp_table *bgp_connected_ipv4;
+
+/* Route table for connected route. */
+struct bgp_table *bgp_connected_ipv6;
+
+/* BGP nexthop lookup query client. */
+static struct zclient *zlookup = NULL;
+
+/* BGP process function. */
+int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
+\f
+/* Add nexthop to the end of the list.  */
+void
+bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop)
+{
+  struct nexthop *last;
+
+  for (last = bnc->nexthop; last && last->next; last = last->next)
+    ;
+  if (last)
+    last->next = nexthop;
+  else
+    bnc->nexthop = nexthop;
+  nexthop->prev = last;
+}
+
+void
+bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
+{
+  struct nexthop *nexthop;
+  struct nexthop *next = NULL;
+
+  for (nexthop = bnc->nexthop; nexthop; nexthop = next)
+    {
+      next = nexthop->next;
+      XFREE (MTYPE_NEXTHOP, nexthop);
+    }
+}
+
+struct bgp_nexthop_cache *
+bnc_new ()
+{
+  struct bgp_nexthop_cache *new;
+
+  new = XMALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache));
+  memset (new, 0, sizeof (struct bgp_nexthop_cache));
+  return new;
+}
+
+void
+bnc_free (struct bgp_nexthop_cache *bnc)
+{
+  bnc_nexthop_free (bnc);
+  XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc);
+}
+\f
+int
+bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2)
+{
+  if (next1->type != next2->type)
+    return 0;
+
+  switch (next1->type)
+    {
+    case ZEBRA_NEXTHOP_IPV4:
+      if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
+       return 0;
+      break;
+    case ZEBRA_NEXTHOP_IFINDEX:
+    case ZEBRA_NEXTHOP_IFNAME:
+      if (next1->ifindex != next2->ifindex)
+       return 0;
+      break;
+#ifdef HAVE_IPV6
+    case ZEBRA_NEXTHOP_IPV6:
+      if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+       return 0;
+      break;
+    case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+    case ZEBRA_NEXTHOP_IPV6_IFNAME:
+      if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+       return 0;
+      if (next1->ifindex != next2->ifindex)
+       return 0;
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return 1;
+}
+
+int
+bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1,
+                          struct bgp_nexthop_cache *bnc2)
+{
+  int i;
+  struct nexthop *next1, *next2;
+
+  if (bnc1->nexthop_num != bnc2->nexthop_num)
+    return 1;
+
+  next1 = bnc1->nexthop;
+  next2 = bnc2->nexthop;
+
+  for (i = 0; i < bnc1->nexthop_num; i++)
+    {
+      if (! bgp_nexthop_same (next1, next2))
+       return 1;
+
+      next1 = next1->next;
+      next2 = next2->next;
+    }
+  return 0;
+}
+
+/* If nexthop exists on connected network return 1. */
+int
+bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr)
+{
+  struct bgp_node *rn;
+
+  /* If zebra is not enabled return */
+  if (zlookup->sock < 0)
+    return 1;
+
+  /* Lookup the address is onlink or not. */
+  if (afi == AFI_IP)
+    {
+      rn = bgp_node_match_ipv4 (bgp_connected_ipv4, &attr->nexthop);
+      if (rn)
+       {
+         bgp_unlock_node (rn);
+         return 1;
+       }
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      if (attr->mp_nexthop_len == 32)
+       return 1;
+      else if (attr->mp_nexthop_len == 16)
+       {
+         if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global))
+           return 1;
+
+         rn = bgp_node_match_ipv6 (bgp_connected_ipv6,
+                                     &attr->mp_nexthop_global);
+         if (rn)
+           {
+             bgp_unlock_node (rn);
+             return 1;
+           }
+       }
+    }
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+/* Check specified next-hop is reachable or not. */
+int
+bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
+                        int *metricchanged)
+{
+  struct bgp_node *rn;
+  struct prefix p;
+  struct bgp_nexthop_cache *bnc;
+  struct attr *attr;
+
+  /* If lookup is not enabled, return valid. */
+  if (zlookup->sock < 0)
+    {
+      ri->igpmetric = 0;
+      return 1;
+    }
+
+  /* Only check IPv6 global address only nexthop. */
+  attr = ri->attr;
+
+  if (attr->mp_nexthop_len != 16 
+      || IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global))
+    return 1;
+
+  memset (&p, 0, sizeof (struct prefix));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_BITLEN;
+  p.u.prefix6 = attr->mp_nexthop_global;
+
+  /* IBGP or ebgp-multihop */
+  rn = bgp_node_get (bgp_nexthop_cache_ipv6, &p);
+
+  if (rn->info)
+    {
+      bnc = rn->info;
+      bgp_unlock_node (rn);
+    }
+  else
+    {
+      bnc = zlookup_query_ipv6 (&attr->mp_nexthop_global);
+      if (bnc)
+       {
+         struct bgp_table *old;
+         struct bgp_node *oldrn;
+         struct bgp_nexthop_cache *oldbnc;
+
+         if (changed)
+           {
+             if (bgp_nexthop_cache_ipv6 == cache6_1)
+               old = cache6_2;
+             else
+               old = cache6_1;
+
+             oldrn = bgp_node_lookup (old, &p);
+             if (oldrn)
+               {
+                 oldbnc = oldrn->info;
+
+                 bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc);
+
+                 if (bnc->metric != oldbnc->metric)
+                   bnc->metricchanged = 1;
+               }
+           }
+       }
+      else
+       {
+         bnc = bnc_new ();
+         bnc->valid = 0;
+       }
+      rn->info = bnc;
+    }
+
+  if (changed)
+    *changed = bnc->changed;
+
+  if (metricchanged)
+    *metricchanged = bnc->metricchanged;
+
+  if (bnc->valid)
+    ri->igpmetric = bnc->metric;
+  else
+    ri->igpmetric = 0;
+
+  return bnc->valid;
+}
+#endif /* HAVE_IPV6 */
+
+/* Check specified next-hop is reachable or not. */
+int
+bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
+                   int *changed, int *metricchanged)
+{
+  struct bgp_node *rn;
+  struct prefix p;
+  struct bgp_nexthop_cache *bnc;
+  struct in_addr addr;
+
+  /* If lookup is not enabled, return valid. */
+  if (zlookup->sock < 0)
+    {
+      ri->igpmetric = 0;
+      return 1;
+    }
+
+#ifdef HAVE_IPV6
+  if (afi == AFI_IP6)
+    return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged);
+#endif /* HAVE_IPV6 */
+
+  addr = ri->attr->nexthop;
+
+  memset (&p, 0, sizeof (struct prefix));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.u.prefix4 = addr;
+
+  /* IBGP or ebgp-multihop */
+  rn = bgp_node_get (bgp_nexthop_cache_ipv4, &p);
+
+  if (rn->info)
+    {
+      bnc = rn->info;
+      bgp_unlock_node (rn);
+    }
+  else
+    {
+      bnc = zlookup_query (addr);
+      if (bnc)
+       {
+         struct bgp_table *old;
+         struct bgp_node *oldrn;
+         struct bgp_nexthop_cache *oldbnc;
+
+         if (changed)
+           {
+             if (bgp_nexthop_cache_ipv4 == cache1)
+               old = cache2;
+             else
+               old = cache1;
+
+             oldrn = bgp_node_lookup (old, &p);
+             if (oldrn)
+               {
+                 oldbnc = oldrn->info;
+
+                 bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc);
+
+                 if (bnc->metric != oldbnc->metric)
+                   bnc->metricchanged = 1;
+               }
+           }
+       }
+      else
+       {
+         bnc = bnc_new ();
+         bnc->valid = 0;
+       }
+      rn->info = bnc;
+    }
+
+  if (changed)
+    *changed = bnc->changed;
+
+  if (metricchanged)
+    *metricchanged = bnc->metricchanged;
+
+  if (bnc->valid)
+    ri->igpmetric = bnc->metric;
+  else
+    ri->igpmetric = 0;
+
+  return bnc->valid;
+}
+
+/* Reset and free all BGP nexthop cache. */
+void
+bgp_nexthop_cache_reset (struct bgp_table *table)
+{
+  struct bgp_node *rn;
+  struct bgp_nexthop_cache *bnc;
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    if ((bnc = rn->info) != NULL)
+      {
+       bnc_free (bnc);
+       rn->info = NULL;
+       bgp_unlock_node (rn);
+      }
+}
+
+void
+bgp_scan_ipv4 ()
+{
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct bgp_info *bi;
+  struct bgp_info *next;
+  struct peer *peer;
+  struct listnode *nn;
+  int valid;
+  int current;
+  int changed;
+  int metricchanged;
+
+  /* Change cache. */
+  if (bgp_nexthop_cache_ipv4 == cache1)
+    bgp_nexthop_cache_ipv4 = cache2;
+  else
+    bgp_nexthop_cache_ipv4 = cache1;
+
+  /* Get default bgp. */
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    return;
+
+  /* Maximum prefix check */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer->status != Established)
+       continue;
+
+      if (peer->afc[AFI_IP][SAFI_UNICAST])
+       bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_UNICAST);
+      if (peer->afc[AFI_IP][SAFI_MULTICAST])
+       bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_MULTICAST);
+      if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
+       bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_MPLS_VPN);
+    }
+
+  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]); rn;
+       rn = bgp_route_next (rn))
+    {
+      for (bi = rn->info; bi; bi = next)
+       {
+         next = bi->next;
+
+         if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL)
+           {
+             changed = 0;
+             metricchanged = 0;
+
+             if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1)
+               valid = bgp_nexthop_check_ebgp (AFI_IP, bi->attr);
+             else
+               valid = bgp_nexthop_lookup (AFI_IP, bi->peer, bi,
+                                           &changed, &metricchanged);
+
+             current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0;
+
+             if (changed)
+               SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
+             else
+               UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
+
+             if (valid != current)
+               {
+                 if (CHECK_FLAG (bi->flags, BGP_INFO_VALID))
+                   {
+                     bgp_aggregate_decrement (bgp, &rn->p, bi,
+                                              AFI_IP, SAFI_UNICAST);
+                     UNSET_FLAG (bi->flags, BGP_INFO_VALID);
+                   }
+                 else
+                   {
+                     SET_FLAG (bi->flags, BGP_INFO_VALID);
+                     bgp_aggregate_increment (bgp, &rn->p, bi,
+                                              AFI_IP, SAFI_UNICAST);
+                   }
+               }
+
+              if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST],
+                 BGP_CONFIG_DAMPENING)
+                  &&  bi->damp_info )
+                if (bgp_damp_scan (bi, AFI_IP, SAFI_UNICAST))
+                 bgp_aggregate_increment (bgp, &rn->p, bi,
+                                          AFI_IP, SAFI_UNICAST);
+           }
+       }
+      bgp_process (bgp, rn, AFI_IP, SAFI_UNICAST);
+    }
+
+  /* Flash old cache. */
+  if (bgp_nexthop_cache_ipv4 == cache1)
+    bgp_nexthop_cache_reset (cache2);
+  else
+    bgp_nexthop_cache_reset (cache1);
+}
+
+#ifdef HAVE_IPV6
+void
+bgp_scan_ipv6 ()
+{
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct bgp_info *bi;
+  struct bgp_info *next;
+  struct peer *peer;
+  struct listnode *nn;
+  int valid;
+  int current;
+  int changed;
+  int metricchanged;
+
+  /* Change cache. */
+  if (bgp_nexthop_cache_ipv6 == cache6_1)
+    bgp_nexthop_cache_ipv6 = cache6_2;
+  else
+    bgp_nexthop_cache_ipv6 = cache6_1;
+
+  /* Get default bgp. */
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    return;
+
+  /* Maximum prefix check */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer->status != Established)
+       continue;
+
+      if (peer->afc[AFI_IP6][SAFI_UNICAST])
+       bgp_maximum_prefix_overflow (peer, AFI_IP6, SAFI_UNICAST);
+      if (peer->afc[AFI_IP6][SAFI_MULTICAST])
+       bgp_maximum_prefix_overflow (peer, AFI_IP6, SAFI_MULTICAST);
+    }
+
+  for (rn = bgp_table_top (bgp->rib[AFI_IP6][SAFI_UNICAST]); rn;
+       rn = bgp_route_next (rn))
+    {
+      for (bi = rn->info; bi; bi = next)
+       {
+         next = bi->next;
+
+         if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL)
+           {
+             changed = 0;
+             metricchanged = 0;
+
+             if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1)
+               valid = 1;
+             else
+               valid = bgp_nexthop_lookup_ipv6 (bi->peer, bi,
+                                                &changed, &metricchanged);
+
+             current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0;
+
+             if (changed)
+               SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
+             else
+               UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
+
+             if (valid != current)
+               {
+                 if (CHECK_FLAG (bi->flags, BGP_INFO_VALID))
+                   {
+                     bgp_aggregate_decrement (bgp, &rn->p, bi,
+                                              AFI_IP6, SAFI_UNICAST);
+                     UNSET_FLAG (bi->flags, BGP_INFO_VALID);
+                   }
+                 else
+                   {
+                     SET_FLAG (bi->flags, BGP_INFO_VALID);
+                     bgp_aggregate_increment (bgp, &rn->p, bi,
+                                              AFI_IP6, SAFI_UNICAST);
+                   }
+               }
+
+              if (CHECK_FLAG (bgp->af_flags[AFI_IP6][SAFI_UNICAST],
+                 BGP_CONFIG_DAMPENING)
+                  &&  bi->damp_info )
+                if (bgp_damp_scan (bi, AFI_IP6, SAFI_UNICAST))
+                 bgp_aggregate_increment (bgp, &rn->p, bi,
+                                          AFI_IP6, SAFI_UNICAST);
+           }
+       }
+      bgp_process (bgp, rn, AFI_IP6, SAFI_UNICAST);
+    }
+
+  /* Flash old cache. */
+  if (bgp_nexthop_cache_ipv6 == cache6_1)
+    bgp_nexthop_cache_reset (cache6_2);
+  else
+    bgp_nexthop_cache_reset (cache6_1);
+}
+#endif /* HAVE_IPV6 */
+
+/* BGP scan thread.  This thread check nexthop reachability. */
+int
+bgp_scan (struct thread *t)
+{
+  bgp_scan_thread =
+    thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("Performing BGP general scanning");
+
+  bgp_scan_ipv4 ();
+
+#ifdef HAVE_IPV6
+  bgp_scan_ipv6 ();
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+\f
+struct bgp_connected
+{
+  unsigned int refcnt;
+};
+
+void
+bgp_connected_add (struct connected *ifc)
+{
+  struct prefix p;
+  struct prefix *addr;
+  struct prefix *dest;
+  struct interface *ifp;
+  struct bgp_node *rn;
+  struct bgp_connected *bc;
+
+  ifp = ifc->ifp;
+
+  if (! ifp)
+    return;
+
+  if (if_is_loopback (ifp))
+    return;
+
+  addr = ifc->address;
+  dest = ifc->destination;
+
+  if (addr->family == AF_INET)
+    {
+      memset (&p, 0, sizeof (struct prefix));
+      p.family = AF_INET;
+      p.prefixlen = addr->prefixlen;
+
+      if (if_is_pointopoint (ifp))
+       p.u.prefix4 = dest->u.prefix4;
+      else
+       p.u.prefix4 = addr->u.prefix4;
+
+      apply_mask_ipv4 ((struct prefix_ipv4 *) &p);
+
+      if (prefix_ipv4_any ((struct prefix_ipv4 *) &p))
+       return;
+
+      rn = bgp_node_get (bgp_connected_ipv4, (struct prefix *) &p);
+      if (rn->info)
+       {
+         bc = rn->info;
+         bc->refcnt++;
+       }
+      else
+       {
+         bc = XMALLOC (0, sizeof (struct bgp_connected));
+         memset (bc, 0, sizeof (struct bgp_connected));
+         bc->refcnt = 1;
+         rn->info = bc;
+       }
+    }
+#ifdef HAVE_IPV6
+  if (addr->family == AF_INET6)
+    {
+      memset (&p, 0, sizeof (struct prefix));
+      p.family = AF_INET6;
+      p.prefixlen = addr->prefixlen;
+
+      if (if_is_pointopoint (ifp))
+       p.u.prefix6 = dest->u.prefix6;
+      else
+       p.u.prefix6 = addr->u.prefix6;
+
+      apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
+
+      if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6))
+       return;
+
+      if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+       return;
+
+      rn = bgp_node_get (bgp_connected_ipv6, (struct prefix *) &p);
+      if (rn->info)
+       {
+         bc = rn->info;
+         bc->refcnt++;
+       }
+      else
+       {
+         bc = XMALLOC (0, sizeof (struct bgp_connected));
+         memset (bc, 0, sizeof (struct bgp_connected));
+         bc->refcnt = 1;
+         rn->info = bc;
+       }
+    }
+#endif /* HAVE_IPV6 */
+}
+
+void
+bgp_connected_delete (struct connected *ifc)
+{
+  struct prefix p;
+  struct prefix *addr;
+  struct prefix *dest;
+  struct interface *ifp;
+  struct bgp_node *rn;
+  struct bgp_connected *bc;
+
+  ifp = ifc->ifp;
+
+  if (if_is_loopback (ifp))
+    return;
+
+  addr = ifc->address;
+  dest = ifc->destination;
+
+  if (addr->family == AF_INET)
+    {
+      memset (&p, 0, sizeof (struct prefix));
+      p.family = AF_INET;
+      p.prefixlen = addr->prefixlen;
+
+      if (if_is_pointopoint (ifp))
+       p.u.prefix4 = dest->u.prefix4;
+      else
+       p.u.prefix4 = addr->u.prefix4;
+
+      apply_mask_ipv4 ((struct prefix_ipv4 *) &p);
+
+      if (prefix_ipv4_any ((struct prefix_ipv4 *) &p))
+       return;
+
+      rn = bgp_node_lookup (bgp_connected_ipv4, &p);
+      if (! rn)
+       return;
+
+      bc = rn->info;
+      bc->refcnt--;
+      if (bc->refcnt == 0)
+       {
+         XFREE (0, bc);
+         rn->info = NULL;
+       }
+      bgp_unlock_node (rn);
+      bgp_unlock_node (rn);
+    }
+#ifdef HAVE_IPV6
+  else if (addr->family == AF_INET6)
+    {
+      memset (&p, 0, sizeof (struct prefix));
+      p.family = AF_INET6;
+      p.prefixlen = addr->prefixlen;
+
+      if (if_is_pointopoint (ifp))
+       p.u.prefix6 = dest->u.prefix6;
+      else
+       p.u.prefix6 = addr->u.prefix6;
+
+      apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
+
+      if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6))
+       return;
+
+      if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+       return;
+
+      rn = bgp_node_lookup (bgp_connected_ipv6, (struct prefix *) &p);
+      if (! rn)
+       return;
+
+      bc = rn->info;
+      bc->refcnt--;
+      if (bc->refcnt == 0)
+       {
+         XFREE (0, bc);
+         rn->info = NULL;
+       }
+      bgp_unlock_node (rn);
+      bgp_unlock_node (rn);
+    }
+#endif /* HAVE_IPV6 */
+}
+
+int
+bgp_nexthop_self (afi_t afi, struct attr *attr)
+{
+  listnode node;
+  listnode node2;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (node2 = listhead (ifp->connected); node2; nextnode (node2))
+       {
+         ifc = getdata (node2);
+         p = ifc->address;
+
+         if (p && p->family == AF_INET 
+             && IPV4_ADDR_SAME (&p->u.prefix4, &attr->nexthop))
+           return 1;
+       }
+    }
+  return 0;
+}
+\f
+struct bgp_nexthop_cache *
+zlookup_read ()
+{
+  struct stream *s;
+  u_int16_t length;
+  u_char command;
+  int nbytes;
+  struct in_addr raddr;
+  u_int32_t metric;
+  int i;
+  u_char nexthop_num;
+  struct nexthop *nexthop;
+  struct bgp_nexthop_cache *bnc;
+
+  s = zlookup->ibuf;
+  stream_reset (s);
+
+  nbytes = stream_read (s, zlookup->sock, 2);
+  length = stream_getw (s);
+
+  nbytes = stream_read (s, zlookup->sock, length - 2);
+  command = stream_getc (s);
+  raddr.s_addr = stream_get_ipv4 (s);
+  metric = stream_getl (s);
+  nexthop_num = stream_getc (s);
+
+  if (nexthop_num)
+    {
+      bnc = bnc_new ();
+      bnc->valid = 1;
+      bnc->metric = metric;
+      bnc->nexthop_num = nexthop_num;
+
+      for (i = 0; i < nexthop_num; i++)
+       {
+         nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+         memset (nexthop, 0, sizeof (struct nexthop));
+         nexthop->type = stream_getc (s);
+         switch (nexthop->type)
+           {
+           case ZEBRA_NEXTHOP_IPV4:
+             nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+             break;
+           case ZEBRA_NEXTHOP_IFINDEX:
+           case ZEBRA_NEXTHOP_IFNAME:
+             nexthop->ifindex = stream_getl (s);
+             break;
+           }
+         bnc_nexthop_add (bnc, nexthop);
+       }
+    }
+  else
+    return NULL;
+
+  return bnc;
+}
+
+struct bgp_nexthop_cache *
+zlookup_query (struct in_addr addr)
+{
+  int ret;
+  struct stream *s;
+
+  /* Check socket. */
+  if (zlookup->sock < 0)
+    return NULL;
+
+  s = zlookup->obuf;
+  stream_reset (s);
+  stream_putw (s, 7);
+  stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
+  stream_put_in_addr (s, &addr);
+
+  ret = writen (zlookup->sock, s->data, 7);
+  if (ret < 0)
+    {
+      zlog_err ("can't write to zlookup->sock");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return NULL;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("zlookup->sock connection closed");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return NULL;
+    }
+
+  return zlookup_read ();
+}
+
+#ifdef HAVE_IPV6
+struct bgp_nexthop_cache *
+zlookup_read_ipv6 ()
+{
+  struct stream *s;
+  u_int16_t length;
+  u_char command;
+  int nbytes;
+  struct in6_addr raddr;
+  u_int32_t metric;
+  int i;
+  u_char nexthop_num;
+  struct nexthop *nexthop;
+  struct bgp_nexthop_cache *bnc;
+
+  s = zlookup->ibuf;
+  stream_reset (s);
+
+  nbytes = stream_read (s, zlookup->sock, 2);
+  length = stream_getw (s);
+
+  nbytes = stream_read (s, zlookup->sock, length - 2);
+  command = stream_getc (s);
+
+  stream_get (&raddr, s, 16);
+
+  metric = stream_getl (s);
+  nexthop_num = stream_getc (s);
+
+  if (nexthop_num)
+    {
+      bnc = bnc_new ();
+      bnc->valid = 1;
+      bnc->metric = metric;
+      bnc->nexthop_num = nexthop_num;
+
+      for (i = 0; i < nexthop_num; i++)
+       {
+         nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+         memset (nexthop, 0, sizeof (struct nexthop));
+         nexthop->type = stream_getc (s);
+         switch (nexthop->type)
+           {
+           case ZEBRA_NEXTHOP_IPV6:
+             stream_get (&nexthop->gate.ipv6, s, 16);
+             break;
+           case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+           case ZEBRA_NEXTHOP_IPV6_IFNAME:
+             stream_get (&nexthop->gate.ipv6, s, 16);
+             nexthop->ifindex = stream_getl (s);
+             break;
+           case ZEBRA_NEXTHOP_IFINDEX:
+           case ZEBRA_NEXTHOP_IFNAME:
+             nexthop->ifindex = stream_getl (s);
+             break;
+           }
+         bnc_nexthop_add (bnc, nexthop);
+       }
+    }
+  else
+    return NULL;
+
+  return bnc;
+}
+
+struct bgp_nexthop_cache *
+zlookup_query_ipv6 (struct in6_addr *addr)
+{
+  int ret;
+  struct stream *s;
+
+  /* Check socket. */
+  if (zlookup->sock < 0)
+    return NULL;
+
+  s = zlookup->obuf;
+  stream_reset (s);
+  stream_putw (s, 19);
+  stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
+  stream_put (s, addr, 16);
+
+  ret = writen (zlookup->sock, s->data, 19);
+  if (ret < 0)
+    {
+      zlog_err ("can't write to zlookup->sock");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return NULL;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("zlookup->sock connection closed");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return NULL;
+    }
+
+  return zlookup_read_ipv6 ();
+}
+#endif /* HAVE_IPV6 */
+
+int
+bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop)
+{
+  struct stream *s;
+  int ret;
+  u_int16_t length;
+  u_char command;
+  int nbytes;
+  struct in_addr addr;
+  struct in_addr nexthop;
+  u_int32_t metric = 0;
+  u_char nexthop_num;
+  u_char nexthop_type;
+
+  /* If lookup connection is not available return valid. */
+  if (zlookup->sock < 0)
+    {
+      if (igpmetric)
+       *igpmetric = 0;
+      return 1;
+    }
+
+  /* Send query to the lookup connection */
+  s = zlookup->obuf;
+  stream_reset (s);
+  stream_putw (s, 8);
+  stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP);
+  stream_putc (s, p->prefixlen);
+  stream_put_in_addr (s, &p->u.prefix4);
+
+  /* Write the packet. */
+  ret = writen (zlookup->sock, s->data, 8);
+
+  if (ret < 0)
+    {
+      zlog_err ("can't write to zlookup->sock");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return 1;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("zlookup->sock connection closed");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return 1;
+    }
+
+  /* Get result. */
+  stream_reset (s);
+
+  /* Fetch length. */
+  nbytes = stream_read (s, zlookup->sock, 2);
+  length = stream_getw (s);
+
+  /* Fetch whole data. */
+  nbytes = stream_read (s, zlookup->sock, length - 2);
+  command = stream_getc (s);
+  addr.s_addr = stream_get_ipv4 (s);
+  metric = stream_getl (s);
+  nexthop_num = stream_getc (s);
+
+  /* Set IGP metric value. */
+  if (igpmetric)
+    *igpmetric = metric;
+
+  /* If there is nexthop then this is active route. */
+  if (nexthop_num)
+    {
+      nexthop.s_addr = 0;
+      nexthop_type = stream_getc (s);
+      if (nexthop_type == ZEBRA_NEXTHOP_IPV4)
+       {
+         nexthop.s_addr = stream_get_ipv4 (s);
+         if (igpnexthop)
+           *igpnexthop = nexthop;
+       }
+      else
+       *igpnexthop = nexthop;
+
+      return 1;
+    }
+  else
+    return 0;
+}
+
+/* Scan all configured BGP route then check the route exists in IGP or
+   not. */
+int
+bgp_import (struct thread *t)
+{
+  struct bgp *bgp;
+  struct bgp_node *rn;
+  struct bgp_static *bgp_static;
+  int valid;
+  u_int32_t metric;
+  struct in_addr nexthop;
+  afi_t afi;
+  safi_t safi;
+
+  bgp_import_thread = 
+    thread_add_timer (master, bgp_import, NULL, bgp_import_interval);
+
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return 0;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++)
+      for (rn = bgp_table_top (bgp->route[afi][safi]); rn;
+          rn = bgp_route_next (rn))
+       if ((bgp_static = rn->info) != NULL)
+         {
+           if (bgp_static->backdoor)
+             continue;
+
+           valid = bgp_static->valid;
+           metric = bgp_static->igpmetric;
+           nexthop = bgp_static->igpnexthop;
+
+           if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)
+               && afi == AFI_IP && safi == SAFI_UNICAST)
+             bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric,
+                                                   &bgp_static->igpnexthop);
+           else
+             {
+               bgp_static->valid = 1;
+               bgp_static->igpmetric = 0;
+               bgp_static->igpnexthop.s_addr = 0;
+             }
+
+           if (bgp_static->valid != valid)
+             {
+               if (bgp_static->valid)
+                 bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
+               else
+                 bgp_static_withdraw (bgp, &rn->p, afi, safi);
+             }
+           else if (bgp_static->valid)
+             {
+               if (bgp_static->igpmetric != metric
+                   || bgp_static->igpnexthop.s_addr != nexthop.s_addr
+                   || bgp_static->rmap.name)
+                 bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
+             }
+         }
+  return 0;
+}
+
+/* Connect to zebra for nexthop lookup. */
+int
+zlookup_connect (struct thread *t)
+{
+  struct zclient *zlookup;
+
+  zlookup = THREAD_ARG (t);
+  zlookup->t_connect = NULL;
+
+  if (zlookup->sock != -1)
+    return 0;
+
+#ifdef HAVE_TCP_ZEBRA
+  zlookup->sock = zclient_socket ();
+#else
+  zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+  if (zlookup->sock < 0)
+    return -1;
+
+  /* Make BGP import there. */
+  bgp_import_thread = 
+    thread_add_timer (master, bgp_import, NULL, 0);
+
+  return 0;
+}
+
+/* Check specified multiaccess next-hop. */
+int
+bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer)
+{
+  struct bgp_node *rn1;
+  struct bgp_node *rn2;
+  struct prefix p1;
+  struct prefix p2;
+  struct in_addr addr;
+  int ret;
+
+  ret = inet_aton (peer, &addr);
+  if (! ret)
+    return 0;
+
+  memset (&p1, 0, sizeof (struct prefix));
+  p1.family = AF_INET;
+  p1.prefixlen = IPV4_MAX_BITLEN;
+  p1.u.prefix4 = nexthop;
+  memset (&p2, 0, sizeof (struct prefix));
+  p2.family = AF_INET;
+  p2.prefixlen = IPV4_MAX_BITLEN;
+  p2.u.prefix4 = addr;
+
+  /* If bgp scan is not enabled, return invalid. */
+  if (zlookup->sock < 0)
+    return 0;
+
+  rn1 = bgp_node_match (bgp_connected_ipv4, &p1);
+  if (! rn1)
+    return 0;
+  
+  rn2 = bgp_node_match (bgp_connected_ipv4, &p2);
+  if (! rn2)
+    return 0;
+
+  if (rn1 == rn2)
+    return 1;
+
+  return 0;
+}
+\f
+DEFUN (bgp_scan_time,
+       bgp_scan_time_cmd,
+       "bgp scan-time <5-60>",
+       "BGP specific commands\n"
+       "Configure background scanner interval\n"
+       "Scanner interval (seconds)\n")
+{
+  bgp_scan_interval = atoi (argv[0]);
+
+  if (bgp_scan_thread)
+    {
+      thread_cancel (bgp_scan_thread);
+      bgp_scan_thread = 
+       thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_scan_time,
+       no_bgp_scan_time_cmd,
+       "no bgp scan-time",
+       NO_STR
+       "BGP specific commands\n"
+       "Configure background scanner interval\n")
+{
+  bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
+
+  if (bgp_scan_thread)
+    {
+      thread_cancel (bgp_scan_thread);
+      bgp_scan_thread = 
+       thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_scan_time,
+       no_bgp_scan_time_val_cmd,
+       "no bgp scan-time <5-60>",
+       NO_STR
+       "BGP specific commands\n"
+       "Configure background scanner interval\n"
+       "Scanner interval (seconds)\n")
+
+DEFUN (show_ip_bgp_scan,
+       show_ip_bgp_scan_cmd,
+       "show ip bgp scan",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP scan status\n")
+{
+  struct bgp_node *rn;
+  struct bgp_nexthop_cache *bnc;
+
+  if (bgp_scan_thread)
+    vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
+  else
+    vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE);
+  vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE);
+
+  vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE);
+  for (rn = bgp_table_top (bgp_nexthop_cache_ipv4); rn; rn = bgp_route_next (rn))
+    if ((bnc = rn->info) != NULL)
+      {
+       if (bnc->valid)
+         vty_out (vty, " %s valid [IGP metric %d]%s",
+                  inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE);
+       else
+         vty_out (vty, " %s invalid%s",
+                  inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE);
+      }
+
+#ifdef HAVE_IPV6
+  {
+    char buf[BUFSIZ];
+    for (rn = bgp_table_top (bgp_nexthop_cache_ipv6); rn; rn = bgp_route_next (rn))
+      if ((bnc = rn->info) != NULL)
+       {
+         if (bnc->valid)
+           vty_out (vty, " %s valid [IGP metric %d]%s",
+                    inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+                    bnc->metric, VTY_NEWLINE);
+         else
+           vty_out (vty, " %s invalid%s",
+                    inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+                    VTY_NEWLINE);
+       }
+  }
+#endif /* HAVE_IPV6 */
+
+  vty_out (vty, "BGP connected route:%s", VTY_NEWLINE);
+  for (rn = bgp_table_top (bgp_connected_ipv4); rn; rn = bgp_route_next (rn))
+    if (rn->info != NULL)
+      vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+              VTY_NEWLINE);
+
+#ifdef HAVE_IPV6
+  {
+    char buf[BUFSIZ];
+
+    for (rn = bgp_table_top (bgp_connected_ipv6); rn; rn = bgp_route_next (rn))
+      if (rn->info != NULL)
+       vty_out (vty, " %s/%d%s",
+                inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+                rn->p.prefixlen,
+                VTY_NEWLINE);
+  }
+#endif /* HAVE_IPV6 */
+
+  return CMD_SUCCESS;
+}
+
+int
+bgp_config_write_scan_time (struct vty *vty)
+{
+  if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT)
+    vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+void
+bgp_scan_init ()
+{
+  zlookup = zclient_new ();
+  zlookup->sock = -1;
+  zlookup->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+  zlookup->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+  zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0);
+
+  bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
+  bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT;
+
+  cache1 = bgp_table_init ();
+  cache2 = bgp_table_init ();
+  bgp_nexthop_cache_ipv4 = cache1;
+
+  bgp_connected_ipv4 = bgp_table_init ();
+
+#ifdef HAVE_IPV6
+  cache6_1 = bgp_table_init ();
+  cache6_2 = bgp_table_init ();
+  bgp_nexthop_cache_ipv6 = cache6_1;
+  bgp_connected_ipv6 = bgp_table_init ();
+#endif /* HAVE_IPV6 */
+
+  /* Make BGP scan thread. */
+  bgp_scan_thread = thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval);
+
+  install_element (BGP_NODE, &bgp_scan_time_cmd);
+  install_element (BGP_NODE, &no_bgp_scan_time_cmd);
+  install_element (BGP_NODE, &no_bgp_scan_time_val_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_scan_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd);
+}
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
new file mode 100644 (file)
index 0000000..5f4255d
--- /dev/null
@@ -0,0 +1,52 @@
+/* BGP nexthop scan
+   Copyright (C) 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#define BGP_SCAN_INTERVAL_DEFAULT   60
+#define BGP_IMPORT_INTERVAL_DEFAULT 15
+
+/* BGP nexthop cache value structure. */
+struct bgp_nexthop_cache
+{
+  /* This nexthop exists in IGP. */
+  u_char valid;
+
+  /* Nexthop is changed. */
+  u_char changed;
+
+  /* Nexthop is changed. */
+  u_char metricchanged;
+
+  /* IGP route's metric. */
+  u_int32_t metric;
+
+  /* Nexthop number and nexthop linked list.*/
+  u_char nexthop_num;
+  struct nexthop *nexthop;
+};
+
+void bgp_scan_init ();
+int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *,
+                       int *, int *);
+void bgp_connected_add (struct connected *c);
+void bgp_connected_delete (struct connected *c);
+int bgp_multiaccess_check_v4 (struct in_addr, char *);
+int bgp_config_write_scan_time (struct vty *);
+int bgp_nexthop_check_ebgp (afi_t, struct attr *);
+int bgp_nexthop_self (afi_t, struct attr *);
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
new file mode 100644 (file)
index 0000000..a3e86b0
--- /dev/null
@@ -0,0 +1,793 @@
+/* BGP open message handling
+   Copyright (C) 1998, 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "log.h"
+#include "command.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_open.h"
+\f
+/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
+   negotiate remote peer supports extentions or not. But if
+   remote-peer doesn't supports negotiation process itself.  We would
+   like to do manual configuration.
+
+   So there is many configurable point.  First of all we want set each
+   peer whether we send capability negotiation to the peer or not.
+   Next, if we send capability to the peer we want to set my capabilty
+   inforation at each peer. */
+
+void
+bgp_capability_vty_out (struct vty *vty, struct peer *peer)
+{
+  u_char *pnt;
+  u_char *end;
+  struct capability cap;
+
+  pnt = peer->notify.data;
+  end = pnt + peer->notify.length;
+
+  while (pnt < end)
+    {
+      memcpy(&cap, pnt, sizeof(struct capability));
+
+      if (pnt + 2 > end)
+       return;
+      if (pnt + (cap.length + 2) > end)
+       return;
+
+      if (cap.code == CAPABILITY_CODE_MP)
+       {
+         vty_out (vty, "  Capability error for: Multi protocol ");
+
+         switch (ntohs (cap.mpc.afi))
+           {
+           case AFI_IP:
+             vty_out (vty, "AFI IPv4, ");
+             break;
+           case AFI_IP6:
+             vty_out (vty, "AFI IPv6, ");
+             break;
+           default:
+             vty_out (vty, "AFI Unknown %d, ", ntohs (cap.mpc.afi));
+             break;
+           }
+         switch (cap.mpc.safi)
+           {
+           case SAFI_UNICAST:
+             vty_out (vty, "SAFI Unicast");
+             break;
+           case SAFI_MULTICAST:
+             vty_out (vty, "SAFI Multicast");
+             break;
+           case SAFI_UNICAST_MULTICAST:
+             vty_out (vty, "SAFI Unicast Multicast");
+             break;
+           case BGP_SAFI_VPNV4:
+             vty_out (vty, "SAFI MPLS-VPN");
+             break;
+           default:
+             vty_out (vty, "SAFI Unknown %d ", cap.mpc.safi);
+             break;
+           }
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+      else if (cap.code >= 128)
+       vty_out (vty, "  Capability error: vendor specific capability code %d",
+                cap.code);
+      else
+       vty_out (vty, "  Capability error: unknown capability code %d", 
+                cap.code);
+
+      pnt += cap.length + 2;
+    }
+}
+
+/* Set negotiated capability value. */
+int
+bgp_capability_mp (struct peer *peer, struct capability *cap)
+{
+  if (ntohs (cap->mpc.afi) == AFI_IP)
+    {
+      if (cap->mpc.safi == SAFI_UNICAST)
+       {
+         peer->afc_recv[AFI_IP][SAFI_UNICAST] = 1;
+
+         if (peer->afc[AFI_IP][SAFI_UNICAST])
+           peer->afc_nego[AFI_IP][SAFI_UNICAST] = 1;
+         else
+           return -1;
+       }
+      else if (cap->mpc.safi == SAFI_MULTICAST) 
+       {
+         peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 1;
+
+         if (peer->afc[AFI_IP][SAFI_MULTICAST])
+           peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 1;
+         else
+           return -1;
+       }
+      else if (cap->mpc.safi == BGP_SAFI_VPNV4)
+       {
+         peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 1;
+
+         if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
+           peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 1;
+         else
+           return -1;
+       }
+      else
+       return -1;
+    }
+#ifdef HAVE_IPV6
+  else if (ntohs (cap->mpc.afi) == AFI_IP6)
+    {
+      if (cap->mpc.safi == SAFI_UNICAST)
+       {
+         peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 1;
+
+         if (peer->afc[AFI_IP6][SAFI_UNICAST])
+           peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 1;
+         else
+           return -1;
+       }
+      else if (cap->mpc.safi == SAFI_MULTICAST)
+       {
+         peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 1;
+
+         if (peer->afc[AFI_IP6][SAFI_MULTICAST])
+           peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 1;
+         else
+           return -1;
+       }
+      else
+       return -1;
+    }
+#endif /* HAVE_IPV6 */
+  else
+    {
+      /* Unknown Address Family. */
+      return -1;
+    }
+
+  return 0;
+}
+
+void
+bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
+                               u_char type, u_char mode)
+{
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
+              peer->host, afi, safi, type, mode);
+}
+
+int
+bgp_capability_orf (struct peer *peer, struct capability *cap,
+                   u_char *pnt)
+{
+  afi_t afi = ntohs(cap->mpc.afi);
+  safi_t safi = cap->mpc.safi;
+  u_char number_of_orfs;
+  u_char type;
+  u_char mode;
+  u_int16_t sm_cap = 0; /* capability send-mode receive */
+  u_int16_t rm_cap = 0; /* capability receive-mode receive */ 
+  int i;
+
+  /* Check length. */
+  if (cap->length < 7)
+    {
+      zlog_info ("%s ORF Capability length error %d",
+                peer->host, cap->length);
+                bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+      return -1;
+    }
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s OPEN has ORF CAP(%s) for afi/safi: %u/%u",
+              peer->host, (cap->code == CAPABILITY_CODE_ORF ?
+                       "new" : "old"), afi, safi);
+
+  /* Check AFI and SAFI. */
+  if ((afi != AFI_IP && afi != AFI_IP6)
+      || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+         && safi != BGP_SAFI_VPNV4))
+    {
+      zlog_info ("%s Addr-family %d/%d not supported. Ignoring the ORF capability",
+                 peer->host, afi, safi);
+      return -1;
+    }
+
+  number_of_orfs = *pnt++;
+
+  for (i = 0 ; i < number_of_orfs ; i++)
+    {
+      type = *pnt++;
+      mode = *pnt++;
+
+      /* ORF Mode error check */
+      if (mode != ORF_MODE_BOTH && mode != ORF_MODE_SEND
+         && mode != ORF_MODE_RECEIVE)
+       {
+         bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+         continue;
+       }
+
+      /* ORF Type and afi/safi error check */
+      if (cap->code == CAPABILITY_CODE_ORF)
+       {
+         if (type == ORF_TYPE_PREFIX &&
+             ((afi == AFI_IP && safi == SAFI_UNICAST)
+               || (afi == AFI_IP && safi == SAFI_MULTICAST)
+               || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
+           {
+             sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
+             rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
+             if (BGP_DEBUG (normal, NORMAL))
+               zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d",
+                          peer->host, ORF_TYPE_PREFIX, (mode == ORF_MODE_SEND ? "SEND" :
+                          mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi);
+           }
+         else
+           {
+             bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+             continue;
+           }
+       }
+      else if (cap->code == CAPABILITY_CODE_ORF_OLD)
+       {
+         if (type == ORF_TYPE_PREFIX_OLD &&
+             ((afi == AFI_IP && safi == SAFI_UNICAST)
+               || (afi == AFI_IP && safi == SAFI_MULTICAST)
+               || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
+           {
+             sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
+             rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
+             if (BGP_DEBUG (normal, NORMAL))
+               zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d",
+                          peer->host, ORF_TYPE_PREFIX_OLD, (mode == ORF_MODE_SEND ? "SEND" :
+                          mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi);
+           }
+         else
+           {
+             bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+             continue;
+           }
+       }
+      else
+       {
+         bgp_capability_orf_not_support (peer, afi, safi, type, mode);
+         continue;
+       }
+
+      switch (mode)
+       {
+         case ORF_MODE_BOTH:
+           SET_FLAG (peer->af_cap[afi][safi], sm_cap);
+           SET_FLAG (peer->af_cap[afi][safi], rm_cap);
+           break;
+         case ORF_MODE_SEND:
+           SET_FLAG (peer->af_cap[afi][safi], sm_cap);
+           break;
+         case ORF_MODE_RECEIVE:
+           SET_FLAG (peer->af_cap[afi][safi], rm_cap);
+           break;
+       }
+    }
+  return 0;
+}
+
+/* Parse given capability. */
+int
+bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length,
+                     u_char **error)
+{
+  int ret;
+  u_char *end;
+  struct capability cap;
+
+  end = pnt + length;
+
+  while (pnt < end)
+    {
+      afi_t afi;
+      safi_t safi;
+
+      /* Fetch structure to the byte stream. */
+      memcpy (&cap, pnt, sizeof (struct capability));
+
+      afi = ntohs(cap.mpc.afi);
+      safi = cap.mpc.safi;
+
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s OPEN has CAPABILITY code: %d, length %d",
+                  peer->host, cap.code, cap.length);
+
+      /* We need at least capability code and capability length. */
+      if (pnt + 2 > end)
+       {
+         zlog_info ("%s Capability length error", peer->host);
+         bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+         return -1;
+       }
+
+      /* Capability length check. */
+      if (pnt + (cap.length + 2) > end)
+       {
+         zlog_info ("%s Capability length error", peer->host);
+         bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+         return -1;
+       }
+
+      /* We know MP Capability Code. */
+      if (cap.code == CAPABILITY_CODE_MP)
+       {
+         if (BGP_DEBUG (normal, NORMAL))
+           zlog_info ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
+                      peer->host, afi, safi);
+
+         /* Ignore capability when override-capability is set. */
+         if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+           {
+             /* Set negotiated value. */
+             ret = bgp_capability_mp (peer, &cap);
+
+             /* Unsupported Capability. */
+             if (ret < 0)
+               {
+                 /* Store return data. */
+                 memcpy (*error, &cap, cap.length + 2);
+                 *error += cap.length + 2;
+               }
+           }
+       }
+      else if (cap.code == CAPABILITY_CODE_REFRESH
+              || cap.code == CAPABILITY_CODE_REFRESH_OLD)
+       {
+         /* Check length. */
+         if (cap.length != 0)
+           {
+             zlog_info ("%s Route Refresh Capability length error %d",
+                        peer->host, cap.length);
+             bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+             return -1;
+           }
+
+         if (BGP_DEBUG (normal, NORMAL))
+           zlog_info ("%s OPEN has ROUTE-REFRESH capability(%s) for all address-families",
+                      peer->host,
+                      cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new");
+
+         /* BGP refresh capability */
+         if (cap.code == CAPABILITY_CODE_REFRESH_OLD)
+           SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+         else
+           SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+       }
+      else if (cap.code == CAPABILITY_CODE_ORF
+              || cap.code == CAPABILITY_CODE_ORF_OLD)
+       bgp_capability_orf (peer, &cap, pnt + sizeof (struct capability));
+      else if (cap.code == CAPABILITY_CODE_DYNAMIC)
+       {
+         /* Check length. */
+         if (cap.length != 0)
+           {
+             zlog_info ("%s Dynamic Capability length error %d",
+                        peer->host, cap.length);
+             bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+             return -1;
+           }
+
+         if (BGP_DEBUG (normal, NORMAL))
+           zlog_info ("%s OPEN has DYNAMIC capability", peer->host);
+
+         SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
+       }
+      else if (cap.code > 128)
+       {
+         /* We don't send Notification for unknown vendor specific
+            capabilities.  It seems reasonable for now...  */
+         zlog_warn ("%s Vendor specific capability %d",
+                    peer->host, cap.code);
+       }
+      else
+       {
+         zlog_warn ("%s unrecognized capability code: %d - ignored",
+                    peer->host, cap.code);
+         memcpy (*error, &cap, cap.length + 2);
+         *error += cap.length + 2;
+       }
+
+      pnt += cap.length + 2;
+    }
+  return 0;
+}
+
+int
+bgp_auth_parse (struct peer *peer, u_char *pnt, size_t length)
+{
+  bgp_notify_send (peer, 
+                  BGP_NOTIFY_OPEN_ERR, 
+                  BGP_NOTIFY_OPEN_AUTH_FAILURE); 
+  return -1;
+}
+
+int
+strict_capability_same (struct peer *peer)
+{
+  int i, j;
+
+  for (i = AFI_IP; i < AFI_MAX; i++)
+    for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
+      if (peer->afc[i][j] != peer->afc_nego[i][j])
+       return 0;
+  return 1;
+}
+
+/* Parse open option */
+int
+bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
+{
+  int ret;
+  u_char *end;
+  u_char opt_type;
+  u_char opt_length;
+  u_char *pnt;
+  u_char *error;
+  u_char error_data[BGP_MAX_PACKET_SIZE];
+
+  /* Fetch pointer. */
+  pnt = stream_pnt (peer->ibuf);
+
+  ret = 0;
+  opt_type = 0;
+  opt_length = 0;
+  end = pnt + length;
+  error = error_data;
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s rcv OPEN w/ OPTION parameter len: %u",
+              peer->host, length);
+  
+  while (pnt < end) 
+    {
+      /* Check the length. */
+      if (pnt + 2 > end)
+       {
+         zlog_info ("%s Option length error", peer->host);
+         bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+         return -1;
+       }
+
+      /* Fetch option type and length. */
+      opt_type = *pnt++;
+      opt_length = *pnt++;
+      
+      /* Option length check. */
+      if (pnt + opt_length > end)
+       {
+         zlog_info ("%s Option length error", peer->host);
+         bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+         return -1;
+       }
+
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
+                  peer->host, opt_type,
+                  opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
+                  opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
+                  opt_length);
+  
+      switch (opt_type)
+       {
+       case BGP_OPEN_OPT_AUTH:
+         ret = bgp_auth_parse (peer, pnt, opt_length);
+         break;
+       case BGP_OPEN_OPT_CAP:
+         ret = bgp_capability_parse (peer, pnt, opt_length, &error);
+         *capability = 1;
+         break;
+       default:
+         bgp_notify_send (peer, 
+                          BGP_NOTIFY_OPEN_ERR, 
+                          BGP_NOTIFY_OPEN_UNSUP_PARAM); 
+         ret = -1;
+         break;
+       }
+
+      /* Parse error.  To accumulate all unsupported capability codes,
+         bgp_capability_parse does not return -1 when encounter
+         unsupported capability code.  To detect that, please check
+         error and erro_data pointer, like below.  */
+      if (ret < 0)
+       return -1;
+
+      /* Forward pointer. */
+      pnt += opt_length;
+    }
+
+  /* All OPEN option is parsed.  Check capability when strict compare
+     flag is enabled.*/
+  if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
+    {
+      /* If Unsupported Capability exists. */
+      if (error != error_data)
+       {
+         bgp_notify_send_with_data (peer, 
+                                    BGP_NOTIFY_OPEN_ERR, 
+                                    BGP_NOTIFY_OPEN_UNSUP_CAPBL, 
+                                    error_data, error - error_data);
+         return -1;
+       }
+
+      /* Check local capability does not negotiated with remote
+         peer. */
+      if (! strict_capability_same (peer))
+       {
+         bgp_notify_send (peer, 
+                          BGP_NOTIFY_OPEN_ERR, 
+                          BGP_NOTIFY_OPEN_UNSUP_CAPBL);
+         return -1;
+       }
+    }
+
+  /* Check there is no common capability send Unsupported Capability
+     error. */
+  if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+    {
+      if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] 
+         && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+         && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
+         && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
+         && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
+       {
+         plog_err (peer->log, "%s [Error] No common capability", peer->host);
+
+         if (error != error_data)
+
+           bgp_notify_send_with_data (peer, 
+                                      BGP_NOTIFY_OPEN_ERR, 
+                                      BGP_NOTIFY_OPEN_UNSUP_CAPBL, 
+                                      error_data, error - error_data);
+         else
+           bgp_notify_send (peer, 
+                            BGP_NOTIFY_OPEN_ERR, 
+                            BGP_NOTIFY_OPEN_UNSUP_CAPBL);
+         return -1;
+       }
+    }
+  return 0;
+}
+
+void
+bgp_open_capability_orf (struct stream *s, struct peer *peer,
+                         afi_t afi, safi_t safi, u_char code)
+{
+  u_char cap_len;
+  u_char orf_len;
+  unsigned long capp;
+  unsigned long orfp;
+  unsigned long numberp;
+  int number_of_orfs = 0;
+
+  if (safi == SAFI_MPLS_VPN)
+    safi = BGP_SAFI_VPNV4;
+
+  stream_putc (s, BGP_OPEN_OPT_CAP);
+  capp = stream_get_putp (s);           /* Set Capability Len Pointer */
+  stream_putc (s, 0);                   /* Capability Length */
+  stream_putc (s, code);                /* Capability Code */
+  orfp = stream_get_putp (s);           /* Set ORF Len Pointer */
+  stream_putc (s, 0);                   /* ORF Length */
+  stream_putw (s, afi);
+  stream_putc (s, 0);
+  stream_putc (s, safi);
+  numberp = stream_get_putp (s);        /* Set Number Pointer */
+  stream_putc (s, 0);                   /* Number of ORFs */
+
+  /* Address Prefix ORF */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
+      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
+    {
+      stream_putc (s, (code == CAPABILITY_CODE_ORF ?
+                  ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
+
+      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
+         && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
+       {
+         SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
+         SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
+         stream_putc (s, ORF_MODE_BOTH);
+       }
+      else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
+       {
+         SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
+         stream_putc (s, ORF_MODE_SEND);
+       }
+      else
+       {
+         SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
+         stream_putc (s, ORF_MODE_RECEIVE);
+       }
+      number_of_orfs++;
+    }
+
+  /* Total Number of ORFs. */
+  stream_putc_at (s, numberp, number_of_orfs);
+
+  /* Total ORF Len. */
+  orf_len = stream_get_putp (s) - orfp - 1;
+  stream_putc_at (s, orfp, orf_len);
+
+  /* Total Capability Len. */
+  cap_len = stream_get_putp (s) - capp - 1;
+  stream_putc_at (s, capp, cap_len);
+}
+
+/* Fill in capability open option to the packet. */
+void
+bgp_open_capability (struct stream *s, struct peer *peer)
+{
+  u_char len;
+  unsigned long cp;
+  afi_t afi;
+  safi_t safi;
+
+  /* Remember current pointer for Opt Parm Len. */
+  cp = stream_get_putp (s);
+
+  /* Opt Parm Len. */
+  stream_putc (s, 0);
+
+  /* Do not send capability. */
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN) 
+      || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
+    return;
+
+  /* When the peer is IPv4 unicast only, do not send capability. */
+  if (! peer->afc[AFI_IP][SAFI_MULTICAST] 
+      && ! peer->afc[AFI_IP][SAFI_MPLS_VPN]
+      && ! peer->afc[AFI_IP6][SAFI_UNICAST] 
+      && ! peer->afc[AFI_IP6][SAFI_MULTICAST]
+      && CHECK_FLAG (peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP)
+      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST],
+                      PEER_FLAG_ORF_PREFIX_SM)
+      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST],
+                      PEER_FLAG_ORF_PREFIX_RM)
+      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
+                      PEER_FLAG_ORF_PREFIX_SM)
+      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
+                      PEER_FLAG_ORF_PREFIX_RM)
+      && ! CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
+    return;
+
+  /* IPv4 unicast. */
+  if (peer->afc[AFI_IP][SAFI_UNICAST])
+    {
+      peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP);
+      stream_putc (s, 0);
+      stream_putc (s, SAFI_UNICAST);
+    }
+  /* IPv4 multicast. */
+  if (peer->afc[AFI_IP][SAFI_MULTICAST])
+    {
+      peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP);
+      stream_putc (s, 0);
+      stream_putc (s, SAFI_MULTICAST);
+    }
+  /* IPv4 VPN */
+  if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
+    {
+      peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP);
+      stream_putc (s, 0);
+      stream_putc (s, BGP_SAFI_VPNV4);
+    }
+#ifdef HAVE_IPV6
+  /* IPv6 unicast. */
+  if (peer->afc[AFI_IP6][SAFI_UNICAST])
+    {
+      peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP6);
+      stream_putc (s, 0);
+      stream_putc (s, SAFI_UNICAST);
+    }
+  /* IPv6 multicast. */
+  if (peer->afc[AFI_IP6][SAFI_MULTICAST])
+    {
+      peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP6);
+      stream_putc (s, 0);
+      stream_putc (s, SAFI_MULTICAST);
+    }
+#endif /* HAVE_IPV6 */
+
+  /* Route refresh. */
+  if (! CHECK_FLAG (peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP))
+    {
+      SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_REFRESH);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
+    }
+
+  /* ORF capability. */
+  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
+         || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
+       {
+         bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
+         bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
+       }
+
+  /* Dynamic capability. */
+  if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
+    {
+      SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_DYNAMIC);
+      stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
+    }
+
+  /* Total Opt Parm Len. */
+  len = stream_get_putp (s) - cp - 1;
+  stream_putc_at (s, cp, len);
+}
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
new file mode 100644 (file)
index 0000000..af7505a
--- /dev/null
@@ -0,0 +1,69 @@
+/* BGP open message handling
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* MP Capability information. */
+struct capability_mp
+{
+  u_int16_t afi;
+  u_char reserved;
+  u_char safi;
+};
+
+/* BGP open message capability. */
+struct capability
+{
+  u_char code;
+  u_char length;
+  struct capability_mp mpc;
+};
+
+/* Multiprotocol Extensions capabilities. */
+#define CAPABILITY_CODE_MP              1
+#define CAPABILITY_CODE_MP_LEN          4
+
+/* Route refresh capabilities. */
+#define CAPABILITY_CODE_REFRESH         2
+#define CAPABILITY_CODE_REFRESH_OLD   128
+#define CAPABILITY_CODE_REFRESH_LEN     0
+
+/* Cooperative Route Filtering Capability.  */
+#define CAPABILITY_CODE_ORF             3 
+#define CAPABILITY_CODE_ORF_OLD       130
+
+/* ORF Type.  */
+#define ORF_TYPE_PREFIX                64 
+#define ORF_TYPE_PREFIX_OLD           128
+
+/* ORF Mode.  */
+#define ORF_MODE_RECEIVE                1 
+#define ORF_MODE_SEND                   2 
+#define ORF_MODE_BOTH                   3 
+
+/* Dynamic capability.  */
+#define CAPABILITY_CODE_DYNAMIC        66
+#define CAPABILITY_CODE_DYNAMIC_LEN     0
+
+/* Capability Message Action.  */
+#define CAPABILITY_ACTION_SET           0
+#define CAPABILITY_ACTION_UNSET         1
+
+int bgp_open_option_parse (struct peer *, u_char, int *);
+void bgp_open_capability (struct stream *, struct peer *);
+void bgp_capability_vty_out (struct vty *, struct peer *);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
new file mode 100644 (file)
index 0000000..48879f3
--- /dev/null
@@ -0,0 +1,2240 @@
+/* BGP packet management routine.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "stream.h"
+#include "network.h"
+#include "prefix.h"
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "sockunion.h"         /* for inet_ntop () */
+#include "linklist.h"
+#include "plist.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_advertise.h"
+
+int stream_put_prefix (struct stream *, struct prefix *);
+\f
+/* Set up BGP packet marker and packet type. */
+static int
+bgp_packet_set_marker (struct stream *s, u_char type)
+{
+  int i;
+
+  /* Fill in marker. */
+  for (i = 0; i < BGP_MARKER_SIZE; i++)
+    stream_putc (s, 0xff);
+
+  /* Dummy total length. This field is should be filled in later on. */
+  stream_putw (s, 0);
+
+  /* BGP packet type. */
+  stream_putc (s, type);
+
+  /* Return current stream size. */
+  return stream_get_putp (s);
+}
+
+/* Set BGP packet header size entry.  If size is zero then use current
+   stream size. */
+static int
+bgp_packet_set_size (struct stream *s)
+{
+  int cp;
+
+  /* Preserve current pointer. */
+  cp = stream_get_putp (s);
+  stream_set_putp (s, BGP_MARKER_SIZE);
+  stream_putw (s, cp);
+
+  /* Write back current pointer. */
+  stream_set_putp (s, cp);
+
+  return cp;
+}
+
+/* Add new packet to the peer. */
+void
+bgp_packet_add (struct peer *peer, struct stream *s)
+{
+  /* Add packet to the end of list. */
+  stream_fifo_push (peer->obuf, s);
+}
+
+/* Free first packet. */
+void
+bgp_packet_delete (struct peer *peer)
+{
+  stream_free (stream_fifo_pop (peer->obuf));
+}
+
+/* Duplicate packet. */
+struct stream *
+bgp_packet_dup (struct stream *s)
+{
+  struct stream *new;
+
+  new = stream_new (stream_get_endp (s));
+
+  new->endp = s->endp;
+  new->putp = s->putp;
+  new->getp = s->getp;
+
+  memcpy (new->data, s->data, stream_get_endp (s));
+
+  return new;
+}
+
+/* Check file descriptor whether connect is established. */
+static void
+bgp_connect_check (struct peer *peer)
+{
+  int status;
+  int slen;
+  int ret;
+
+  /* Anyway I have to reset read and write thread. */
+  BGP_READ_OFF (peer->t_read);
+  BGP_WRITE_OFF (peer->t_write);
+
+  /* Check file descriptor. */
+  slen = sizeof (status);
+  ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen);
+
+  /* If getsockopt is fail, this is fatal error. */
+  if (ret < 0)
+    {
+      zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect");
+      BGP_EVENT_ADD (peer, TCP_fatal_error);
+      return;
+    }      
+
+  /* When status is 0 then TCP connection is established. */
+  if (status == 0)
+    {
+      BGP_EVENT_ADD (peer, TCP_connection_open);
+    }
+  else
+    {
+      if (BGP_DEBUG (events, EVENTS))
+         plog_info (peer->log, "%s [Event] Connect failed (%s)",
+                    peer->host, strerror (errno));
+      BGP_EVENT_ADD (peer, TCP_connection_open_failed);
+    }
+}
+
+/* Make BGP update packet.  */
+struct stream *
+bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct stream *s;
+  struct bgp_adj_out *adj;
+  struct bgp_advertise *adv;
+  struct stream *packet;
+  struct bgp_node *rn = NULL;
+  struct bgp_info *binfo = NULL;
+  bgp_size_t total_attr_len = 0;
+  unsigned long pos;
+  char buf[BUFSIZ];
+  struct prefix_rd *prd = NULL;
+  char *tag = NULL;
+
+  s = peer->work;
+  stream_reset (s);
+
+  adv = FIFO_HEAD (&peer->sync[afi][safi]->update);
+
+  while (adv)
+    {
+      if (adv->rn)
+        rn = adv->rn;
+      adj = adv->adj;
+      if (adv->binfo)
+        binfo = adv->binfo;
+#ifdef MPLS_VPN
+      if (rn)
+        prd = (struct prefix_rd *) &rn->prn->p;
+      if (binfo)
+        tag = binfo->tag;
+#endif /* MPLS_VPN */
+
+      /* When remaining space can't include NLRI and it's length.  */
+      if (rn && STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen))
+       break;
+
+      /* If packet is empty, set attribute. */
+      if (stream_empty (s))
+       {
+         bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+         stream_putw (s, 0);           
+         pos = stream_get_putp (s);
+         stream_putw (s, 0);
+         total_attr_len = bgp_packet_attribute (NULL, peer, s,
+                                                adv->baa->attr,
+                                                &rn->p, afi, safi,
+                                                binfo->peer, prd, tag);
+         stream_putw_at (s, pos, total_attr_len);
+       }
+
+      if (afi == AFI_IP && safi == SAFI_UNICAST)
+       stream_put_prefix (s, &rn->p);
+      
+      if (BGP_DEBUG (update, UPDATE_OUT))
+       zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d",
+             peer->host,
+             inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ),
+             rn->p.prefixlen);
+
+      /* Synchnorize attribute.  */
+      if (adj->attr)
+       bgp_attr_unintern (adj->attr);
+      else
+       peer->scount[afi][safi]++;
+
+      adj->attr = bgp_attr_intern (adv->baa->attr);
+
+      adv = bgp_advertise_clean (peer, adj, afi, safi);
+
+      if (! (afi == AFI_IP && safi == SAFI_UNICAST))
+       break;
+    }
+        
+  if (! stream_empty (s))
+    {
+      bgp_packet_set_size (s);
+      packet = bgp_packet_dup (s);
+      bgp_packet_add (peer, packet);
+      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+      stream_reset (s);
+      return packet;
+    }
+  return NULL;
+
+}
+
+/* Make BGP withdraw packet.  */
+struct stream *
+bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct stream *s;
+  struct stream *packet;
+  struct bgp_adj_out *adj;
+  struct bgp_advertise *adv;
+  struct bgp_node *rn;
+  unsigned long pos;
+  bgp_size_t unfeasible_len;
+  bgp_size_t total_attr_len;
+  char buf[BUFSIZ];
+  struct prefix_rd *prd = NULL;
+
+  s = peer->work;
+  stream_reset (s);
+
+  while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL)
+    {
+      adj = adv->adj;
+      rn = adv->rn;
+#ifdef MPLS_VPN
+      prd = (struct prefix_rd *) &rn->prn->p;
+#endif /* MPLS_VPN */
+
+      if (STREAM_REMAIN (s) 
+         <= (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen)))
+       break;
+
+      if (stream_empty (s))
+       {
+         bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+         stream_putw (s, 0);
+       }
+
+      if (afi == AFI_IP && safi == SAFI_UNICAST)
+       stream_put_prefix (s, &rn->p);
+      else
+       {
+         pos = stream_get_putp (s);
+         stream_putw (s, 0);
+         total_attr_len
+           = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL);
+      
+         /* Set total path attribute length. */
+         stream_putw_at (s, pos, total_attr_len);
+       }
+
+      if (BGP_DEBUG (update, UPDATE_OUT))
+       zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable",
+             peer->host,
+             inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ),
+             rn->p.prefixlen);
+
+      peer->scount[afi][safi]--;
+
+      bgp_adj_out_remove (rn, adj, peer, afi, safi);
+      bgp_unlock_node (rn);
+
+      if (! (afi == AFI_IP && safi == SAFI_UNICAST))
+       break;
+    }
+
+  if (! stream_empty (s))
+    {
+      if (afi == AFI_IP && safi == SAFI_UNICAST)
+       {
+         unfeasible_len 
+           = stream_get_putp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
+         stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len);
+         stream_putw (s, 0);
+       }
+      bgp_packet_set_size (s);
+      packet = bgp_packet_dup (s);
+      bgp_packet_add (peer, packet);
+      stream_reset (s);
+      return packet;
+    }
+
+  return NULL;
+}
+
+void
+bgp_default_update_send (struct peer *peer, struct attr *attr,
+                        afi_t afi, safi_t safi, struct peer *from)
+{
+  struct stream *s;
+  struct stream *packet;
+  struct prefix p;
+  unsigned long pos;
+  bgp_size_t total_attr_len;
+  char attrstr[BUFSIZ];
+  char buf[BUFSIZ];
+
+#ifdef DISABLE_BGP_ANNOUNCE
+  return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+  if (afi == AFI_IP)
+    str2prefix ("0.0.0.0/0", &p);
+#ifdef HAVE_IPV6
+  else 
+    str2prefix ("::/0", &p);
+#endif /* HAVE_IPV6 */
+
+  /* Logging the attribute. */
+  if (BGP_DEBUG (update, UPDATE_OUT))
+    {
+      bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
+      zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d %s",
+           peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ),
+           p.prefixlen, attrstr);
+    }
+
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make BGP update packet. */
+  bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+
+  /* Unfeasible Routes Length. */
+  stream_putw (s, 0);
+
+  /* Make place for total attribute length.  */
+  pos = stream_get_putp (s);
+  stream_putw (s, 0);
+  total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL);
+
+  /* Set Total Path Attribute Length. */
+  stream_putw_at (s, pos, total_attr_len);
+
+  /* NLRI set. */
+  if (p.family == AF_INET && safi == SAFI_UNICAST)
+    stream_put_prefix (s, &p);
+
+  /* Set size. */
+  bgp_packet_set_size (s);
+
+  packet = bgp_packet_dup (s);
+  stream_free (s);
+
+  /* Dump packet if debug option is set. */
+#ifdef DEBUG
+  bgp_packet_dump (packet);
+#endif /* DEBUG */
+
+  /* Add packet to the peer. */
+  bgp_packet_add (peer, packet);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+}
+
+void
+bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct stream *s;
+  struct stream *packet;
+  struct prefix p;
+  unsigned long pos;
+  unsigned long cp;
+  bgp_size_t unfeasible_len;
+  bgp_size_t total_attr_len;
+  char buf[BUFSIZ];
+
+#ifdef DISABLE_BGP_ANNOUNCE
+  return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+  if (afi == AFI_IP)
+    str2prefix ("0.0.0.0/0", &p);
+#ifdef HAVE_IPV6
+  else 
+    str2prefix ("::/0", &p);
+#endif /* HAVE_IPV6 */
+
+  total_attr_len = 0;
+  pos = 0;
+
+  if (BGP_DEBUG (update, UPDATE_OUT))
+    zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable",
+          peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ),
+          p.prefixlen);
+
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make BGP update packet. */
+  bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+
+  /* Unfeasible Routes Length. */;
+  cp = stream_get_putp (s);
+  stream_putw (s, 0);
+
+  /* Withdrawn Routes. */
+  if (p.family == AF_INET && safi == SAFI_UNICAST)
+    {
+      stream_put_prefix (s, &p);
+
+      unfeasible_len = stream_get_putp (s) - cp - 2;
+
+      /* Set unfeasible len.  */
+      stream_putw_at (s, cp, unfeasible_len);
+
+      /* Set total path attribute length. */
+      stream_putw (s, 0);
+    }
+  else
+    {
+      pos = stream_get_putp (s);
+      stream_putw (s, 0);
+      total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL);
+
+      /* Set total path attribute length. */
+      stream_putw_at (s, pos, total_attr_len);
+    }
+
+  bgp_packet_set_size (s);
+
+  packet = bgp_packet_dup (s);
+  stream_free (s);
+
+  /* Add packet to the peer. */
+  bgp_packet_add (peer, packet);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+}
+
+/* Get next packet to be written.  */
+struct stream *
+bgp_write_packet (struct peer *peer)
+{
+  afi_t afi;
+  safi_t safi;
+  struct stream *s = NULL;
+  struct bgp_advertise *adv;
+
+  s = stream_fifo_head (peer->obuf);
+  if (s)
+    return s;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw);
+       if (adv)
+         {
+           s = bgp_withdraw_packet (peer, afi, safi);
+           if (s)
+             return s;
+         }
+      }
+    
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       adv = FIFO_HEAD (&peer->sync[afi][safi]->update);
+       if (adv)
+         {
+            if (adv->binfo && adv->binfo->uptime < peer->synctime)
+              s = bgp_update_packet (peer, afi, safi);
+
+           if (s)
+             return s;
+         }
+      }
+
+  return NULL;
+}
+
+/* Is there partially written packet or updates we can send right
+   now.  */
+int
+bgp_write_proceed (struct peer *peer)
+{
+  afi_t afi;
+  safi_t safi;
+  struct bgp_advertise *adv;
+
+  if (stream_fifo_head (peer->obuf))
+    return 1;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw))
+       return 1;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL)
+       if (adv->binfo->uptime < peer->synctime)
+         return 1;
+
+  return 0;
+}
+
+/* Write packet to the peer. */
+int
+bgp_write (struct thread *thread)
+{
+  struct peer *peer;
+  u_char type;
+  struct stream *s; 
+  int num;
+  int count = 0;
+  int write_errno;
+
+  /* Yes first of all get peer pointer. */
+  peer = THREAD_ARG (thread);
+  peer->t_write = NULL;
+
+  /* For non-blocking IO check. */
+  if (peer->status == Connect)
+    {
+      bgp_connect_check (peer);
+      return 0;
+    }
+
+    /* Nonblocking write until TCP output buffer is full.  */
+  while (1)
+    {
+      int writenum;
+
+      s = bgp_write_packet (peer);
+      if (! s)
+       return 0;
+
+      /* Number of bytes to be sent.  */
+      writenum = stream_get_endp (s) - stream_get_getp (s);
+
+      /* Call write() system call.  */
+      num = write (peer->fd, STREAM_PNT (s), writenum);
+      write_errno = errno;
+      if (num <= 0)
+       {
+         /* Partial write. */
+         if (write_errno == EWOULDBLOCK || write_errno == EAGAIN)
+             break;
+
+         bgp_stop (peer);
+         peer->status = Idle;
+         bgp_timer_set (peer);
+         return 0;
+       }
+      if (num != writenum)
+       {
+         stream_forward (s, num);
+
+         if (write_errno == EAGAIN)
+           break;
+
+         continue;
+       }
+
+      /* Retrieve BGP packet type. */
+      stream_set_getp (s, BGP_MARKER_SIZE + 2);
+      type = stream_getc (s);
+
+      switch (type)
+       {
+       case BGP_MSG_OPEN:
+         peer->open_out++;
+         break;
+       case BGP_MSG_UPDATE:
+         peer->update_out++;
+         break;
+       case BGP_MSG_NOTIFY:
+         peer->notify_out++;
+         /* Double start timer. */
+         peer->v_start *= 2;
+
+         /* Overflow check. */
+         if (peer->v_start >= (60 * 2))
+           peer->v_start = (60 * 2);
+
+         /* BGP_EVENT_ADD (peer, BGP_Stop); */
+         bgp_stop (peer);
+         peer->status = Idle;
+         bgp_timer_set (peer);
+         return 0;
+         break;
+       case BGP_MSG_KEEPALIVE:
+         peer->keepalive_out++;
+         break;
+       case BGP_MSG_ROUTE_REFRESH_NEW:
+       case BGP_MSG_ROUTE_REFRESH_OLD:
+         peer->refresh_out++;
+         break;
+       case BGP_MSG_CAPABILITY:
+         peer->dynamic_cap_out++;
+         break;
+       }
+
+      /* OK we send packet so delete it. */
+      bgp_packet_delete (peer);
+
+      if (++count >= BGP_WRITE_PACKET_MAX)
+       break;
+    }
+  
+  if (bgp_write_proceed (peer))
+    BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+  
+  return 0;
+}
+
+/* This is only for sending NOTIFICATION message to neighbor. */
+int
+bgp_write_notify (struct peer *peer)
+{
+  int ret;
+  u_char type;
+  struct stream *s; 
+
+  /* There should be at least one packet. */
+  s = stream_fifo_head (peer->obuf);
+  if (!s)
+    return 0;
+  assert (stream_get_endp (s) >= BGP_HEADER_SIZE);
+
+  /* I'm not sure fd is writable. */
+  ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s));
+  if (ret <= 0)
+    {
+      bgp_stop (peer);
+      peer->status = Idle;
+      bgp_timer_set (peer);
+      return 0;
+    }
+
+  /* Retrieve BGP packet type. */
+  stream_set_getp (s, BGP_MARKER_SIZE + 2);
+  type = stream_getc (s);
+
+  assert (type == BGP_MSG_NOTIFY);
+
+  /* Type should be notify. */
+  peer->notify_out++;
+
+  /* Double start timer. */
+  peer->v_start *= 2;
+
+  /* Overflow check. */
+  if (peer->v_start >= (60 * 2))
+    peer->v_start = (60 * 2);
+
+  /* We don't call event manager at here for avoiding other events. */
+  bgp_stop (peer);
+  peer->status = Idle;
+  bgp_timer_set (peer);
+
+  return 0;
+}
+
+/* Make keepalive packet and send it to the peer. */
+void
+bgp_keepalive_send (struct peer *peer)
+{
+  struct stream *s;
+  int length;
+
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make keepalive packet. */
+  bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE);
+
+  /* Set packet size. */
+  length = bgp_packet_set_size (s);
+
+  /* Dump packet if debug option is set. */
+  /* bgp_packet_dump (s); */
+  if (BGP_DEBUG (keepalive, KEEPALIVE))  
+    zlog_info ("%s sending KEEPALIVE", peer->host); 
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s send message type %d, length (incl. header) %d",
+               peer->host, BGP_MSG_KEEPALIVE, length);
+
+  /* Add packet to the peer. */
+  bgp_packet_add (peer, s);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+}
+
+/* Make open packet and send it to the peer. */
+void
+bgp_open_send (struct peer *peer)
+{
+  struct stream *s;
+  int length;
+  u_int16_t send_holdtime;
+  as_t local_as;
+
+  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
+    send_holdtime = peer->holdtime;
+  else
+    send_holdtime = peer->bgp->default_holdtime;
+
+  /* local-as Change */
+  if (peer->change_local_as)
+    local_as = peer->change_local_as; 
+  else
+    local_as = peer->local_as; 
+
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make open packet. */
+  bgp_packet_set_marker (s, BGP_MSG_OPEN);
+
+  /* Set open packet values. */
+  stream_putc (s, BGP_VERSION_4);        /* BGP version */
+  stream_putw (s, local_as);            /* My Autonomous System*/
+  stream_putw (s, send_holdtime);       /* Hold Time */
+  stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */
+
+  /* Set capability code. */
+  bgp_open_capability (s, peer);
+
+  /* Set BGP packet length. */
+  length = bgp_packet_set_size (s);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s sending OPEN, version %d, my as %d, holdtime %d, id %s", 
+              peer->host, BGP_VERSION_4, local_as,
+              send_holdtime, inet_ntoa (peer->local_id));
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s send message type %d, length (incl. header) %d",
+              peer->host, BGP_MSG_OPEN, length);
+
+  /* Dump packet if debug option is set. */
+  /* bgp_packet_dump (s); */
+
+  /* Add packet to the peer. */
+  bgp_packet_add (peer, s);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+}
+
+/* Send BGP notify packet with data potion. */
+void
+bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
+                          u_char *data, size_t datalen)
+{
+  struct stream *s;
+  int length;
+
+  /* Allocate new stream. */
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make nitify packet. */
+  bgp_packet_set_marker (s, BGP_MSG_NOTIFY);
+
+  /* Set notify packet values. */
+  stream_putc (s, code);        /* BGP notify code */
+  stream_putc (s, sub_code);   /* BGP notify sub_code */
+
+  /* If notify data is present. */
+  if (data)
+    stream_write (s, data, datalen);
+  
+  /* Set BGP packet length. */
+  length = bgp_packet_set_size (s);
+  
+  /* Add packet to the peer. */
+  stream_fifo_clean (peer->obuf);
+  bgp_packet_add (peer, s);
+
+  /* For debug */
+  {
+    struct bgp_notify bgp_notify;
+    int first = 0;
+    int i;
+    char c[4];
+
+    bgp_notify.code = code;
+    bgp_notify.subcode = sub_code;
+    bgp_notify.data = NULL;
+    bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE;
+    
+    if (bgp_notify.length)
+      {
+       bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3);
+       for (i = 0; i < bgp_notify.length; i++)
+         if (first)
+           {
+             sprintf (c, " %02x", data[i]);
+             strcat (bgp_notify.data, c);
+           }
+         else
+           {
+             first = 1;
+             sprintf (c, "%02x", data[i]);
+             strcpy (bgp_notify.data, c);
+           }
+      }
+    bgp_notify_print (peer, &bgp_notify, "sending");
+    if (bgp_notify.data)
+      XFREE (MTYPE_TMP, bgp_notify.data);
+  }
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s send message type %d, length (incl. header) %d",
+              peer->host, BGP_MSG_NOTIFY, length);
+
+  /* Call imidiately. */
+  BGP_WRITE_OFF (peer->t_write);
+
+  bgp_write_notify (peer);
+}
+
+/* Send BGP notify packet. */
+void
+bgp_notify_send (struct peer *peer, u_char code, u_char sub_code)
+{
+  bgp_notify_send_with_data (peer, code, sub_code, NULL, 0);
+}
+
+char *
+afi2str (afi_t afi)
+{
+  if (afi == AFI_IP)
+    return "AFI_IP";
+  else if (afi == AFI_IP6)
+    return "AFI_IP6";
+  else
+    return "Unknown AFI";
+}
+
+char *
+safi2str (safi_t safi)
+{
+  if (safi == SAFI_UNICAST)
+    return "SAFI_UNICAST";
+  else if (safi == SAFI_MULTICAST)
+    return "SAFI_MULTICAST";
+  else if (safi == SAFI_MPLS_VPN || safi == BGP_SAFI_VPNV4)
+    return "SAFI_MPLS_VPN";
+  else
+    return "Unknown SAFI";
+}
+
+/* Send route refresh message to the peer. */
+void
+bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
+                       u_char orf_type, u_char when_to_refresh, int remove)
+{
+  struct stream *s;
+  struct stream *packet;
+  int length;
+  struct bgp_filter *filter;
+  int orf_refresh = 0;
+
+#ifdef DISABLE_BGP_ANNOUNCE
+  return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+  filter = &peer->filter[afi][safi];
+
+  /* Adjust safi code. */
+  if (safi == SAFI_MPLS_VPN)
+    safi = BGP_SAFI_VPNV4;
+  
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make BGP update packet. */
+  if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+    bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW);
+  else
+    bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD);
+
+  /* Encode Route Refresh message. */
+  stream_putw (s, afi);
+  stream_putc (s, 0);
+  stream_putc (s, safi);
+  if (orf_type == ORF_TYPE_PREFIX
+      || orf_type == ORF_TYPE_PREFIX_OLD)
+    if (remove || filter->plist[FILTER_IN].plist)
+      {
+       u_int16_t orf_len;
+       unsigned long orfp;
+
+       orf_refresh = 1; 
+       stream_putc (s, when_to_refresh);
+       stream_putc (s, orf_type);
+       orfp = stream_get_putp (s);
+       stream_putw (s, 0);
+
+       if (remove)
+         {
+           UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
+           stream_putc (s, ORF_COMMON_PART_REMOVE_ALL);
+           if (BGP_DEBUG (normal, NORMAL))
+             zlog_info ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", 
+                        peer->host, orf_type,
+                        (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
+                        afi, safi);
+         }
+       else
+         {
+           SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
+           prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist,
+                                 ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT,
+                                 ORF_COMMON_PART_DENY);
+           if (BGP_DEBUG (normal, NORMAL))
+             zlog_info ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", 
+                        peer->host, orf_type,
+                        (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
+                        afi, safi);
+         }
+
+       /* Total ORF Entry Len. */
+       orf_len = stream_get_putp (s) - orfp - 2;
+       stream_putw_at (s, orfp, orf_len);
+      }
+
+  /* Set packet size. */
+  length = bgp_packet_set_size (s);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    {
+      if (! orf_refresh)
+       zlog_info ("%s sending REFRESH_REQ for afi/safi: %d/%d", 
+                  peer->host, afi, safi);
+      zlog_info ("%s send message type %d, length (incl. header) %d",
+                peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ?
+                BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length);
+    }
+
+  /* Make real packet. */
+  packet = bgp_packet_dup (s);
+  stream_free (s);
+
+  /* Add packet to the peer. */
+  bgp_packet_add (peer, packet);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+}
+
+/* Send capability message to the peer. */
+void
+bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
+                    int capability_code, int action)
+{
+  struct stream *s;
+  struct stream *packet;
+  int length;
+
+  /* Adjust safi code. */
+  if (safi == SAFI_MPLS_VPN)
+    safi = BGP_SAFI_VPNV4;
+
+  s = stream_new (BGP_MAX_PACKET_SIZE);
+
+  /* Make BGP update packet. */
+  bgp_packet_set_marker (s, BGP_MSG_CAPABILITY);
+
+  /* Encode MP_EXT capability. */
+  if (capability_code == CAPABILITY_CODE_MP)
+    {
+      stream_putc (s, action);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, afi);
+      stream_putc (s, 0);
+      stream_putc (s, safi);
+
+      if (BGP_DEBUG (normal, NORMAL))
+        zlog_info ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d",
+                  peer->host, action == CAPABILITY_ACTION_SET ?
+                  "Advertising" : "Removing", afi, safi);
+    }
+
+  /* Encode Route Refresh capability. */
+  if (capability_code == CAPABILITY_CODE_REFRESH)
+    {
+      stream_putc (s, action);
+      stream_putc (s, CAPABILITY_CODE_REFRESH);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
+      stream_putc (s, action);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
+      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
+
+      if (BGP_DEBUG (normal, NORMAL))
+        zlog_info ("%s sending CAPABILITY has %s ROUTE-REFRESH capability",
+                  peer->host, action == CAPABILITY_ACTION_SET ?
+                  "Advertising" : "Removing");
+    }
+
+  /* Set packet size. */
+  length = bgp_packet_set_size (s);
+
+  /* Make real packet. */
+  packet = bgp_packet_dup (s);
+  stream_free (s);
+
+  /* Add packet to the peer. */
+  bgp_packet_add (peer, packet);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s send message type %d, length (incl. header) %d",
+              peer->host, BGP_MSG_CAPABILITY, length);
+
+  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+}
+\f
+/* RFC1771 6.8 Connection collision detection. */
+int
+bgp_collision_detect (struct peer *new, struct in_addr remote_id)
+{
+  struct peer *peer;
+  struct listnode *nn;
+  struct bgp *bgp;
+
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return 0;
+  
+  /* Upon receipt of an OPEN message, the local system must examine
+     all of its connections that are in the OpenConfirm state.  A BGP
+     speaker may also examine connections in an OpenSent state if it
+     knows the BGP Identifier of the peer by means outside of the
+     protocol.  If among these connections there is a connection to a
+     remote BGP speaker whose BGP Identifier equals the one in the
+     OPEN message, then the local system performs the following
+     collision resolution procedure: */
+
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      /* Under OpenConfirm status, local peer structure already hold
+         remote router ID. */
+
+      if (peer != new
+         && (peer->status == OpenConfirm || peer->status == OpenSent)
+         && sockunion_same (&peer->su, &new->su))
+       {
+         /* 1. The BGP Identifier of the local system is compared to
+            the BGP Identifier of the remote system (as specified in
+            the OPEN message). */
+
+         if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr))
+           {
+             /* 2. If the value of the local BGP Identifier is less
+                than the remote one, the local system closes BGP
+                connection that already exists (the one that is
+                already in the OpenConfirm state), and accepts BGP
+                connection initiated by the remote system. */
+
+             if (peer->fd >= 0)
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+             return 1;
+           }
+         else
+           {
+             /* 3. Otherwise, the local system closes newly created
+                BGP connection (the one associated with the newly
+                received OPEN message), and continues to use the
+                existing one (the one that is already in the
+                OpenConfirm state). */
+
+             if (new->fd >= 0)
+               bgp_notify_send (new, BGP_NOTIFY_CEASE, 0);
+             return -1;
+           }
+       }
+    }
+  return 0;
+}
+
+int
+bgp_open_receive (struct peer *peer, bgp_size_t size)
+{
+  int ret;
+  u_char version;
+  u_char optlen;
+  u_int16_t holdtime;
+  u_int16_t send_holdtime;
+  as_t remote_as;
+  struct peer *realpeer;
+  struct in_addr remote_id;
+  int capability;
+  char notify_data_remote_as[2];
+  char notify_data_remote_id[4];
+
+  realpeer = NULL;
+  
+  /* Parse open packet. */
+  version = stream_getc (peer->ibuf);
+  memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2);
+  remote_as  = stream_getw (peer->ibuf);
+  holdtime = stream_getw (peer->ibuf);
+  memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4);
+  remote_id.s_addr = stream_get_ipv4 (peer->ibuf);
+
+  /* Receive OPEN message log  */
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s",
+              peer->host, version, remote_as, holdtime,
+              inet_ntoa (remote_id));
+         
+  /* Lookup peer from Open packet. */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+    {
+      int as = 0;
+
+      realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as);
+
+      if (! realpeer)
+       {
+         /* Peer's source IP address is check in bgp_accept(), so this
+            must be AS number mismatch or remote-id configuration
+            mismatch. */
+         if (as)
+           {
+             if (BGP_DEBUG (normal, NORMAL))
+               zlog_info ("%s bad OPEN, wrong router identifier %s",
+                          peer->host, inet_ntoa (remote_id));
+             bgp_notify_send_with_data (peer, 
+                                        BGP_NOTIFY_OPEN_ERR, 
+                                        BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
+                                        notify_data_remote_id, 4);
+           }
+         else
+           {
+             if (BGP_DEBUG (normal, NORMAL))
+               zlog_info ("%s bad OPEN, remote AS is %d, expected %d",
+                          peer->host, remote_as, peer->as);
+             bgp_notify_send_with_data (peer, 
+                                        BGP_NOTIFY_OPEN_ERR, 
+                                        BGP_NOTIFY_OPEN_BAD_PEER_AS,
+                                        notify_data_remote_as, 2);
+           }
+         return -1;
+       }
+    }
+
+  /* When collision is detected and this peer is closed.  Retrun
+     immidiately. */
+  ret = bgp_collision_detect (peer, remote_id);
+  if (ret < 0)
+    return ret;
+
+  /* Hack part. */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+    {
+      if (ret == 0 && realpeer->status != Active
+         && realpeer->status != OpenSent
+         && realpeer->status != OpenConfirm)
+       {
+         if (BGP_DEBUG (events, EVENTS))
+           zlog_info ("%s [Event] peer's status is %s close connection",
+                      realpeer->host, LOOKUP (bgp_status_msg, peer->status));
+         return -1;
+       }
+
+      if (BGP_DEBUG (events, EVENTS))
+       zlog_info ("%s [Event] Transfer temporary BGP peer to existing one",
+                  peer->host);
+
+      bgp_stop (realpeer);
+      
+      /* Transfer file descriptor. */
+      realpeer->fd = peer->fd;
+      peer->fd = -1;
+
+      /* Transfer input buffer. */
+      stream_free (realpeer->ibuf);
+      realpeer->ibuf = peer->ibuf;
+      realpeer->packet_size = peer->packet_size;
+      peer->ibuf = NULL;
+
+      /* Transfer status. */
+      realpeer->status = peer->status;
+      bgp_stop (peer);
+
+      /* peer pointer change. Open packet send to neighbor. */
+      peer = realpeer;
+      bgp_open_send (peer);
+      if (peer->fd < 0)
+       {
+         zlog_err ("bgp_open_receive peer's fd is negative value %d",
+                   peer->fd);
+         return -1;
+       }
+      BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
+    }
+
+  /* remote router-id check. */
+  if (remote_id.s_addr == 0
+      || ntohl (remote_id.s_addr) >= 0xe0000000
+      || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
+    {
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s bad OPEN, wrong router identifier %s",
+                  peer->host, inet_ntoa (remote_id));
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_OPEN_ERR, 
+                                BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
+                                notify_data_remote_id, 4);
+      return -1;
+    }
+
+  /* Set remote router-id */
+  peer->remote_id = remote_id;
+
+  /* Peer BGP version check. */
+  if (version != BGP_VERSION_4)
+    {
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s bad protocol version, remote requested %d, local request %d",
+                  peer->host, version, BGP_VERSION_4);
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_OPEN_ERR, 
+                                BGP_NOTIFY_OPEN_UNSUP_VERSION,
+                                "\x04", 1);
+      return -1;
+    }
+
+  /* Check neighbor as number. */
+  if (remote_as != peer->as)
+    {
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s bad OPEN, remote AS is %d, expected %d",
+                  peer->host, remote_as, peer->as);
+      bgp_notify_send_with_data (peer, 
+                                BGP_NOTIFY_OPEN_ERR, 
+                                BGP_NOTIFY_OPEN_BAD_PEER_AS,
+                                notify_data_remote_as, 2);
+      return -1;
+    }
+
+  /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST
+     calculate the value of the Hold Timer by using the smaller of its
+     configured Hold Time and the Hold Time received in the OPEN message.
+     The Hold Time MUST be either zero or at least three seconds.  An
+     implementation may reject connections on the basis of the Hold Time. */
+
+  if (holdtime < 3 && holdtime != 0)
+    {
+      bgp_notify_send (peer,
+                      BGP_NOTIFY_OPEN_ERR, 
+                      BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
+      return -1;
+    }
+    
+  /* From the rfc: A reasonable maximum time between KEEPALIVE messages
+     would be one third of the Hold Time interval.  KEEPALIVE messages
+     MUST NOT be sent more frequently than one per second.  An
+     implementation MAY adjust the rate at which it sends KEEPALIVE
+     messages as a function of the Hold Time interval. */
+
+  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
+    send_holdtime = peer->holdtime;
+  else
+    send_holdtime = peer->bgp->default_holdtime;
+
+  if (holdtime < send_holdtime)
+    peer->v_holdtime = holdtime;
+  else
+    peer->v_holdtime = send_holdtime;
+
+  peer->v_keepalive = peer->v_holdtime / 3;
+
+  /* Open option part parse. */
+  capability = 0;
+  optlen = stream_getc (peer->ibuf);
+  if (optlen != 0) 
+    {
+      ret = bgp_open_option_parse (peer, optlen, &capability);
+      if (ret < 0)
+       return ret;
+
+      stream_forward (peer->ibuf, optlen);
+    }
+  else
+    {
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s rcvd OPEN w/ OPTION parameter len: 0",
+                  peer->host);
+    }
+
+  /* Override capability. */
+  if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+    {
+      peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST];
+      peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST];
+      peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST];
+      peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
+    }
+
+  /* Get sockname. */
+  bgp_getsockname (peer);
+
+  BGP_EVENT_ADD (peer, Receive_OPEN_message);
+
+  peer->packet_size = 0;
+  if (peer->ibuf)
+    stream_reset (peer->ibuf);
+
+  return 0;
+}
+
+/* Parse BGP Update packet and make attribute object. */
+int
+bgp_update_receive (struct peer *peer, bgp_size_t size)
+{
+  int ret;
+  u_char *end;
+  struct stream *s;
+  struct attr attr;
+  bgp_size_t attribute_len;
+  bgp_size_t update_len;
+  bgp_size_t withdraw_len;
+  struct bgp_nlri update;
+  struct bgp_nlri withdraw;
+  struct bgp_nlri mp_update;
+  struct bgp_nlri mp_withdraw;
+  char attrstr[BUFSIZ];
+
+  /* Status must be Established. */
+  if (peer->status != Established) 
+    {
+      zlog_err ("%s [FSM] Update packet received under status %s",
+               peer->host, LOOKUP (bgp_status_msg, peer->status));
+      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+      return -1;
+    }
+
+  /* Set initial values. */
+  memset (&attr, 0, sizeof (struct attr));
+  memset (&update, 0, sizeof (struct bgp_nlri));
+  memset (&withdraw, 0, sizeof (struct bgp_nlri));
+  memset (&mp_update, 0, sizeof (struct bgp_nlri));
+  memset (&mp_withdraw, 0, sizeof (struct bgp_nlri));
+
+  s = peer->ibuf;
+  end = stream_pnt (s) + size;
+
+  /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute
+     Length is too large (i.e., if Unfeasible Routes Length + Total
+     Attribute Length + 23 exceeds the message Length), then the Error
+     Subcode is set to Malformed Attribute List.  */
+  if (stream_pnt (s) + 2 > end)
+    {
+      zlog_err ("%s [Error] Update packet error"
+               " (packet length is short for unfeasible length)",
+               peer->host);
+      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_MAL_ATTR);
+      return -1;
+    }
+
+  /* Unfeasible Route Length. */
+  withdraw_len = stream_getw (s);
+
+  /* Unfeasible Route Length check. */
+  if (stream_pnt (s) + withdraw_len > end)
+    {
+      zlog_err ("%s [Error] Update packet error"
+               " (packet unfeasible length overflow %d)",
+               peer->host, withdraw_len);
+      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_MAL_ATTR);
+      return -1;
+    }
+
+  /* Unfeasible Route packet format check. */
+  if (withdraw_len > 0)
+    {
+      ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len);
+      if (ret < 0)
+       return -1;
+
+      if (BGP_DEBUG (packet, PACKET_RECV))
+         zlog_info ("%s [Update:RECV] Unfeasible NLRI received", peer->host);
+
+      withdraw.afi = AFI_IP;
+      withdraw.safi = SAFI_UNICAST;
+      withdraw.nlri = stream_pnt (s);
+      withdraw.length = withdraw_len;
+      stream_forward (s, withdraw_len);
+    }
+  
+  /* Attribute total length check. */
+  if (stream_pnt (s) + 2 > end)
+    {
+      zlog_warn ("%s [Error] Packet Error"
+                " (update packet is short for attribute length)",
+                peer->host);
+      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_MAL_ATTR);
+      return -1;
+    }
+
+  /* Fetch attribute total length. */
+  attribute_len = stream_getw (s);
+
+  /* Attribute length check. */
+  if (stream_pnt (s) + attribute_len > end)
+    {
+      zlog_warn ("%s [Error] Packet Error"
+                " (update packet attribute length overflow %d)",
+                peer->host, attribute_len);
+      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_MAL_ATTR);
+      return -1;
+    }
+
+  /* Parse attribute when it exists. */
+  if (attribute_len)
+    {
+      ret = bgp_attr_parse (peer, &attr, attribute_len, 
+                           &mp_update, &mp_withdraw);
+      if (ret < 0)
+       return -1;
+    }
+
+  /* Logging the attribute. */
+  if (BGP_DEBUG (update, UPDATE_IN))
+    {
+      bgp_dump_attr (peer, &attr, attrstr, BUFSIZ);
+      zlog (peer->log, LOG_INFO, "%s rcvd UPDATE w/ attr: %s",
+           peer->host, attrstr);
+    }
+
+  /* Network Layer Reachability Information. */
+  update_len = end - stream_pnt (s);
+
+  if (update_len)
+    {
+      /* Check NLRI packet format and prefix length. */
+      ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len);
+      if (ret < 0)
+       return -1;
+
+      /* Set NLRI portion to structure. */
+      update.afi = AFI_IP;
+      update.safi = SAFI_UNICAST;
+      update.nlri = stream_pnt (s);
+      update.length = update_len;
+      stream_forward (s, update_len);
+    }
+
+  /* NLRI is processed only when the peer is configured specific
+     Address Family and Subsequent Address Family. */
+  if (peer->afc[AFI_IP][SAFI_UNICAST])
+    {
+      if (withdraw.length)
+       bgp_nlri_parse (peer, NULL, &withdraw);
+
+      if (update.length)
+       {
+         /* We check well-known attribute only for IPv4 unicast
+            update. */
+         ret = bgp_attr_check (peer, &attr);
+         if (ret < 0)
+           return -1;
+
+         bgp_nlri_parse (peer, &attr, &update);
+       }
+    }
+  if (peer->afc[AFI_IP][SAFI_MULTICAST])
+    {
+      if (mp_update.length
+         && mp_update.afi == AFI_IP 
+         && mp_update.safi == SAFI_MULTICAST)
+       bgp_nlri_parse (peer, &attr, &mp_update);
+
+      if (mp_withdraw.length
+         && mp_withdraw.afi == AFI_IP 
+         && mp_withdraw.safi == SAFI_MULTICAST)
+       bgp_nlri_parse (peer, NULL, &mp_withdraw);
+    }
+  if (peer->afc[AFI_IP6][SAFI_UNICAST])
+    {
+      if (mp_update.length 
+         && mp_update.afi == AFI_IP6 
+         && mp_update.safi == SAFI_UNICAST)
+       bgp_nlri_parse (peer, &attr, &mp_update);
+
+      if (mp_withdraw.length 
+         && mp_withdraw.afi == AFI_IP6 
+         && mp_withdraw.safi == SAFI_UNICAST)
+       bgp_nlri_parse (peer, NULL, &mp_withdraw);
+    }
+  if (peer->afc[AFI_IP6][SAFI_MULTICAST])
+    {
+      if (mp_update.length 
+         && mp_update.afi == AFI_IP6 
+         && mp_update.safi == SAFI_MULTICAST)
+       bgp_nlri_parse (peer, &attr, &mp_update);
+
+      if (mp_withdraw.length 
+         && mp_withdraw.afi == AFI_IP6 
+         && mp_withdraw.safi == SAFI_MULTICAST)
+       bgp_nlri_parse (peer, NULL, &mp_withdraw);
+    }
+  if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
+    {
+      if (mp_update.length 
+         && mp_update.afi == AFI_IP 
+         && mp_update.safi == BGP_SAFI_VPNV4)
+       bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
+
+      if (mp_withdraw.length 
+         && mp_withdraw.afi == AFI_IP 
+         && mp_withdraw.safi == BGP_SAFI_VPNV4)
+       bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);
+    }
+
+  /* Everything is done.  We unintern temporary structures which
+     interned in bgp_attr_parse(). */
+  if (attr.aspath)
+    aspath_unintern (attr.aspath);
+  if (attr.community)
+    community_unintern (attr.community);
+  if (attr.ecommunity)
+    ecommunity_unintern (attr.ecommunity);
+  if (attr.cluster)
+    cluster_unintern (attr.cluster);
+  if (attr.transit)
+    transit_unintern (attr.transit);
+
+  /* If peering is stopped due to some reason, do not generate BGP
+     event.  */
+  if (peer->status != Established)
+    return 0;
+
+  /* Increment packet counter. */
+  peer->update_in++;
+  peer->update_time = time (NULL);
+
+  /* Generate BGP event. */
+  BGP_EVENT_ADD (peer, Receive_UPDATE_message);
+
+  return 0;
+}
+
+/* Notify message treatment function. */
+void
+bgp_notify_receive (struct peer *peer, bgp_size_t size)
+{
+  struct bgp_notify bgp_notify;
+
+  if (peer->notify.data)
+    {
+      XFREE (MTYPE_TMP, peer->notify.data);
+      peer->notify.data = NULL;
+      peer->notify.length = 0;
+    }
+
+  bgp_notify.code = stream_getc (peer->ibuf);
+  bgp_notify.subcode = stream_getc (peer->ibuf);
+  bgp_notify.length = size - 2;
+  bgp_notify.data = NULL;
+
+  /* Preserv notify code and sub code. */
+  peer->notify.code = bgp_notify.code;
+  peer->notify.subcode = bgp_notify.subcode;
+  /* For further diagnostic record returned Data. */
+  if (bgp_notify.length)
+    {
+      peer->notify.length = size - 2;
+      peer->notify.data = XMALLOC (MTYPE_TMP, size - 2);
+      memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2);
+    }
+
+  /* For debug */
+  {
+    int i;
+    int first = 0;
+    char c[4];
+
+    if (bgp_notify.length)
+      {
+       bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3);
+       for (i = 0; i < bgp_notify.length; i++)
+         if (first)
+           {
+             sprintf (c, " %02x", stream_getc (peer->ibuf));
+             strcat (bgp_notify.data, c);
+           }
+         else
+           {
+             first = 1;
+             sprintf (c, "%02x", stream_getc (peer->ibuf));
+             strcpy (bgp_notify.data, c);
+           }
+      }
+
+    bgp_notify_print(peer, &bgp_notify, "received");
+    if (bgp_notify.data)
+      XFREE (MTYPE_TMP, bgp_notify.data);
+  }
+
+  /* peer count update */
+  peer->notify_in++;
+
+  /* We have to check for Notify with Unsupported Optional Parameter.
+     in that case we fallback to open without the capability option.
+     But this done in bgp_stop. We just mark it here to avoid changing
+     the fsm tables.  */
+  if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR &&
+      bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM )
+    UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+
+  /* Also apply to Unsupported Capability until remote router support
+     capability. */
+  if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR &&
+      bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL)
+    UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+
+  BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message);
+}
+
+/* Keepalive treatment function -- get keepalive send keepalive */
+void
+bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
+{
+  if (BGP_DEBUG (keepalive, KEEPALIVE))  
+    zlog_info ("%s KEEPALIVE rcvd", peer->host); 
+  
+  BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message);
+}
+
+/* Route refresh message is received. */
+void
+bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
+{
+  afi_t afi;
+  safi_t safi;
+  u_char reserved;
+  struct stream *s;
+
+  /* If peer does not have the capability, send notification. */
+  if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV))
+    {
+      plog_err (peer->log, "%s [Error] BGP route refresh is not enabled",
+               peer->host);
+      bgp_notify_send (peer,
+                      BGP_NOTIFY_HEADER_ERR,
+                      BGP_NOTIFY_HEADER_BAD_MESTYPE);
+      return;
+    }
+
+  /* Status must be Established. */
+  if (peer->status != Established) 
+    {
+      plog_err (peer->log,
+               "%s [Error] Route refresh packet received under status %s",
+               peer->host, LOOKUP (bgp_status_msg, peer->status));
+      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+      return;
+    }
+
+  s = peer->ibuf;
+  
+  /* Parse packet. */
+  afi = stream_getw (s);
+  reserved = stream_getc (s);
+  safi = stream_getc (s);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s rcvd REFRESH_REQ for afi/safi: %d/%d",
+              peer->host, afi, safi);
+
+  /* Check AFI and SAFI. */
+  if ((afi != AFI_IP && afi != AFI_IP6)
+      || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+         && safi != BGP_SAFI_VPNV4))
+    {
+      if (BGP_DEBUG (normal, NORMAL))
+       {
+         zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored",
+                    peer->host, afi, safi);
+       }
+      return;
+    }
+
+  /* Adjust safi code. */
+  if (safi == BGP_SAFI_VPNV4)
+    safi = SAFI_MPLS_VPN;
+
+  if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
+    {
+      u_char *end;
+      u_char when_to_refresh;
+      u_char orf_type;
+      u_int16_t orf_len;
+
+      if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5)
+        {
+          zlog_info ("%s ORF route refresh length error", peer->host);
+          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+          return;
+        }
+
+      when_to_refresh = stream_getc (s);
+      end = stream_pnt (s) + (size - 5);
+
+      while (stream_pnt (s) < end)
+       {
+         orf_type = stream_getc (s); 
+         orf_len = stream_getw (s);
+
+         if (orf_type == ORF_TYPE_PREFIX
+             || orf_type == ORF_TYPE_PREFIX_OLD)
+           {
+             u_char *p_pnt = stream_pnt (s);
+             u_char *p_end = stream_pnt (s) + orf_len;
+             struct orf_prefix orfp;
+             u_char common = 0;
+             u_int32_t seq;
+             int psize;
+             char name[BUFSIZ];
+             char buf[BUFSIZ];
+             int ret;
+
+             if (BGP_DEBUG (normal, NORMAL))
+               {
+                 zlog_info ("%s rcvd Prefixlist ORF(%d) length %d",
+                            peer->host, orf_type, orf_len);
+               }
+
+             /* ORF prefix-list name */
+             sprintf (name, "%s.%d.%d", peer->host, afi, safi);
+
+             while (p_pnt < p_end)
+               {
+                 memset (&orfp, 0, sizeof (struct orf_prefix));
+                 common = *p_pnt++;
+                 if (common & ORF_COMMON_PART_REMOVE_ALL)
+                   {
+                     if (BGP_DEBUG (normal, NORMAL))
+                       zlog_info ("%s rcvd Remove-All pfxlist ORF request", peer->host);
+                     prefix_bgp_orf_remove_all (name);
+                     break;
+                   }
+                 memcpy (&seq, p_pnt, sizeof (u_int32_t));
+                 p_pnt += sizeof (u_int32_t);
+                 orfp.seq = ntohl (seq);
+                 orfp.ge = *p_pnt++;
+                 orfp.le = *p_pnt++;
+                 orfp.p.prefixlen = *p_pnt++;
+                 orfp.p.family = afi2family (afi);
+                 psize = PSIZE (orfp.p.prefixlen);
+                 memcpy (&orfp.p.u.prefix, p_pnt, psize);
+                 p_pnt += psize;
+
+                 if (BGP_DEBUG (normal, NORMAL))
+                   zlog_info ("%s rcvd %s %s seq %u %s/%d ge %d le %d",
+                              peer->host,
+                              (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), 
+                              (common & ORF_COMMON_PART_DENY ? "deny" : "permit"),
+                              orfp.seq, 
+                              inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ),
+                              orfp.p.prefixlen, orfp.ge, orfp.le);
+
+                 ret = prefix_bgp_orf_set (name, afi, &orfp,
+                                (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
+                                (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
+
+                 if (ret != CMD_SUCCESS)
+                   {
+                     if (BGP_DEBUG (normal, NORMAL))
+                       zlog_info ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host);
+                     prefix_bgp_orf_remove_all (name);
+                     break;
+                   }
+               }
+             peer->orf_plist[afi][safi] =
+                        prefix_list_lookup (AFI_ORF_PREFIX, name);
+           }
+         stream_forward (s, orf_len);
+       }
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s rcvd Refresh %s ORF request", peer->host,
+                  when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate");
+      if (when_to_refresh == REFRESH_DEFER)
+       return;
+    }
+
+  /* First update is deferred until ORF or ROUTE-REFRESH is received */
+  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
+    UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
+
+  /* Perform route refreshment to the peer */
+  bgp_announce_route (peer, afi, safi);
+}
+
+int
+bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
+{
+  u_char *end;
+  struct capability cap;
+  u_char action;
+  struct bgp *bgp;
+  afi_t afi;
+  safi_t safi;
+
+  bgp = peer->bgp;
+  end = pnt + length;
+
+  while (pnt < end)
+    {
+      /* We need at least action, capability code and capability length. */
+      if (pnt + 3 > end)
+        {
+          zlog_info ("%s Capability length error", peer->host);
+          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+          return -1;
+        }
+
+      action = *pnt;
+
+      /* Fetch structure to the byte stream. */
+      memcpy (&cap, pnt + 1, sizeof (struct capability));
+
+      /* Action value check.  */
+      if (action != CAPABILITY_ACTION_SET
+         && action != CAPABILITY_ACTION_UNSET)
+        {
+          zlog_info ("%s Capability Action Value error %d",
+                    peer->host, action);
+          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+          return -1;
+        }
+
+      if (BGP_DEBUG (normal, NORMAL))
+       zlog_info ("%s CAPABILITY has action: %d, code: %u, length %u",
+                  peer->host, action, cap.code, cap.length);
+
+      /* Capability length check. */
+      if (pnt + (cap.length + 3) > end)
+        {
+          zlog_info ("%s Capability length error", peer->host);
+          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+          return -1;
+        }
+
+      /* We know MP Capability Code. */
+      if (cap.code == CAPABILITY_CODE_MP)
+        {
+         afi = ntohs (cap.mpc.afi);
+         safi = cap.mpc.safi;
+
+          /* Ignore capability when override-capability is set. */
+          if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+           continue;
+
+         /* Address family check.  */
+         if ((afi == AFI_IP 
+              || afi == AFI_IP6)
+             && (safi == SAFI_UNICAST 
+                 || safi == SAFI_MULTICAST 
+                 || safi == BGP_SAFI_VPNV4))
+           {
+             if (BGP_DEBUG (normal, NORMAL))
+               zlog_info ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
+                          peer->host,
+                          action == CAPABILITY_ACTION_SET 
+                          ? "Advertising" : "Removing",
+                          ntohs(cap.mpc.afi) , cap.mpc.safi);
+                 
+             /* Adjust safi code. */
+             if (safi == BGP_SAFI_VPNV4)
+               safi = SAFI_MPLS_VPN;
+             
+             if (action == CAPABILITY_ACTION_SET)
+               {
+                 peer->afc_recv[afi][safi] = 1;
+                 if (peer->afc[afi][safi])
+                   {
+                     peer->afc_nego[afi][safi] = 1;
+                     bgp_announce_route (peer, afi, safi);
+                   }
+               }
+             else
+               {
+                 peer->afc_recv[afi][safi] = 0;
+                 peer->afc_nego[afi][safi] = 0;
+
+                 if (peer_active_nego (peer))
+                   bgp_clear_route (peer, afi, safi);
+                 else
+                   BGP_EVENT_ADD (peer, BGP_Stop);
+               } 
+           }
+        }
+      else if (cap.code == CAPABILITY_CODE_REFRESH
+              || cap.code == CAPABILITY_CODE_REFRESH_OLD)
+        {
+          /* Check length. */
+          if (cap.length != 0)
+            {
+              zlog_info ("%s Route Refresh Capability length error %d",
+                         peer->host, cap.length);
+              bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+              return -1;
+            }
+         
+          if (BGP_DEBUG (normal, NORMAL))
+            zlog_info ("%s CAPABILITY has %s ROUTE-REFRESH capability(%s) for all address-families",
+                      peer->host,
+                      action == CAPABILITY_ACTION_SET
+                      ? "Advertising" : "Removing",
+                      cap.code == CAPABILITY_CODE_REFRESH_OLD
+                      ? "old" : "new");
+         
+          /* BGP refresh capability */
+         if (action == CAPABILITY_ACTION_SET)
+           {
+             if (cap.code == CAPABILITY_CODE_REFRESH_OLD)
+               SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+             else
+               SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+           }
+         else
+           {
+             if (cap.code == CAPABILITY_CODE_REFRESH_OLD)
+               UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+             else
+               UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+           }
+        }
+      else
+        {
+          zlog_warn ("%s unrecognized capability code: %d - ignored",
+                     peer->host, cap.code);
+        }
+      pnt += cap.length + 3;
+    }
+  return 0;
+}
+
+/* Dynamic Capability is received. */
+void
+bgp_capability_receive (struct peer *peer, bgp_size_t size)
+{
+  u_char *pnt;
+  int ret;
+
+  /* Fetch pointer. */
+  pnt = stream_pnt (peer->ibuf);
+
+  if (BGP_DEBUG (normal, NORMAL))
+    zlog_info ("%s rcv CAPABILITY", peer->host);
+
+  /* If peer does not have the capability, send notification. */
+  if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV))
+    {
+      plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled",
+               peer->host);
+      bgp_notify_send (peer,
+                      BGP_NOTIFY_HEADER_ERR,
+                      BGP_NOTIFY_HEADER_BAD_MESTYPE);
+      return;
+    }
+
+  /* Status must be Established. */
+  if (peer->status != Established)
+    {
+      plog_err (peer->log,
+               "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status));
+      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+      return;
+    }
+
+  /* Parse packet. */
+  ret = bgp_capability_msg_parse (peer, pnt, size);
+}
+\f
+/* BGP read utility function. */
+int
+bgp_read_packet (struct peer *peer)
+{
+  int nbytes;
+  int readsize;
+
+  readsize = peer->packet_size - peer->ibuf->putp;
+
+  /* If size is zero then return. */
+  if (! readsize)
+    return 0;
+
+  /* Read packet from fd. */
+  nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize);
+
+  /* If read byte is smaller than zero then error occured. */
+  if (nbytes < 0) 
+    {
+      if (errno == EAGAIN)
+       return -1;
+
+      plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
+                peer->host, strerror (errno));
+      BGP_EVENT_ADD (peer, TCP_fatal_error);
+      return -1;
+    }  
+
+  /* When read byte is zero : clear bgp peer and return */
+  if (nbytes == 0) 
+    {
+      if (BGP_DEBUG (events, EVENTS))
+       plog_info (peer->log, "%s [Event] BGP connection closed fd %d",
+                  peer->host, peer->fd);
+      BGP_EVENT_ADD (peer, TCP_connection_closed);
+      return -1;
+    }
+
+  /* We read partial packet. */
+  if (peer->ibuf->putp != peer->packet_size)
+    return -1;
+
+  return 0;
+}
+
+/* Marker check. */
+int
+bgp_marker_all_one (struct stream *s, int length)
+{
+  int i;
+
+  for (i = 0; i < length; i++)
+    if (s->data[i] != 0xff)
+      return 0;
+
+  return 1;
+}
+
+/* Starting point of packet process function. */
+int
+bgp_read (struct thread *thread)
+{
+  int ret;
+  u_char type = 0;
+  struct peer *peer;
+  bgp_size_t size;
+  char notify_data_length[2];
+
+  /* Yes first of all get peer pointer. */
+  peer = THREAD_ARG (thread);
+  peer->t_read = NULL;
+
+  /* For non-blocking IO check. */
+  if (peer->status == Connect)
+    {
+      bgp_connect_check (peer);
+      goto done;
+    }
+  else
+    {
+      if (peer->fd < 0)
+       {
+         zlog_err ("bgp_read peer's fd is negative value %d", peer->fd);
+         return -1;
+       }
+      BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
+    }
+
+  /* Read packet header to determine type of the packet */
+  if (peer->packet_size == 0)
+    peer->packet_size = BGP_HEADER_SIZE;
+
+  if (peer->ibuf->putp < BGP_HEADER_SIZE)
+    {
+      ret = bgp_read_packet (peer);
+
+      /* Header read error or partial read packet. */
+      if (ret < 0) 
+       goto done;
+
+      /* Get size and type. */
+      stream_forward (peer->ibuf, BGP_MARKER_SIZE);
+      memcpy (notify_data_length, stream_pnt (peer->ibuf), 2);
+      size = stream_getw (peer->ibuf);
+      type = stream_getc (peer->ibuf);
+
+      if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0)
+       zlog_info ("%s rcv message type %d, length (excl. header) %d",
+                  peer->host, type, size - BGP_HEADER_SIZE);
+
+      /* Marker check */
+      if (type == BGP_MSG_OPEN
+         && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE))
+       {
+         bgp_notify_send (peer,
+                          BGP_NOTIFY_HEADER_ERR, 
+                          BGP_NOTIFY_HEADER_NOT_SYNC);
+         goto done;
+       }
+
+      /* BGP type check. */
+      if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE 
+         && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE 
+         && type != BGP_MSG_ROUTE_REFRESH_NEW
+         && type != BGP_MSG_ROUTE_REFRESH_OLD
+         && type != BGP_MSG_CAPABILITY)
+       {
+         if (BGP_DEBUG (normal, NORMAL))
+           plog_err (peer->log,
+                     "%s unknown message type 0x%02x",
+                     peer->host, type);
+         bgp_notify_send_with_data (peer,
+                                    BGP_NOTIFY_HEADER_ERR,
+                                    BGP_NOTIFY_HEADER_BAD_MESTYPE,
+                                    &type, 1);
+         goto done;
+       }
+      /* Mimimum packet length check. */
+      if ((size < BGP_HEADER_SIZE)
+         || (size > BGP_MAX_PACKET_SIZE)
+         || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE)
+         || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE)
+         || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE)
+         || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE)
+         || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
+         || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
+         || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE))
+       {
+         if (BGP_DEBUG (normal, NORMAL))
+           plog_err (peer->log,
+                     "%s bad message length - %d for %s",
+                     peer->host, size, 
+                     type == 128 ? "ROUTE-REFRESH" :
+                     bgp_type_str[(int) type]);
+         bgp_notify_send_with_data (peer,
+                                    BGP_NOTIFY_HEADER_ERR,
+                                    BGP_NOTIFY_HEADER_BAD_MESLEN,
+                                    notify_data_length, 2);
+         goto done;
+       }
+
+      /* Adjust size to message length. */
+      peer->packet_size = size;
+    }
+
+  ret = bgp_read_packet (peer);
+  if (ret < 0) 
+    goto done;
+
+  /* Get size and type again. */
+  size = stream_getw_from (peer->ibuf, BGP_MARKER_SIZE);
+  type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2);
+
+  /* BGP packet dump function. */
+  bgp_dump_packet (peer, type, peer->ibuf);
+  
+  size = (peer->packet_size - BGP_HEADER_SIZE);
+
+  /* Read rest of the packet and call each sort of packet routine */
+  switch (type) 
+    {
+    case BGP_MSG_OPEN:
+      peer->open_in++;
+      bgp_open_receive (peer, size);
+      break;
+    case BGP_MSG_UPDATE:
+      peer->readtime = time(NULL);    /* Last read timer reset */
+      bgp_update_receive (peer, size);
+      break;
+    case BGP_MSG_NOTIFY:
+      bgp_notify_receive (peer, size);
+      break;
+    case BGP_MSG_KEEPALIVE:
+      peer->readtime = time(NULL);    /* Last read timer reset */
+      bgp_keepalive_receive (peer, size);
+      break;
+    case BGP_MSG_ROUTE_REFRESH_NEW:
+    case BGP_MSG_ROUTE_REFRESH_OLD:
+      peer->refresh_in++;
+      bgp_route_refresh_receive (peer, size);
+      break;
+    case BGP_MSG_CAPABILITY:
+      peer->dynamic_cap_in++;
+      bgp_capability_receive (peer, size);
+      break;
+    }
+
+  /* Clear input buffer. */
+  peer->packet_size = 0;
+  if (peer->ibuf)
+    stream_reset (peer->ibuf);
+
+ done:
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+    {
+      if (BGP_DEBUG (events, EVENTS))
+       zlog_info ("%s [Event] Accepting BGP peer delete", peer->host);
+      peer_delete (peer);
+    }
+  return 0;
+}
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
new file mode 100644 (file)
index 0000000..c1efc8b
--- /dev/null
@@ -0,0 +1,49 @@
+/* BGP packet management header.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#define BGP_NLRI_LENGTH       1
+#define BGP_TOTAL_ATTR_LEN    2
+#define BGP_UNFEASIBLE_LEN    2
+#define BGP_WRITE_PACKET_MAX 10
+
+/* When to refresh */
+#define REFRESH_IMMEDIATE 1
+#define REFRESH_DEFER     2 
+
+/* ORF Common part flag */
+#define ORF_COMMON_PART_ADD        0x00 
+#define ORF_COMMON_PART_REMOVE     0x80 
+#define ORF_COMMON_PART_REMOVE_ALL 0xC0 
+#define ORF_COMMON_PART_PERMIT     0x00 
+#define ORF_COMMON_PART_DENY       0x20 
+
+/* Packet send and receive function prototypes. */
+int bgp_read (struct thread *);
+int bgp_write (struct thread *);
+
+void bgp_keepalive_send (struct peer *);
+void bgp_open_send (struct peer *);
+void bgp_notify_send (struct peer *, u_char, u_char);
+void bgp_notify_send_with_data (struct peer *, u_char, u_char, u_char *, size_t);
+void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int);
+void bgp_capability_send (struct peer *, afi_t, safi_t, int, int);
+void bgp_default_update_send (struct peer *, struct attr *,
+                             afi_t, safi_t, struct peer *);
+void bgp_default_withdraw_send (struct peer *, afi_t, safi_t);
diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c
new file mode 100644 (file)
index 0000000..a6b6598
--- /dev/null
@@ -0,0 +1,93 @@
+/* AS regular expression routine
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "command.h"
+#include "memory.h"
+
+#include "bgpd.h"
+#include "bgp_aspath.h"
+#include "bgp_regex.h"
+
+/* Character `_' has special mean.  It represents [,{}() ] and the
+   beginning of the line(^) and the end of the line ($).  
+
+   (^|[,{}() ]|$) */
+
+regex_t *
+bgp_regcomp (char *regstr)
+{
+  /* Convert _ character to generic regular expression. */
+  int i, j;
+  int len;
+  int magic = 0;
+  char *magic_str;
+  char magic_regexp[] = "(^|[,{}() ]|$)";
+  int ret;
+  regex_t *regex;
+
+  len = strlen (regstr);
+  for (i = 0; i < len; i++)
+    if (regstr[i] == '_')
+      magic++;
+
+  magic_str = XMALLOC (MTYPE_TMP, len + (14 * magic) + 1);
+  
+  for (i = 0, j = 0; i < len; i++)
+    {
+      if (regstr[i] == '_')
+       {
+         memcpy (magic_str + j, magic_regexp, strlen (magic_regexp));
+         j += strlen (magic_regexp);
+       }
+      else
+       magic_str[j++] = regstr[i];
+    }
+  magic_str[j] = '\0';
+
+  regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t));
+
+  ret = regcomp (regex, magic_str, REG_EXTENDED);
+
+  XFREE (MTYPE_TMP, magic_str);
+
+  if (ret != 0)
+    {
+      XFREE (MTYPE_BGP_REGEXP, regex);
+      return NULL;
+    }
+
+  return regex;
+}
+
+int
+bgp_regexec (regex_t *regex, struct aspath *aspath)
+{
+  return regexec (regex, aspath->str, 0, NULL, 0);
+}
+
+void
+bgp_regex_free (regex_t *regex)
+{
+  regfree (regex);
+  XFREE (MTYPE_BGP_REGEXP, regex);
+}
diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h
new file mode 100644 (file)
index 0000000..0829dd9
--- /dev/null
@@ -0,0 +1,31 @@
+/* AS regular expression routine
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#ifdef HAVE_GNU_REGEX
+#include <regex.h>
+#else
+#include "regex-gnu.h"
+#endif /* HAVE_GNU_REGEX */
+
+void bgp_regex_free (regex_t *regex);
+regex_t *bgp_regcomp (char *str);
+int bgp_regexec (regex_t *regex, struct aspath *aspath);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
new file mode 100644 (file)
index 0000000..87d305c
--- /dev/null
@@ -0,0 +1,9053 @@
+/* BGP routing information
+   Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "linklist.h"
+#include "memory.h"
+#include "command.h"
+#include "stream.h"
+#include "filter.h"
+#include "str.h"
+#include "log.h"
+#include "routemap.h"
+#include "buffer.h"
+#include "sockunion.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_zebra.h"
+
+/* Extern from bgp_dump.c */
+extern char *bgp_origin_str[];
+extern char *bgp_origin_long_str[];
+\f
+struct bgp_node *
+bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p,
+                 struct prefix_rd *prd)
+{
+  struct bgp_node *rn;
+  struct bgp_node *prn = NULL;
+  struct bgp_table *table;
+
+  if (safi == SAFI_MPLS_VPN)
+    {
+      prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd);
+
+      if (prn->info == NULL)
+       prn->info = bgp_table_init ();
+      else
+       bgp_unlock_node (prn);
+      table = prn->info;
+    }
+  else
+    table = bgp->rib[afi][safi];
+
+  rn = bgp_node_get (table, p);
+
+  if (safi == SAFI_MPLS_VPN)
+    rn->prn = prn;
+
+  return rn;
+}
+\f
+/* Allocate new bgp info structure. */
+struct bgp_info *
+bgp_info_new ()
+{
+  struct bgp_info *new;
+
+  new = XMALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info));
+  memset (new, 0, sizeof (struct bgp_info));
+
+  return new;
+}
+
+/* Free bgp route information. */
+void
+bgp_info_free (struct bgp_info *binfo)
+{
+  if (binfo->attr)
+    bgp_attr_unintern (binfo->attr);
+
+  if (binfo->damp_info)
+    bgp_damp_info_free (binfo->damp_info, 0);
+
+  XFREE (MTYPE_BGP_ROUTE, binfo);
+}
+
+void
+bgp_info_add (struct bgp_node *rn, struct bgp_info *ri)
+{
+  struct bgp_info *top;
+
+  top = rn->info;
+
+  ri->next = rn->info;
+  ri->prev = NULL;
+  if (top)
+    top->prev = ri;
+  rn->info = ri;
+}
+
+void
+bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri)
+{
+  if (ri->next)
+    ri->next->prev = ri->prev;
+  if (ri->prev)
+    ri->prev->next = ri->next;
+  else
+    rn->info = ri->next;
+}
+
+/* Get MED value.  If MED value is missing and "bgp bestpath
+   missing-as-worst" is specified, treat it as the worst value. */
+u_int32_t
+bgp_med_value (struct attr *attr, struct bgp *bgp)
+{
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+    return attr->med;
+  else
+    {
+      if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST))
+       return 4294967295ul;
+      else
+       return 0;
+    }
+}
+
+/* Compare two bgp route entity.  br is preferable then return 1. */
+int
+bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
+{
+  u_int32_t new_pref;
+  u_int32_t exist_pref;
+  u_int32_t new_med;
+  u_int32_t exist_med;
+  struct in_addr new_id;
+  struct in_addr exist_id;
+  int new_cluster;
+  int exist_cluster;
+  int internal_as_route = 0;
+  int confed_as_route = 0;
+  int ret;
+
+  /* 0. Null check. */
+  if (new == NULL)
+    return 0;
+  if (exist == NULL)
+    return 1;
+
+  /* 1. Weight check. */
+  if (new->attr->weight > exist->attr->weight)
+    return 1;
+  if (new->attr->weight < exist->attr->weight)
+    return 0;
+
+  /* 2. Local preference check. */
+  if (new->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
+    new_pref = new->attr->local_pref;
+  else
+    new_pref = bgp->default_local_pref;
+
+  if (exist->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
+    exist_pref = exist->attr->local_pref;
+  else
+    exist_pref = bgp->default_local_pref;
+    
+  if (new_pref > exist_pref)
+    return 1;
+  if (new_pref < exist_pref)
+    return 0;
+
+  /* 3. Local route check. */
+  if (new->sub_type == BGP_ROUTE_STATIC)
+    return 1;
+  if (exist->sub_type == BGP_ROUTE_STATIC)
+    return 0;
+
+  if (new->sub_type == BGP_ROUTE_REDISTRIBUTE)
+    return 1;
+  if (exist->sub_type == BGP_ROUTE_REDISTRIBUTE)
+    return 0;
+
+  if (new->sub_type == BGP_ROUTE_AGGREGATE)
+    return 1;
+  if (exist->sub_type == BGP_ROUTE_AGGREGATE)
+    return 0;
+
+  /* 4. AS path length check. */
+  if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE))
+    {
+      if (new->attr->aspath->count < exist->attr->aspath->count)
+       return 1;
+      if (new->attr->aspath->count > exist->attr->aspath->count)
+       return 0;
+    }
+
+  /* 5. Origin check. */
+  if (new->attr->origin < exist->attr->origin)
+    return 1;
+  if (new->attr->origin > exist->attr->origin)
+    return 0;
+
+  /* 6. MED check. */
+  internal_as_route = (new->attr->aspath->length == 0
+                     && exist->attr->aspath->length == 0);
+  confed_as_route = (new->attr->aspath->length > 0
+                   && exist->attr->aspath->length > 0
+                   && new->attr->aspath->count == 0
+                   && exist->attr->aspath->count == 0);
+  
+  if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)
+      || (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
+        && confed_as_route)
+      || aspath_cmp_left (new->attr->aspath, exist->attr->aspath)
+      || aspath_cmp_left_confed (new->attr->aspath, exist->attr->aspath)
+      || internal_as_route)
+    {
+      new_med = bgp_med_value (new->attr, bgp);
+      exist_med = bgp_med_value (exist->attr, bgp);
+
+      if (new_med < exist_med)
+       return 1;
+      if (new_med > exist_med)
+       return 0;
+    }
+
+  /* 7. Peer type check. */
+  if (peer_sort (new->peer) == BGP_PEER_EBGP 
+      && peer_sort (exist->peer) == BGP_PEER_IBGP)
+    return 1;
+  if (peer_sort (new->peer) == BGP_PEER_EBGP 
+      && peer_sort (exist->peer) == BGP_PEER_CONFED)
+    return 1;
+  if (peer_sort (new->peer) == BGP_PEER_IBGP 
+      && peer_sort (exist->peer) == BGP_PEER_EBGP)
+    return 0;
+  if (peer_sort (new->peer) == BGP_PEER_CONFED 
+      && peer_sort (exist->peer) == BGP_PEER_EBGP)
+    return 0;
+
+  /* 8. IGP metric check. */
+  if (new->igpmetric < exist->igpmetric)
+    return 1;
+  if (new->igpmetric > exist->igpmetric)
+    return 0;
+
+  /* 9. Maximum path check. */
+
+  /* 10. If both paths are external, prefer the path that was received
+     first (the oldest one).  This step minimizes route-flap, since a
+     newer path won't displace an older one, even if it was the
+     preferred route based on the additional decision criteria below.  */
+  if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)
+      && peer_sort (new->peer) == BGP_PEER_EBGP
+      && peer_sort (exist->peer) == BGP_PEER_EBGP)
+    {
+      if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED))
+       return 1;
+      if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED))
+       return 0;
+    }
+
+  /* 11. Rourter-ID comparision. */
+  if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+    new_id.s_addr = new->attr->originator_id.s_addr;
+  else
+    new_id.s_addr = new->peer->remote_id.s_addr;
+  if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+    exist_id.s_addr = exist->attr->originator_id.s_addr;
+  else
+    exist_id.s_addr = exist->peer->remote_id.s_addr;
+
+  if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr))
+    return 1;
+  if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr))
+    return 0;
+
+  /* 12. Cluster length comparision. */
+  if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
+    new_cluster = new->attr->cluster->length;
+  else
+    new_cluster = 0;
+  if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
+    exist_cluster = exist->attr->cluster->length;
+  else
+    exist_cluster = 0;
+
+  if (new_cluster < exist_cluster)
+    return 1;
+  if (new_cluster > exist_cluster)
+    return 0;
+
+  /* 13. Neighbor address comparision. */
+  ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote);
+
+  if (ret == 1)
+    return 0;
+  if (ret == -1)
+    return 1;
+
+  return 1;
+}
+
+enum filter_type
+bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr,
+                 afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+
+  filter = &peer->filter[afi][safi];
+
+  if (DISTRIBUTE_IN_NAME (filter))
+    if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY)
+      return FILTER_DENY;
+
+  if (PREFIX_LIST_IN_NAME (filter))
+    if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY)
+      return FILTER_DENY;
+  
+  if (FILTER_LIST_IN_NAME (filter))
+    if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY)
+      return FILTER_DENY;
+
+  return FILTER_PERMIT;
+}
+
+enum filter_type
+bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr,
+                  afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+
+  filter = &peer->filter[afi][safi];
+
+  if (DISTRIBUTE_OUT_NAME (filter))
+    if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY)
+      return FILTER_DENY;
+
+  if (PREFIX_LIST_OUT_NAME (filter))
+    if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY)
+      return FILTER_DENY;
+
+  if (FILTER_LIST_OUT_NAME (filter))
+    if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY)
+      return FILTER_DENY;
+
+  return FILTER_PERMIT;
+}
+
+/* If community attribute includes no_export then return 1. */
+int
+bgp_community_filter (struct peer *peer, struct attr *attr)
+{
+  if (attr->community)
+    {
+      /* NO_ADVERTISE check. */
+      if (community_include (attr->community, COMMUNITY_NO_ADVERTISE))
+       return 1;
+
+      /* NO_EXPORT check. */
+      if (peer_sort (peer) == BGP_PEER_EBGP &&
+         community_include (attr->community, COMMUNITY_NO_EXPORT))
+       return 1;
+
+      /* NO_EXPORT_SUBCONFED check. */
+      if (peer_sort (peer) == BGP_PEER_EBGP 
+         || peer_sort (peer) == BGP_PEER_CONFED)
+       if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED))
+         return 1;
+    }
+  return 0;
+}
+
+/* Route reflection loop check.  */
+static int
+bgp_cluster_filter (struct peer *peer, struct attr *attr)
+{
+  struct in_addr cluster_id;
+
+  if (attr->cluster)
+    {
+      if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID)
+       cluster_id = peer->bgp->cluster_id;
+      else
+       cluster_id = peer->bgp->router_id;
+      
+      if (cluster_loop_check (attr->cluster, cluster_id))
+       return 1;
+    }
+  return 0;
+}
+\f
+int
+bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
+                   afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+  struct bgp_info info;
+  route_map_result_t ret;
+
+  filter = &peer->filter[afi][safi];
+
+  /* Apply default weight value. */
+  attr->weight = peer->weight;
+
+  /* Route map apply. */
+  if (ROUTE_MAP_IN_NAME (filter))
+    {
+      /* Duplicate current value to new strucutre for modification. */
+      info.peer = peer;
+      info.attr = attr;
+
+      /* Apply BGP route map to the attribute. */
+      ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info);
+      if (ret == RMAP_DENYMATCH)
+       {
+         /* Free newly generated AS path and community by route-map. */
+         bgp_attr_flush (attr);
+         return RMAP_DENY;
+       }
+    }
+  return RMAP_PERMIT;
+}
+\f
+int
+bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
+                   struct attr *attr, afi_t afi, safi_t safi)
+{
+  int ret;
+  char buf[SU_ADDRSTRLEN];
+  struct bgp_filter *filter;
+  struct bgp_info info;
+  struct peer *from;
+  struct bgp *bgp;
+  struct attr dummy_attr;
+  int transparent;
+  int reflect;
+
+  from = ri->peer;
+  filter = &peer->filter[afi][safi];
+  bgp = peer->bgp;
+  
+#ifdef DISABLE_BGP_ANNOUNCE
+  return 0;
+#endif
+
+  /* Do not send back route to sender. */
+  if (from == peer)
+    return 0;
+
+  /* Aggregate-address suppress check. */
+  if (ri->suppress)
+    if (! UNSUPPRESS_MAP_NAME (filter))
+      return 0;
+
+  /* Default route check.  */
+  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
+    {
+      if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY)
+       return 0;
+#ifdef HAVE_IPV6
+      else if (p->family == AF_INET6 && p->prefixlen == 0)
+       return 0;
+#endif /* HAVE_IPV6 */
+    }
+
+  /* If community is not disabled check the no-export and local. */
+  if (bgp_community_filter (peer, ri->attr)) 
+    return 0;
+
+  /* If the attribute has originator-id and it is same as remote
+     peer's id. */
+  if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
+    {
+      if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->originator_id))
+       {
+         if (BGP_DEBUG (filter, FILTER))  
+           zlog (peer->log, LOG_INFO,
+                 "%s [Update:SEND] %s/%d originator-id is same as remote router-id",
+                 peer->host,
+                 inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+                 p->prefixlen);
+         return 0;
+       }
+    }
+  /* ORF prefix-list filter check */
+  if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)
+      && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
+         || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)))
+    if (peer->orf_plist[afi][safi])
+      {
+       if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY)
+          return 0;
+      }
+
+  /* Output filter check. */
+  if (bgp_output_filter (peer, p, ri->attr, afi, safi) == FILTER_DENY)
+    {
+      if (BGP_DEBUG (filter, FILTER))
+       zlog (peer->log, LOG_INFO,
+             "%s [Update:SEND] %s/%d is filtered",
+             peer->host,
+             inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+             p->prefixlen);
+      return 0;
+    }
+
+#ifdef BGP_SEND_ASPATH_CHECK
+  /* AS path loop check. */
+  if (aspath_loop_check (ri->attr->aspath, peer->as))
+    {
+      if (BGP_DEBUG (filter, FILTER))  
+        zlog (peer->log, LOG_INFO, 
+             "%s [Update:SEND] suppress announcement to peer AS %d is AS path.",
+             peer->host, peer->as);
+      return 0;
+    }
+#endif /* BGP_SEND_ASPATH_CHECK */
+
+  /* If we're a CONFED we need to loop check the CONFED ID too */
+  if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
+    {
+      if (aspath_loop_check(ri->attr->aspath, bgp->confed_id))
+       {
+         if (BGP_DEBUG (filter, FILTER))  
+           zlog (peer->log, LOG_INFO, 
+                 "%s [Update:SEND] suppress announcement to peer AS %d is AS path.",
+                 peer->host,
+                 bgp->confed_id);
+         return 0;
+       }      
+    }
+
+  /* Route-Reflect check. */
+  if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP)
+    reflect = 1;
+  else
+    reflect = 0;
+
+  /* IBGP reflection check. */
+  if (reflect)
+    {
+      /* A route from a Client peer. */
+      if (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+       {
+         /* Reflect to all the Non-Client peers and also to the
+             Client peers other than the originator.  Originator check
+             is already done.  So there is noting to do. */
+         /* no bgp client-to-client reflection check. */
+         if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
+           if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+             return 0;
+       }
+      else
+       {
+         /* A route from a Non-client peer. Reflect to all other
+            clients. */
+         if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+           return 0;
+       }
+    }
+
+  /* For modify attribute, copy it to temporary structure. */
+  *attr = *ri->attr;
+
+  /* If local-preference is not set. */
+  if ((peer_sort (peer) == BGP_PEER_IBGP 
+       || peer_sort (peer) == BGP_PEER_CONFED) 
+      && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))))
+    {
+      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
+      attr->local_pref = bgp->default_local_pref;
+    }
+
+  /* Transparency check. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
+      && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
+    transparent = 1;
+  else
+    transparent = 0;
+
+  /* Remove MED if its an EBGP peer - will get overwritten by route-maps */
+  if (peer_sort (peer) == BGP_PEER_EBGP 
+      && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+    {
+      if (ri->peer != bgp->peer_self && ! transparent
+         && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
+       attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC));
+    }
+
+  /* next-hop-set */
+  if (transparent || reflect
+      || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
+         && ((p->family == AF_INET && attr->nexthop.s_addr)
+             || (p->family == AF_INET6 && ri->peer != bgp->peer_self))))
+    {
+      /* NEXT-HOP Unchanged. */
+    }
+  else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)
+          || (p->family == AF_INET && attr->nexthop.s_addr == 0)
+#ifdef HAVE_IPV6
+          || (p->family == AF_INET6 && ri->peer == bgp->peer_self)
+#endif /* HAVE_IPV6 */
+          || (peer_sort (peer) == BGP_PEER_EBGP
+              && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0))
+    {
+      /* Set IPv4 nexthop. */
+      if (p->family == AF_INET)
+       {
+         if (safi == SAFI_MPLS_VPN)
+           memcpy (&attr->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
+         else
+           memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
+       }
+#ifdef HAVE_IPV6
+      /* Set IPv6 nexthop. */
+      if (p->family == AF_INET6)
+       {
+         /* IPv6 global nexthop must be included. */
+         memcpy (&attr->mp_nexthop_global, &peer->nexthop.v6_global, 
+                 IPV6_MAX_BYTELEN);
+         attr->mp_nexthop_len = 16;
+       }
+#endif /* HAVE_IPV6 */
+    }
+
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    {
+      /* Link-local address should not be transit to different peer. */
+      attr->mp_nexthop_len = 16;
+
+      /* Set link-local address for shared network peer. */
+      if (peer->shared_network 
+         && ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
+       {
+         memcpy (&attr->mp_nexthop_local, &peer->nexthop.v6_local, 
+                 IPV6_MAX_BYTELEN);
+         attr->mp_nexthop_len = 32;
+       }
+
+      /* If bgpd act as BGP-4+ route-reflector, do not send link-local
+        address.*/
+      if (reflect)
+       attr->mp_nexthop_len = 16;
+
+      /* If BGP-4+ link-local nexthop is not link-local nexthop. */
+      if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local))
+       attr->mp_nexthop_len = 16;
+    }
+#endif /* HAVE_IPV6 */
+
+  /* If this is EBGP peer and remove-private-AS is set.  */
+  if (peer_sort (peer) == BGP_PEER_EBGP
+      && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
+      && aspath_private_as_check (attr->aspath))
+    attr->aspath = aspath_empty_get ();
+
+  /* Route map & unsuppress-map apply. */
+  if (ROUTE_MAP_OUT_NAME (filter)
+      || ri->suppress)
+    {
+      info.peer = peer;
+      info.attr = attr;
+
+      /* The route reflector is not allowed to modify the attributes
+        of the reflected IBGP routes. */
+      if (peer_sort (from) == BGP_PEER_IBGP 
+         && peer_sort (peer) == BGP_PEER_IBGP)
+       {
+         dummy_attr = *attr;
+         info.attr = &dummy_attr;
+       }
+      if (ri->suppress)
+       ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info);
+      else
+       ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info);
+
+      if (ret == RMAP_DENYMATCH)
+       {
+         bgp_attr_flush (attr);
+         return 0;
+       }
+    }
+  return 1;
+}
+
+int
+bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
+{
+  struct prefix *p;
+  struct bgp_info *ri;
+  struct bgp_info *new_select;
+  struct bgp_info *old_select;
+  struct listnode *nn;
+  struct peer *peer;
+  struct attr attr;
+  struct bgp_info *ri1;
+  struct bgp_info *ri2;
+
+  p = &rn->p;
+
+  /* bgp deterministic-med */
+  new_select = NULL;
+  if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+    for (ri1 = rn->info; ri1; ri1 = ri1->next)
+      {
+       if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK))
+         continue;
+       if (BGP_INFO_HOLDDOWN (ri1))
+         continue;
+
+       new_select = ri1;
+       if (ri1->next)
+         for (ri2 = ri1->next; ri2; ri2 = ri2->next)
+           {
+             if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK))
+               continue;
+             if (BGP_INFO_HOLDDOWN (ri2))
+               continue;
+
+             if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
+                 || aspath_cmp_left_confed (ri1->attr->aspath,
+                                            ri2->attr->aspath))
+               {
+                 if (bgp_info_cmp (bgp, ri2, new_select))
+                   {
+                     UNSET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED);
+                     new_select = ri2;
+                   }
+
+                 SET_FLAG (ri2->flags, BGP_INFO_DMED_CHECK);
+               }
+           }
+       SET_FLAG (new_select->flags, BGP_INFO_DMED_CHECK);
+       SET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED);
+      }
+
+  /* Check old selected route and new selected route. */
+  old_select = NULL;
+  new_select = NULL;
+  for (ri = rn->info; ri; ri = ri->next)
+    {
+      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+       old_select = ri;
+
+      if (BGP_INFO_HOLDDOWN (ri))
+       continue;
+
+      if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)
+          && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED)))
+       {
+         UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK);
+         continue;
+        }
+      UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK);
+      UNSET_FLAG (ri->flags, BGP_INFO_DMED_SELECTED);
+
+      if (bgp_info_cmp (bgp, ri, new_select))
+       new_select = ri;
+    }
+
+  /* Nothing to do. */
+  if (old_select && old_select == new_select)
+    {
+      if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
+       {
+         if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED))
+           bgp_zebra_announce (p, old_select, bgp);
+         return 0;
+       }
+    }
+
+  if (old_select)
+    UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED);
+  if (new_select)
+    {
+      SET_FLAG (new_select->flags, BGP_INFO_SELECTED);
+      UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);
+    }
+
+  /* Check each BGP peer. */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      /* Announce route to Established peer. */
+      if (peer->status != Established)
+       continue;
+
+      /* Address family configuration check. */
+      if (! peer->afc_nego[afi][safi])
+       continue;
+
+      /* First update is deferred until ORF or ROUTE-REFRESH is received */
+      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
+       continue;
+
+      /* Announcement to peer->conf.  If the route is filtered,
+         withdraw it. */
+      if (new_select 
+         && bgp_announce_check (new_select, peer, p, &attr, afi, safi))
+       bgp_adj_out_set (rn, peer, p, &attr, afi, safi, new_select);
+      else
+       bgp_adj_out_unset (rn, peer, p, afi, safi);
+    }
+
+  /* FIB update. */
+  if (safi == SAFI_UNICAST && ! bgp->name &&
+      ! bgp_option_check (BGP_OPT_NO_FIB))
+    {
+      if (new_select 
+         && new_select->type == ZEBRA_ROUTE_BGP 
+         && new_select->sub_type == BGP_ROUTE_NORMAL)
+       bgp_zebra_announce (p, new_select, bgp);
+      else
+       {
+         /* Withdraw the route from the kernel. */
+         if (old_select 
+             && old_select->type == ZEBRA_ROUTE_BGP
+             && old_select->sub_type == BGP_ROUTE_NORMAL)
+           bgp_zebra_withdraw (p, old_select);
+       }
+    }
+  return 0;
+}
+
+int
+bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, safi_t safi)
+{
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)
+      && peer->pcount[afi][safi] >= peer->pmax[afi][safi])
+    {
+      zlog (peer->log, LOG_INFO,
+           "MAXPFXEXCEED: No. of prefix received from %s (afi %d): %ld exceed limit %ld",
+           peer->host, afi, peer->pcount[afi][safi], peer->pmax[afi][safi]);
+      if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
+       {
+         char ndata[7];
+
+         ndata[0] = (u_char)(afi >>  8);
+         ndata[1] = (u_char) afi;
+         ndata[3] = (u_char)(peer->pmax[afi][safi] >> 24);
+         ndata[4] = (u_char)(peer->pmax[afi][safi] >> 16);
+         ndata[5] = (u_char)(peer->pmax[afi][safi] >> 8);
+         ndata[6] = (u_char)(peer->pmax[afi][safi]);
+
+         if (safi == SAFI_MPLS_VPN)
+           safi = BGP_SAFI_VPNV4;
+         ndata[2] = (u_char) safi;
+
+         bgp_notify_send_with_data (peer, BGP_NOTIFY_CEASE,
+                                    BGP_NOTIFY_CEASE_MAX_PREFIX,
+                                    ndata, 7);
+         SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+         return 1;
+       }
+    }
+  return 0;
+}
+
+void
+bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
+               afi_t afi, safi_t safi)
+{
+  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+    {
+      peer->pcount[afi][safi]--;
+      bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
+      UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+      bgp_process (peer->bgp, rn, afi, safi);
+    }
+  bgp_info_delete (rn, ri);
+  bgp_info_free (ri);
+  bgp_unlock_node (rn);
+}
+
+void
+bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
+                 afi_t afi, safi_t safi, int force)
+{
+  int valid;
+  int status = BGP_DAMP_NONE;
+
+  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+    {
+      peer->pcount[afi][safi]--;
+      bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
+    }
+
+  if (! force)
+    {
+      if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+         && peer_sort (peer) == BGP_PEER_EBGP)
+       status = bgp_damp_withdraw (ri, rn, afi, safi, 0);
+
+      if (status == BGP_DAMP_SUPPRESSED)
+       return;
+    }
+
+  valid = CHECK_FLAG (ri->flags, BGP_INFO_VALID);
+  UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+  bgp_process (peer->bgp, rn, afi, safi);
+
+  if (valid)
+    SET_FLAG (ri->flags, BGP_INFO_VALID);
+
+  if (status != BGP_DAMP_USED)
+    {
+      bgp_info_delete (rn, ri);
+      bgp_info_free (ri);
+      bgp_unlock_node (rn);
+    }
+}
+
+int
+bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, 
+           afi_t afi, safi_t safi, int type, int sub_type,
+           struct prefix_rd *prd, u_char *tag, int soft_reconfig)
+{
+  int ret;
+  int aspath_loop_count = 0;
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct attr new_attr;
+  struct attr *attr_new;
+  struct bgp_info *ri;
+  struct bgp_info *new;
+  char *reason;
+  char buf[SU_ADDRSTRLEN];
+
+  bgp = peer->bgp;
+  rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
+
+  /* When peer's soft reconfiguration enabled.  Record input packet in
+     Adj-RIBs-In.  */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
+      && peer != bgp->peer_self && ! soft_reconfig)
+    bgp_adj_in_set (rn, peer, attr);
+
+  /* Check previously received route. */
+  for (ri = rn->info; ri; ri = ri->next)
+    if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type)
+      break;
+
+  /* AS path local-as loop check. */
+  if (peer->change_local_as)
+    {
+      if (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
+       aspath_loop_count = 1;
+
+      if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count) 
+       {
+         reason = "as-path contains our own AS;";
+         goto filtered;
+       }
+    }
+
+  /* AS path loop check. */
+  if (aspath_loop_check (attr->aspath, bgp->as) > peer->allowas_in[afi][safi]
+      || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
+         && aspath_loop_check(attr->aspath, bgp->confed_id)
+         > peer->allowas_in[afi][safi]))
+    {
+      reason = "as-path contains our own AS;";
+      goto filtered;
+    }
+
+  /* Route reflector originator ID check.  */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)
+      && IPV4_ADDR_SAME (&bgp->router_id, &attr->originator_id))
+    {
+      reason = "originator is us;";
+      goto filtered;
+    }
+
+  /* Route reflector cluster ID check.  */
+  if (bgp_cluster_filter (peer, attr))
+    {
+      reason = "reflected from the same cluster;";
+      goto  filtered;
+    }
+
+  /* Apply incoming filter.  */
+  if (bgp_input_filter (peer, p, attr, afi, safi) == FILTER_DENY)
+    {
+      reason = "filter;";
+      goto filtered;
+    }
+
+  /* Apply incoming route-map. */
+  new_attr = *attr;
+
+  if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY)
+    {
+      reason = "route-map;";
+      goto filtered;
+    }
+
+  /* IPv4 unicast next hop check.  */
+  if (afi == AFI_IP && safi == SAFI_UNICAST)
+    {
+      /* If the peer is EBGP and nexthop is not on connected route,
+        discard it.  */
+      if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1
+         && ! bgp_nexthop_check_ebgp (afi, &new_attr)
+         && ! CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))
+       {
+         reason = "non-connected next-hop;";
+         goto filtered;
+       }
+
+      /* Next hop must not be 0.0.0.0 nor Class E address.  Next hop
+        must not be my own address.  */
+      if (bgp_nexthop_self (afi, &new_attr)
+         || new_attr.nexthop.s_addr == 0
+         || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
+       {
+         reason = "martian next-hop;";
+         goto filtered;
+       }
+    }
+
+  attr_new = bgp_attr_intern (&new_attr);
+
+  /* If the update is implicit withdraw. */
+  if (ri)
+    {
+      ri->uptime = time (NULL);
+
+      /* Same attribute comes in. */
+      if (attrhash_cmp (ri->attr, attr_new))
+       {
+         UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+
+         if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+             && peer_sort (peer) == BGP_PEER_EBGP
+             && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+           {
+             if (BGP_DEBUG (update, UPDATE_IN))  
+                 zlog (peer->log, LOG_INFO, "%s rcvd %s/%d",
+                 peer->host,
+                 inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+                 p->prefixlen);
+
+             peer->pcount[afi][safi]++;
+             ret = bgp_damp_update (ri, rn, afi, safi);
+             if (ret != BGP_DAMP_SUPPRESSED)
+               {
+                 bgp_aggregate_increment (bgp, p, ri, afi, safi);
+                 bgp_process (bgp, rn, afi, safi);
+               }
+           }
+         else
+           {
+             if (BGP_DEBUG (update, UPDATE_IN))  
+               zlog (peer->log, LOG_INFO,
+               "%s rcvd %s/%d...duplicate ignored",
+               peer->host,
+               inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+               p->prefixlen);
+           }
+
+         bgp_unlock_node (rn);
+         bgp_attr_unintern (attr_new);
+         return 0;
+       }
+
+      /* Received Logging. */
+      if (BGP_DEBUG (update, UPDATE_IN))  
+       zlog (peer->log, LOG_INFO, "%s rcvd %s/%d",
+             peer->host,
+             inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+             p->prefixlen);
+
+      /* The attribute is changed. */
+      SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+
+      /* Update bgp route dampening information.  */
+      if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+         && peer_sort (peer) == BGP_PEER_EBGP)
+       {
+         /* This is implicit withdraw so we should update dampening
+            information.  */
+         if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+           bgp_damp_withdraw (ri, rn, afi, safi, 1);  
+         else
+           peer->pcount[afi][safi]++;
+       }
+       
+      bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+
+      /* Update to new attribute.  */
+      bgp_attr_unintern (ri->attr);
+      ri->attr = attr_new;
+
+      /* Update MPLS tag.  */
+      if (safi == SAFI_MPLS_VPN)
+       memcpy (ri->tag, tag, 3);
+
+      /* Update bgp route dampening information.  */
+      if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+         && peer_sort (peer) == BGP_PEER_EBGP)
+       {
+         /* Now we do normal update dampening.  */
+         ret = bgp_damp_update (ri, rn, afi, safi);
+         if (ret == BGP_DAMP_SUPPRESSED)
+           {
+             bgp_unlock_node (rn);
+             return 0;
+           }
+       }
+
+      /* Nexthop reachability check. */
+      if ((afi == AFI_IP || afi == AFI_IP6)
+         && safi == SAFI_UNICAST 
+         && (peer_sort (peer) == BGP_PEER_IBGP
+             || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+             || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)))
+       {
+         if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL))
+           SET_FLAG (ri->flags, BGP_INFO_VALID);
+         else
+           UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+       }
+      else
+       SET_FLAG (ri->flags, BGP_INFO_VALID);
+
+      /* Process change. */
+      bgp_aggregate_increment (bgp, p, ri, afi, safi);
+
+      bgp_process (bgp, rn, afi, safi);
+      bgp_unlock_node (rn);
+      return 0;
+    }
+
+  /* Received Logging. */
+  if (BGP_DEBUG (update, UPDATE_IN))  
+    {
+      zlog (peer->log, LOG_INFO, "%s rcvd %s/%d",
+           peer->host,
+           inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+           p->prefixlen);
+    }
+
+  /* Increment prefix counter */
+  peer->pcount[afi][safi]++;
+
+  /* Make new BGP info. */
+  new = bgp_info_new ();
+  new->type = type;
+  new->sub_type = sub_type;
+  new->peer = peer;
+  new->attr = attr_new;
+  new->uptime = time (NULL);
+
+  /* Update MPLS tag. */
+  if (safi == SAFI_MPLS_VPN)
+    memcpy (new->tag, tag, 3);
+
+  /* Nexthop reachability check. */
+  if ((afi == AFI_IP || afi == AFI_IP6)
+      && safi == SAFI_UNICAST
+      && (peer_sort (peer) == BGP_PEER_IBGP
+         || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+         || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)))
+    {
+      if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL))
+       SET_FLAG (new->flags, BGP_INFO_VALID);
+      else
+       UNSET_FLAG (new->flags, BGP_INFO_VALID);
+    }
+  else
+    SET_FLAG (new->flags, BGP_INFO_VALID);
+
+  /* Aggregate address increment. */
+  bgp_aggregate_increment (bgp, p, new, afi, safi);
+  
+  /* Register new BGP information. */
+  bgp_info_add (rn, new);
+
+  /* If maximum prefix count is configured and current prefix
+     count exeed it. */
+  if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
+    if (bgp_maximum_prefix_overflow (peer, afi, safi))
+      return -1;
+
+  /* Process change. */
+  bgp_process (bgp, rn, afi, safi);
+
+  return 0;
+
+  /* This BGP update is filtered.  Log the reason then update BGP
+     entry.  */
+ filtered:
+  if (BGP_DEBUG (update, UPDATE_IN))
+    zlog (peer->log, LOG_INFO,
+         "%s rcvd UPDATE about %s/%d -- DENIED due to: %s",
+         peer->host,
+         inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+         p->prefixlen, reason);
+
+  if (ri)
+    bgp_rib_withdraw (rn, ri, peer, afi, safi, 1);
+
+  bgp_unlock_node (rn);
+
+  return 0;
+}
+
+int
+bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, 
+            int afi, int safi, int type, int sub_type, struct prefix_rd *prd,
+             u_char *tag)
+{
+  struct bgp *bgp;
+  char buf[SU_ADDRSTRLEN];
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+
+  bgp = peer->bgp;
+
+  /* Logging. */
+  if (BGP_DEBUG (update, UPDATE_IN))  
+    zlog (peer->log, LOG_INFO, "%s rcvd UPDATE about %s/%d -- withdrawn",
+         peer->host,
+         inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+         p->prefixlen);
+
+  /* Lookup node. */
+  rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
+
+  /* If peer is soft reconfiguration enabled.  Record input packet for
+     further calculation. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
+      && peer != bgp->peer_self)
+    bgp_adj_in_unset (rn, peer);
+
+  /* Lookup withdrawn route. */
+  for (ri = rn->info; ri; ri = ri->next)
+    if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type)
+      break;
+
+  /* Withdraw specified route from routing table. */
+  if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+    bgp_rib_withdraw (rn, ri, peer, afi, safi, 0);
+  else if (BGP_DEBUG (update, UPDATE_IN))
+    zlog (peer->log, LOG_INFO, 
+         "%s Can't find the route %s/%d", peer->host,
+         inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+         p->prefixlen);
+
+  /* Unlock bgp_node_get() lock. */
+  bgp_unlock_node (rn);
+
+  return 0;
+}
+\f
+void
+bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
+{
+  struct bgp *bgp;
+  struct attr attr;
+  struct aspath *aspath;
+  struct prefix p;
+  struct bgp_info binfo;
+  struct peer *from;
+  int ret = RMAP_DENYMATCH;
+
+  bgp = peer->bgp;
+  from = bgp->peer_self;
+
+  bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
+  aspath = attr.aspath;
+  attr.local_pref = bgp->default_local_pref;
+  memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
+
+  if (afi == AFI_IP)
+    str2prefix ("0.0.0.0/0", &p);
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      str2prefix ("::/0", &p);
+
+      /* IPv6 global nexthop must be included. */
+      memcpy (&attr.mp_nexthop_global, &peer->nexthop.v6_global, 
+             IPV6_MAX_BYTELEN);
+             attr.mp_nexthop_len = 16;
+      /* If the peer is on shared nextwork and we have link-local
+        nexthop set it. */
+      if (peer->shared_network 
+         && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
+       {
+         memcpy (&attr.mp_nexthop_local, &peer->nexthop.v6_local, 
+                 IPV6_MAX_BYTELEN);
+         attr.mp_nexthop_len = 32;
+       }
+    }
+#endif /* HAVE_IPV6 */
+  else
+    return;
+
+  if (peer->default_rmap[afi][safi].name)
+    {
+      binfo.peer = bgp->peer_self;
+      binfo.attr = &attr;
+
+      ret = route_map_apply (peer->default_rmap[afi][safi].map, &p,
+                            RMAP_BGP, &binfo);
+
+      if (ret == RMAP_DENYMATCH)
+       {
+         bgp_attr_flush (&attr);
+         withdraw = 1;
+       }
+    }
+
+  if (withdraw)
+    {
+      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
+       bgp_default_withdraw_send (peer, afi, safi);
+      UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE);
+    }
+  else
+    {
+      SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE);
+      bgp_default_update_send (peer, &attr, afi, safi, from);
+    }
+
+  aspath_unintern (aspath);
+}
+\f
+static void
+bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
+                   struct bgp_table *table)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+  struct attr attr;
+
+  if (! table)
+    table = peer->bgp->rib[afi][safi];
+
+  if (safi != SAFI_MPLS_VPN
+      && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
+    bgp_default_originate (peer, afi, safi, 0);
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn))
+    for (ri = rn->info; ri; ri = ri->next)
+      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer)
+       {
+         if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi))
+           bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri);
+         else
+           bgp_adj_out_unset (rn, peer, &rn->p, afi, safi);
+       }
+}
+
+void
+bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_table *table;
+
+  if (peer->status != Established)
+    return;
+
+  if (! peer->afc_nego[afi][safi])
+    return;
+
+  /* First update is deferred until ORF or ROUTE-REFRESH is received */
+  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
+    return;
+
+  if (safi != SAFI_MPLS_VPN)
+    bgp_announce_table (peer, afi, safi, NULL);
+  else
+    for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
+        rn = bgp_route_next(rn))
+      if ((table = (rn->info)) != NULL)
+       bgp_announce_table (peer, afi, safi, table);
+}
+
+void
+bgp_announce_route_all (struct peer *peer)
+{
+  afi_t afi;
+  safi_t safi;
+  
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      bgp_announce_route (peer, afi, safi);
+}
+\f
+static void
+bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,
+                        struct bgp_table *table)
+{
+  int ret;
+  struct bgp_node *rn;
+  struct bgp_adj_in *ain;
+
+  if (! table)
+    table = peer->bgp->rib[afi][safi];
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    for (ain = rn->adj_in; ain; ain = ain->next)
+      {
+       if (ain->peer == peer)
+         {
+           ret = bgp_update (peer, &rn->p, ain->attr, afi, safi,
+                             ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
+                             NULL, NULL, 1);
+           if (ret < 0)
+             {
+               bgp_unlock_node (rn);
+               return;
+             }
+           continue;
+         }
+      }
+}
+
+void
+bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_table *table;
+
+  if (peer->status != Established)
+    return;
+
+  if (safi != SAFI_MPLS_VPN)
+    bgp_soft_reconfig_table (peer, afi, safi, NULL);
+  else
+    for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
+        rn = bgp_route_next (rn))
+      if ((table = rn->info) != NULL)
+       bgp_soft_reconfig_table (peer, afi, safi, table);
+}
+\f
+static void
+bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
+                      struct bgp_table *table)
+{
+  struct bgp_node *rn;
+  struct bgp_adj_in *ain;
+  struct bgp_adj_out *aout;
+  struct bgp_info *ri;
+
+  if (! table)
+    table = peer->bgp->rib[afi][safi];
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    {
+      for (ri = rn->info; ri; ri = ri->next)
+       if (ri->peer == peer)
+         {
+           bgp_rib_remove (rn, ri, peer, afi, safi);
+           break;
+         }
+      for (ain = rn->adj_in; ain; ain = ain->next)
+       if (ain->peer == peer)
+         {
+           bgp_adj_in_remove (rn, ain);
+           bgp_unlock_node (rn);
+           break;
+         }
+      for (aout = rn->adj_out; aout; aout = aout->next)
+       if (aout->peer == peer)
+         {
+           bgp_adj_out_remove (rn, aout, peer, afi, safi);
+           bgp_unlock_node (rn);
+           break;
+         }
+    }
+}
+
+void
+bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_table *table;
+
+  if (! peer->afc[afi][safi])
+    return;
+
+  if (safi != SAFI_MPLS_VPN)
+    bgp_clear_route_table (peer, afi, safi, NULL);
+  else
+    for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
+        rn = bgp_route_next (rn))
+      if ((table = rn->info) != NULL)
+       bgp_clear_route_table (peer, afi, safi, table);
+}
+  
+void
+bgp_clear_route_all (struct peer *peer)
+{
+  afi_t afi;
+  safi_t safi;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      bgp_clear_route (peer, afi, safi);
+}
+
+void
+bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_table *table;
+  struct bgp_node *rn;
+  struct bgp_adj_in *ain;
+
+  table = peer->bgp->rib[afi][safi];
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    for (ain = rn->adj_in; ain ; ain = ain->next)
+      if (ain->peer == peer)
+       {
+          bgp_adj_in_remove (rn, ain);
+          bgp_unlock_node (rn);
+          break;
+       }
+}
+\f
+/* Delete all kernel routes. */
+void
+bgp_terminate ()
+{
+  struct bgp *bgp;
+  struct listnode *nn;
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct bgp_info *ri;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      table = bgp->rib[AFI_IP][SAFI_UNICAST];
+
+      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+       for (ri = rn->info; ri; ri = ri->next)
+         if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
+             && ri->type == ZEBRA_ROUTE_BGP 
+             && ri->sub_type == BGP_ROUTE_NORMAL)
+           bgp_zebra_withdraw (&rn->p, ri);
+
+      table = bgp->rib[AFI_IP6][SAFI_UNICAST];
+
+      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+       for (ri = rn->info; ri; ri = ri->next)
+         if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
+             && ri->type == ZEBRA_ROUTE_BGP 
+             && ri->sub_type == BGP_ROUTE_NORMAL)
+           bgp_zebra_withdraw (&rn->p, ri);
+    }
+}
+
+void
+bgp_reset ()
+{
+  vty_reset ();
+  bgp_zclient_reset ();
+  access_list_reset ();
+  prefix_list_reset ();
+}
+\f
+/* Parse NLRI stream.  Withdraw NLRI is recognized by NULL attr
+   value. */
+int
+bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
+{
+  u_char *pnt;
+  u_char *lim;
+  struct prefix p;
+  int psize;
+  int ret;
+
+  /* Check peer status. */
+  if (peer->status != Established)
+    return 0;
+  
+  pnt = packet->nlri;
+  lim = pnt + packet->length;
+
+  for (; pnt < lim; pnt += psize)
+    {
+      /* Clear prefix structure. */
+      memset (&p, 0, sizeof (struct prefix));
+
+      /* Fetch prefix length. */
+      p.prefixlen = *pnt++;
+      p.family = afi2family (packet->afi);
+      
+      /* Already checked in nlri_sanity_check().  We do double check
+         here. */
+      if ((packet->afi == AFI_IP && p.prefixlen > 32)
+         || (packet->afi == AFI_IP6 && p.prefixlen > 128))
+       return -1;
+
+      /* Packet size overflow check. */
+      psize = PSIZE (p.prefixlen);
+
+      /* When packet overflow occur return immediately. */
+      if (pnt + psize > lim)
+       return -1;
+
+      /* Fetch prefix from NLRI packet. */
+      memcpy (&p.u.prefix, pnt, psize);
+
+      /* Check address. */
+      if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST)
+       {
+         if (IN_CLASSD (ntohl (p.u.prefix4.s_addr)))
+           {
+             zlog (peer->log, LOG_ERR, 
+                   "IPv4 unicast NLRI is multicast address %s",
+                   inet_ntoa (p.u.prefix4));
+             bgp_notify_send (peer, 
+                              BGP_NOTIFY_UPDATE_ERR, 
+                              BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+             return -1;
+           }
+       }
+
+#ifdef HAVE_IPV6
+      /* Check address. */
+      if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST)
+       {
+         if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+           {
+             char buf[BUFSIZ];
+
+             zlog (peer->log, LOG_WARNING, 
+                   "IPv6 link-local NLRI received %s ignore this NLRI",
+                   inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+             continue;
+           }
+       }
+#endif /* HAVE_IPV6 */
+
+      /* Normal process. */
+      if (attr)
+       ret = bgp_update (peer, &p, attr, packet->afi, packet->safi, 
+                         ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);
+      else
+       ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi, 
+                           ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL);
+
+      /* Address family configuration mismatch or maximum-prefix count
+         overflow. */
+      if (ret < 0)
+       return -1;
+    }
+
+  /* Packet length consistency check. */
+  if (pnt != lim)
+    return -1;
+
+  return 0;
+}
+
+/* NLRI encode syntax check routine. */
+int
+bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
+                      bgp_size_t length)
+{
+  u_char *end;
+  u_char prefixlen;
+  int psize;
+
+  end = pnt + length;
+
+  /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for
+     syntactic validity.  If the field is syntactically incorrect,
+     then the Error Subcode is set to Invalid Network Field. */
+
+  while (pnt < end)
+    {
+      prefixlen = *pnt++;
+      
+      /* Prefix length check. */
+      if ((afi == AFI_IP && prefixlen > 32)
+         || (afi == AFI_IP6 && prefixlen > 128))
+       {
+         plog_err (peer->log, 
+                   "%s [Error] Update packet error (wrong prefix length %d)",
+                   peer->host, prefixlen);
+         bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                          BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+         return -1;
+       }
+
+      /* Packet size overflow check. */
+      psize = PSIZE (prefixlen);
+
+      if (pnt + psize > end)
+       {
+         plog_err (peer->log, 
+                   "%s [Error] Update packet error"
+                   " (prefix data overflow prefix size is %d)",
+                   peer->host, psize);
+         bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                          BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+         return -1;
+       }
+
+      pnt += psize;
+    }
+
+  /* Packet length consistency check. */
+  if (pnt != end)
+    {
+      plog_err (peer->log,
+               "%s [Error] Update packet error"
+               " (prefix length mismatch with total length)",
+               peer->host);
+      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, 
+                      BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+      return -1;
+    }
+  return 0;
+}
+\f
+struct bgp_static *
+bgp_static_new ()
+{
+  struct bgp_static *new;
+  new = XMALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static));
+  memset (new, 0, sizeof (struct bgp_static));
+  return new;
+}
+
+void
+bgp_static_free (struct bgp_static *bgp_static)
+{
+  if (bgp_static->rmap.name)
+    free (bgp_static->rmap.name);
+  XFREE (MTYPE_BGP_STATIC, bgp_static);
+}
+
+void
+bgp_static_update (struct bgp *bgp, struct prefix *p,
+                  struct bgp_static *bgp_static, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+  struct bgp_info *new;
+  struct bgp_info info;
+  struct attr attr;
+  struct attr *attr_new;
+  int ret;
+
+  rn = bgp_afi_node_get (bgp, afi, safi, p, NULL);
+
+  bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
+  if (bgp_static)
+    {
+      attr.nexthop = bgp_static->igpnexthop;
+      attr.med = bgp_static->igpmetric;
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+    }
+
+  /* Apply route-map. */
+  if (bgp_static->rmap.name)
+    {
+      info.peer = bgp->peer_self;
+      info.attr = &attr;
+
+      ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info);
+      if (ret == RMAP_DENYMATCH)
+       {    
+         /* Free uninterned attribute. */
+         bgp_attr_flush (&attr);
+
+         /* Unintern original. */
+         aspath_unintern (attr.aspath);
+         bgp_static_withdraw (bgp, p, afi, safi);
+         return;
+       }
+    }
+
+  attr_new = bgp_attr_intern (&attr);
+
+  for (ri = rn->info; ri; ri = ri->next)
+    if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP
+       && ri->sub_type == BGP_ROUTE_STATIC)
+      break;
+
+  if (ri)
+    {
+      if (attrhash_cmp (ri->attr, attr_new))
+       {
+         bgp_unlock_node (rn);
+         bgp_attr_unintern (attr_new);
+         aspath_unintern (attr.aspath);
+         return;
+       }
+      else
+       {
+         /* The attribute is changed. */
+         SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+
+         /* Rewrite BGP route information. */
+         bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+         bgp_attr_unintern (ri->attr);
+         ri->attr = attr_new;
+         ri->uptime = time (NULL);
+
+         /* Process change. */
+         bgp_aggregate_increment (bgp, p, ri, afi, safi);
+         bgp_process (bgp, rn, afi, safi);
+         bgp_unlock_node (rn);
+         aspath_unintern (attr.aspath);
+         return;
+       }
+    }
+
+  /* Make new BGP info. */
+  new = bgp_info_new ();
+  new->type = ZEBRA_ROUTE_BGP;
+  new->sub_type = BGP_ROUTE_STATIC;
+  new->peer = bgp->peer_self;
+  SET_FLAG (new->flags, BGP_INFO_VALID);
+  new->attr = attr_new;
+  new->uptime = time (NULL);
+
+  /* Aggregate address increment. */
+  bgp_aggregate_increment (bgp, p, new, afi, safi);
+  
+  /* Register new BGP information. */
+  bgp_info_add (rn, new);
+
+  /* Process change. */
+  bgp_process (bgp, rn, afi, safi);
+
+  /* Unintern original. */
+  aspath_unintern (attr.aspath);
+}
+
+void
+bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
+                        u_char safi, struct prefix_rd *prd, u_char *tag)
+{
+  struct bgp_node *rn;
+  struct bgp_info *new;
+
+  rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
+
+  /* Make new BGP info. */
+  new = bgp_info_new ();
+  new->type = ZEBRA_ROUTE_BGP;
+  new->sub_type = BGP_ROUTE_STATIC;
+  new->peer = bgp->peer_self;
+  new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP);
+  SET_FLAG (new->flags, BGP_INFO_VALID);
+  new->uptime = time (NULL);
+  memcpy (new->tag, tag, 3);
+
+  /* Aggregate address increment. */
+  bgp_aggregate_increment (bgp, p, (struct bgp_info *) new, afi, safi);
+  
+  /* Register new BGP information. */
+  bgp_info_add (rn, (struct bgp_info *) new);
+
+  /* Process change. */
+  bgp_process (bgp, rn, afi, safi);
+}
+
+void
+bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
+                    safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+
+  rn = bgp_afi_node_get (bgp, afi, safi, p, NULL);
+
+  /* Check selected route and self inserted route. */
+  for (ri = rn->info; ri; ri = ri->next)
+    if (ri->peer == bgp->peer_self 
+       && ri->type == ZEBRA_ROUTE_BGP
+       && ri->sub_type == BGP_ROUTE_STATIC)
+      break;
+
+  /* Withdraw static BGP route from routing table. */
+  if (ri)
+    {
+      bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+      UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+      bgp_process (bgp, rn, afi, safi);
+      bgp_info_delete (rn, ri);
+      bgp_info_free (ri);
+      bgp_unlock_node (rn);
+    }
+
+  /* Unlock bgp_node_lookup. */
+  bgp_unlock_node (rn);
+}
+
+void
+bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
+                          u_char safi, struct prefix_rd *prd, u_char *tag)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+
+  rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
+
+  /* Check selected route and self inserted route. */
+  for (ri = rn->info; ri; ri = ri->next)
+    if (ri->peer == bgp->peer_self 
+       && ri->type == ZEBRA_ROUTE_BGP
+       && ri->sub_type == BGP_ROUTE_STATIC)
+      break;
+
+  /* Withdraw static BGP route from routing table. */
+  if (ri)
+    {
+      bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+      UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+      bgp_process (bgp, rn, afi, safi);
+      bgp_info_delete (rn, ri);
+      bgp_info_free (ri);
+      bgp_unlock_node (rn);
+    }
+
+  /* Unlock bgp_node_lookup. */
+  bgp_unlock_node (rn);
+}
+
+/* Configure static BGP network.  When user don't run zebra, static
+   route should be installed as valid.  */
+int
+bgp_static_set (struct vty *vty, struct bgp *bgp, char *ip_str, u_int16_t afi,
+               u_char safi, char *rmap, int backdoor)
+{
+  int ret;
+  struct prefix p;
+  struct bgp_static *bgp_static;
+  struct bgp_node *rn;
+  int need_update = 0;
+
+  /* Convert IP prefix string to struct prefix. */
+  ret = str2prefix (ip_str, &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+#ifdef HAVE_IPV6
+  if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+    {
+      vty_out (vty, "%% Malformed prefix (link-local address)%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+#endif /* HAVE_IPV6 */
+
+  apply_mask (&p);
+
+  /* Set BGP static route configuration. */
+  rn = bgp_node_get (bgp->route[afi][safi], &p);
+
+  if (rn->info)
+    {
+      /* Configuration change. */
+      bgp_static = rn->info;
+
+      /* Check previous routes are installed into BGP.  */
+      if (! bgp_static->backdoor && bgp_static->valid)
+       need_update = 1;
+
+      bgp_static->backdoor = backdoor;
+      if (rmap)
+       {
+         if (bgp_static->rmap.name)
+           free (bgp_static->rmap.name);
+         bgp_static->rmap.name = strdup (rmap);
+         bgp_static->rmap.map = route_map_lookup_by_name (rmap);
+       }
+      else
+       {
+         if (bgp_static->rmap.name)
+           free (bgp_static->rmap.name);
+         bgp_static->rmap.name = NULL;
+         bgp_static->rmap.map = NULL;
+         bgp_static->valid = 0;
+       }
+      bgp_unlock_node (rn);
+    }
+  else
+    {
+      /* New configuration. */
+      bgp_static = bgp_static_new ();
+      bgp_static->backdoor = backdoor;
+      bgp_static->valid = 0;
+      bgp_static->igpmetric = 0;
+      bgp_static->igpnexthop.s_addr = 0;
+      if (rmap)
+       {
+         if (bgp_static->rmap.name)
+           free (bgp_static->rmap.name);
+         bgp_static->rmap.name = strdup (rmap);
+         bgp_static->rmap.map = route_map_lookup_by_name (rmap);
+       }
+      rn->info = bgp_static;
+    }
+
+  /* If BGP scan is not enabled, we should install this route here.  */
+  if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+    {
+      bgp_static->valid = 1;
+
+      if (need_update)
+       bgp_static_withdraw (bgp, &p, afi, safi);
+
+      if (! bgp_static->backdoor)
+       bgp_static_update (bgp, &p, bgp_static, afi, safi);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Configure static BGP network. */
+int
+bgp_static_unset (struct vty *vty, struct bgp *bgp, char *ip_str,
+                 u_int16_t afi, u_char safi)
+{
+  int ret;
+  struct prefix p;
+  struct bgp_static *bgp_static;
+  struct bgp_node *rn;
+
+  /* Convert IP prefix string to struct prefix. */
+  ret = str2prefix (ip_str, &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+#ifdef HAVE_IPV6
+  if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+    {
+      vty_out (vty, "%% Malformed prefix (link-local address)%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+#endif /* HAVE_IPV6 */
+
+  apply_mask (&p);
+
+  rn = bgp_node_lookup (bgp->route[afi][safi], &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% Can't find specified static route configuration.%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_static = rn->info;
+
+  /* Update BGP RIB. */
+  if (! bgp_static->backdoor)
+    bgp_static_withdraw (bgp, &p, afi, safi);
+
+  /* Clear configuration. */
+  bgp_static_free (bgp_static);
+  rn->info = NULL;
+  bgp_unlock_node (rn);
+  bgp_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+/* Called from bgp_delete().  Delete all static routes from the BGP
+   instance. */
+void
+bgp_static_delete (struct bgp *bgp)
+{
+  afi_t afi;
+  safi_t safi;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp_table *table;
+  struct bgp_static *bgp_static;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
+       if (rn->info != NULL)
+         {      
+           if (safi == SAFI_MPLS_VPN)
+             {
+               table = rn->info;
+
+               for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+                 {
+                   bgp_static = rn->info;
+                   bgp_static_withdraw_vpnv4 (bgp, &rm->p,
+                                              AFI_IP, SAFI_MPLS_VPN,
+                                              (struct prefix_rd *)&rn->p,
+                                              bgp_static->tag);
+                   bgp_static_free (bgp_static);
+                   rn->info = NULL;
+                   bgp_unlock_node (rn);
+                 }
+             }
+           else
+             {
+               bgp_static = rn->info;
+               bgp_static_withdraw (bgp, &rn->p, afi, safi);
+               bgp_static_free (bgp_static);
+               rn->info = NULL;
+               bgp_unlock_node (rn);
+             }
+         }
+}
+
+int
+bgp_static_set_vpnv4 (struct vty *vty, char *ip_str, char *rd_str,
+                     char *tag_str)
+{
+  int ret;
+  struct prefix p;
+  struct prefix_rd prd;
+  struct bgp *bgp;
+  struct bgp_node *prn;
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct bgp_static *bgp_static;
+  u_char tag[3];
+
+  bgp = vty->index;
+
+  ret = str2prefix (ip_str, &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask (&p);
+
+  ret = str2prefix_rd (rd_str, &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2tag (tag_str, tag);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN],
+                       (struct prefix *)&prd);
+  if (prn->info == NULL)
+    prn->info = bgp_table_init ();
+  else
+    bgp_unlock_node (prn);
+  table = prn->info;
+
+  rn = bgp_node_get (table, &p);
+
+  if (rn->info)
+    {
+      vty_out (vty, "%% Same network configuration exists%s", VTY_NEWLINE);
+      bgp_unlock_node (rn);
+    }
+  else
+    {
+      /* New configuration. */
+      bgp_static = bgp_static_new ();
+      bgp_static->valid = 1;
+      memcpy (bgp_static->tag, tag, 3);
+      rn->info = bgp_static;
+
+      bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Configure static BGP network. */
+int
+bgp_static_unset_vpnv4 (struct vty *vty, char *ip_str, char *rd_str,
+                       char *tag_str)
+{
+  int ret;
+  struct bgp *bgp;
+  struct prefix p;
+  struct prefix_rd prd;
+  struct bgp_node *prn;
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct bgp_static *bgp_static;
+  u_char tag[3];
+
+  bgp = vty->index;
+
+  /* Convert IP prefix string to struct prefix. */
+  ret = str2prefix (ip_str, &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask (&p);
+
+  ret = str2prefix_rd (rd_str, &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2tag (tag_str, tag);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN],
+                       (struct prefix *)&prd);
+  if (prn->info == NULL)
+    prn->info = bgp_table_init ();
+  else
+    bgp_unlock_node (prn);
+  table = prn->info;
+
+  rn = bgp_node_lookup (table, &p);
+
+  if (rn)
+    {
+      bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag);
+
+      bgp_static = rn->info;
+      bgp_static_free (bgp_static);
+      rn->info = NULL;
+      bgp_unlock_node (rn);
+      bgp_unlock_node (rn);
+    }
+  else
+    vty_out (vty, "%% Can't find the route%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+\f
+DEFUN (bgp_network,
+       bgp_network_cmd,
+       "network A.B.C.D/M",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_static_set (vty, vty->index, argv[0],
+                        AFI_IP, bgp_node_safi (vty), NULL, 0);
+}
+
+DEFUN (bgp_network_route_map,
+       bgp_network_route_map_cmd,
+       "network A.B.C.D/M route-map WORD",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+{
+  return bgp_static_set (vty, vty->index, argv[0],
+                        AFI_IP, bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (bgp_network_backdoor,
+       bgp_network_backdoor_cmd,
+       "network A.B.C.D/M backdoor",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify a BGP backdoor route\n")
+{
+  return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (bgp_network_mask,
+       bgp_network_mask_cmd,
+       "network A.B.C.D mask A.B.C.D",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_set (vty, vty->index, prefix_str,
+                        AFI_IP, bgp_node_safi (vty), NULL, 0);
+}
+
+DEFUN (bgp_network_mask_route_map,
+       bgp_network_mask_route_map_cmd,
+       "network A.B.C.D mask A.B.C.D route-map WORD",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_set (vty, vty->index, prefix_str,
+                        AFI_IP, bgp_node_safi (vty), argv[2], 0);
+}
+
+DEFUN (bgp_network_mask_backdoor,
+       bgp_network_mask_backdoor_cmd,
+       "network A.B.C.D mask A.B.C.D backdoor",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Specify a BGP backdoor route\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (bgp_network_mask_natural,
+       bgp_network_mask_natural_cmd,
+       "network A.B.C.D",
+       "Specify a network to announce via BGP\n"
+       "Network number\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_set (vty, vty->index, prefix_str,
+                        AFI_IP, bgp_node_safi (vty), NULL, 0);
+}
+
+DEFUN (bgp_network_mask_natural_route_map,
+       bgp_network_mask_natural_route_map_cmd,
+       "network A.B.C.D route-map WORD",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_set (vty, vty->index, prefix_str,
+                        AFI_IP, bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (bgp_network_mask_natural_backdoor,
+       bgp_network_mask_natural_backdoor_cmd,
+       "network A.B.C.D backdoor",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Specify a BGP backdoor route\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (no_bgp_network,
+       no_bgp_network_cmd,
+       "no network A.B.C.D/M",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP, 
+                          bgp_node_safi (vty));
+}
+
+ALIAS (no_bgp_network,
+       no_bgp_network_route_map_cmd,
+       "no network A.B.C.D/M route-map WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+ALIAS (no_bgp_network,
+       no_bgp_network_backdoor_cmd,
+       "no network A.B.C.D/M backdoor",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify a BGP backdoor route\n")
+
+DEFUN (no_bgp_network_mask,
+       no_bgp_network_mask_cmd,
+       "no network A.B.C.D mask A.B.C.D",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, 
+                          bgp_node_safi (vty));
+}
+
+ALIAS (no_bgp_network_mask,
+       no_bgp_network_mask_route_map_cmd,
+       "no network A.B.C.D mask A.B.C.D route-map WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+ALIAS (no_bgp_network_mask,
+       no_bgp_network_mask_backdoor_cmd,
+       "no network A.B.C.D mask A.B.C.D backdoor",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Specify a BGP backdoor route\n")
+
+DEFUN (no_bgp_network_mask_natural,
+       no_bgp_network_mask_natural_cmd,
+       "no network A.B.C.D",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, 
+                          bgp_node_safi (vty));
+}
+
+ALIAS (no_bgp_network_mask_natural,
+       no_bgp_network_mask_natural_route_map_cmd,
+       "no network A.B.C.D route-map WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+ALIAS (no_bgp_network_mask_natural,
+       no_bgp_network_mask_natural_backdoor_cmd,
+       "no network A.B.C.D backdoor",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Specify a BGP backdoor route\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_bgp_network,
+       ipv6_bgp_network_cmd,
+       "network X:X::X:X/M",
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n")
+{
+  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (ipv6_bgp_network_route_map,
+       ipv6_bgp_network_route_map_cmd,
+       "network X:X::X:X/M route-map WORD",
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+{
+  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6,
+                        bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (no_ipv6_bgp_network,
+       no_ipv6_bgp_network_cmd,
+       "no network X:X::X:X/M",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n")
+{
+  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (no_ipv6_bgp_network,
+       no_ipv6_bgp_network_route_map_cmd,
+       "no network X:X::X:X/M route-map WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+ALIAS (ipv6_bgp_network,
+       old_ipv6_bgp_network_cmd,
+       "ipv6 bgp network X:X::X:X/M",
+       IPV6_STR
+       BGP_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+
+ALIAS (no_ipv6_bgp_network,
+       old_no_ipv6_bgp_network_cmd,
+       "no ipv6 bgp network X:X::X:X/M",
+       NO_STR
+       IPV6_STR
+       BGP_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+#endif /* HAVE_IPV6 */
+\f
+/* Aggreagete address:
+
+  advertise-map  Set condition to advertise attribute
+  as-set         Generate AS set path information
+  attribute-map  Set attributes of aggregate
+  route-map      Set parameters of aggregate
+  summary-only   Filter more specific routes from updates
+  suppress-map   Conditionally filter more specific routes from updates
+  <cr>
+ */
+struct bgp_aggregate
+{
+  /* Summary-only flag. */
+  u_char summary_only;
+
+  /* AS set generation. */
+  u_char as_set;
+
+  /* Route-map for aggregated route. */
+  struct route_map *map;
+
+  /* Suppress-count. */
+  unsigned long count;
+
+  /* SAFI configuration. */
+  safi_t safi;
+};
+
+struct bgp_aggregate *
+bgp_aggregate_new ()
+{
+  struct bgp_aggregate *new;
+  new = XMALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate));
+  memset (new, 0, sizeof (struct bgp_aggregate));
+  return new;
+}
+
+void
+bgp_aggregate_free (struct bgp_aggregate *aggregate)
+{
+  XFREE (MTYPE_BGP_AGGREGATE, aggregate);
+}     
+
+void
+bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
+                    afi_t afi, safi_t safi, struct bgp_info *del, 
+                    struct bgp_aggregate *aggregate)
+{
+  struct bgp_table *table;
+  struct bgp_node *top;
+  struct bgp_node *rn;
+  u_char origin;
+  struct aspath *aspath = NULL;
+  struct aspath *asmerge = NULL;
+  struct community *community = NULL;
+  struct community *commerge = NULL;
+  struct in_addr nexthop;
+  u_int32_t med = 0;
+  struct bgp_info *ri;
+  struct bgp_info *new;
+  int first = 1;
+  unsigned long match = 0;
+
+  /* Record adding route's nexthop and med. */
+  if (rinew)
+    {
+      nexthop = rinew->attr->nexthop;
+      med = rinew->attr->med;
+    }
+
+  /* ORIGIN attribute: If at least one route among routes that are
+     aggregated has ORIGIN with the value INCOMPLETE, then the
+     aggregated route must have the ORIGIN attribute with the value
+     INCOMPLETE. Otherwise, if at least one route among routes that
+     are aggregated has ORIGIN with the value EGP, then the aggregated
+     route must have the origin attribute with the value EGP. In all
+     other case the value of the ORIGIN attribute of the aggregated
+     route is INTERNAL. */
+  origin = BGP_ORIGIN_IGP;
+
+  table = bgp->rib[afi][safi];
+
+  top = bgp_node_get (table, p);
+  for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
+    if (rn->p.prefixlen > p->prefixlen)
+      {
+       match = 0;
+
+       for (ri = rn->info; ri; ri = ri->next)
+         {
+           if (BGP_INFO_HOLDDOWN (ri))
+             continue;
+
+           if (del && ri == del)
+             continue;
+
+           if (! rinew && first)
+             {
+               nexthop = ri->attr->nexthop;
+               med = ri->attr->med;
+               first = 0;
+             }
+
+#ifdef AGGREGATE_NEXTHOP_CHECK
+           if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop)
+               || ri->attr->med != med)
+             {
+               if (aspath)
+                 aspath_free (aspath);
+               if (community)
+                 community_free (community);
+               bgp_unlock_node (rn);
+               bgp_unlock_node (top);
+               return;
+             }
+#endif /* AGGREGATE_NEXTHOP_CHECK */
+
+           if (ri->sub_type != BGP_ROUTE_AGGREGATE)
+             {
+               if (aggregate->summary_only)
+                 {
+                   ri->suppress++;
+                   SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+                   match++;
+                 }
+
+               aggregate->count++;
+
+               if (aggregate->as_set)
+                 {
+                   if (origin < ri->attr->origin)
+                     origin = ri->attr->origin;
+
+                   if (aspath)
+                     {
+                       asmerge = aspath_aggregate (aspath, ri->attr->aspath);
+                       aspath_free (aspath);
+                       aspath = asmerge;
+                     }
+                   else
+                     aspath = aspath_dup (ri->attr->aspath);
+
+                   if (ri->attr->community)
+                     {
+                       if (community)
+                         {
+                           commerge = community_merge (community,
+                                                       ri->attr->community);
+                           community = community_uniq_sort (commerge);
+                           community_free (commerge);
+                         }
+                       else
+                         community = community_dup (ri->attr->community);
+                     }
+                 }
+             }
+         }
+       if (match)
+         bgp_process (bgp, rn, afi, safi);
+      }
+  bgp_unlock_node (top);
+
+  if (rinew)
+    {
+      aggregate->count++;
+      
+      if (aggregate->summary_only)
+       rinew->suppress++;
+
+      if (aggregate->as_set)
+       {
+         if (origin < rinew->attr->origin)
+           origin = rinew->attr->origin;
+
+         if (aspath)
+           {
+             asmerge = aspath_aggregate (aspath, rinew->attr->aspath);
+             aspath_free (aspath);
+             aspath = asmerge;
+           }
+         else
+           aspath = aspath_dup (rinew->attr->aspath);
+
+         if (rinew->attr->community)
+           {
+             if (community)
+               {
+                 commerge = community_merge (community,
+                                             rinew->attr->community);
+                 community = community_uniq_sort (commerge);
+                 community_free (commerge);
+               }
+             else
+               community = community_dup (rinew->attr->community);
+           }
+       }
+    }
+
+  if (aggregate->count > 0)
+    {
+      rn = bgp_node_get (table, p);
+      new = bgp_info_new ();
+      new->type = ZEBRA_ROUTE_BGP;
+      new->sub_type = BGP_ROUTE_AGGREGATE;
+      new->peer = bgp->peer_self;
+      SET_FLAG (new->flags, BGP_INFO_VALID);
+      new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
+      new->uptime = time (NULL);
+
+      bgp_info_add (rn, new);
+      bgp_process (bgp, rn, afi, safi);
+    }
+  else
+    {
+      if (aspath)
+       aspath_free (aspath);
+      if (community)
+       community_free (community);
+    }
+}
+
+void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t,
+                          struct bgp_aggregate *);
+
+void
+bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
+                        struct bgp_info *ri, afi_t afi, safi_t safi)
+{
+  struct bgp_node *child;
+  struct bgp_node *rn;
+  struct bgp_aggregate *aggregate;
+
+  /* MPLS-VPN aggregation is not yet supported. */
+  if (safi == SAFI_MPLS_VPN)
+    return;
+
+  if (p->prefixlen == 0)
+    return;
+
+  if (BGP_INFO_HOLDDOWN (ri))
+    return;
+
+  child = bgp_node_get (bgp->aggregate[afi][safi], p);
+
+  /* Aggregate address configuration check. */
+  for (rn = child; rn; rn = rn->parent)
+    if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen)
+      {
+       bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate);
+       bgp_aggregate_route (bgp, &rn->p, ri, safi, safi, NULL, aggregate);
+      }
+  bgp_unlock_node (child);
+}
+
+void
+bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, 
+                        struct bgp_info *del, afi_t afi, safi_t safi)
+{
+  struct bgp_node *child;
+  struct bgp_node *rn;
+  struct bgp_aggregate *aggregate;
+
+  /* MPLS-VPN aggregation is not yet supported. */
+  if (safi == SAFI_MPLS_VPN)
+    return;
+
+  if (p->prefixlen == 0)
+    return;
+
+  child = bgp_node_get (bgp->aggregate[afi][safi], p);
+
+  /* Aggregate address configuration check. */
+  for (rn = child; rn; rn = rn->parent)
+    if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen)
+      {
+       bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate);
+       bgp_aggregate_route (bgp, &rn->p, NULL, safi, safi, del, aggregate);
+      }
+  bgp_unlock_node (child);
+}
+
+void
+bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
+                  struct bgp_aggregate *aggregate)
+{
+  struct bgp_table *table;
+  struct bgp_node *top;
+  struct bgp_node *rn;
+  struct bgp_info *new;
+  struct bgp_info *ri;
+  unsigned long match;
+  u_char origin = BGP_ORIGIN_IGP;
+  struct aspath *aspath = NULL;
+  struct aspath *asmerge = NULL;
+  struct community *community = NULL;
+  struct community *commerge = NULL;
+
+  table = bgp->rib[afi][safi];
+
+  /* Sanity check. */
+  if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN)
+    return;
+  if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN)
+    return;
+    
+  /* If routes exists below this node, generate aggregate routes. */
+  top = bgp_node_get (table, p);
+  for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
+    if (rn->p.prefixlen > p->prefixlen)
+      {
+       match = 0;
+
+       for (ri = rn->info; ri; ri = ri->next)
+         {
+           if (BGP_INFO_HOLDDOWN (ri))
+             continue;
+
+           if (ri->sub_type != BGP_ROUTE_AGGREGATE)
+             {
+               /* summary-only aggregate route suppress aggregated
+                  route announcement.  */
+               if (aggregate->summary_only)
+                 {
+                   ri->suppress++;
+                   SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+                   match++;
+                 }
+               /* as-set aggregate route generate origin, as path,
+                  community aggregation.  */
+               if (aggregate->as_set)
+                 {
+                   if (origin < ri->attr->origin)
+                     origin = ri->attr->origin;
+
+                   if (aspath)
+                     {
+                       asmerge = aspath_aggregate (aspath, ri->attr->aspath);
+                       aspath_free (aspath);
+                       aspath = asmerge;
+                     }
+                   else
+                     aspath = aspath_dup (ri->attr->aspath);
+
+                   if (ri->attr->community)
+                     {
+                       if (community)
+                         {
+                           commerge = community_merge (community,
+                                                       ri->attr->community);
+                           community = community_uniq_sort (commerge);
+                           community_free (commerge);
+                         }
+                       else
+                         community = community_dup (ri->attr->community);
+                     }
+                 }
+               aggregate->count++;
+             }
+         }
+       
+       /* If this node is suppressed, process the change. */
+       if (match)
+         bgp_process (bgp, rn, afi, safi);
+      }
+  bgp_unlock_node (top);
+
+  /* Add aggregate route to BGP table. */
+  if (aggregate->count)
+    {
+      rn = bgp_node_get (table, p);
+
+      new = bgp_info_new ();
+      new->type = ZEBRA_ROUTE_BGP;
+      new->sub_type = BGP_ROUTE_AGGREGATE;
+      new->peer = bgp->peer_self;
+      SET_FLAG (new->flags, BGP_INFO_VALID);
+      new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
+      new->uptime = time (NULL);
+
+      bgp_info_add (rn, new);
+
+      /* Process change. */
+      bgp_process (bgp, rn, afi, safi);
+    }
+}
+
+void
+bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, 
+                     safi_t safi, struct bgp_aggregate *aggregate)
+{
+  struct bgp_table *table;
+  struct bgp_node *top;
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+  unsigned long match;
+
+  table = bgp->rib[afi][safi];
+
+  if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN)
+    return;
+  if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN)
+    return;
+
+  /* If routes exists below this node, generate aggregate routes. */
+  top = bgp_node_get (table, p);
+  for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
+    if (rn->p.prefixlen > p->prefixlen)
+      {
+       match = 0;
+
+       for (ri = rn->info; ri; ri = ri->next)
+         {
+           if (BGP_INFO_HOLDDOWN (ri))
+             continue;
+
+           if (ri->sub_type != BGP_ROUTE_AGGREGATE)
+             {
+               if (aggregate->summary_only)
+                 {
+                   ri->suppress--;
+
+                   if (ri->suppress == 0)
+                     {
+                       SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+                       match++;
+                     }
+                 }
+               aggregate->count--;
+             }
+         }
+
+       /* If this node is suppressed, process the change. */
+       if (match)
+         bgp_process (bgp, rn, afi, safi);
+      }
+  bgp_unlock_node (top);
+
+  /* Delete aggregate route from BGP table. */
+  rn = bgp_node_get (table, p);
+
+  for (ri = rn->info; ri; ri = ri->next)
+    if (ri->peer == bgp->peer_self 
+       && ri->type == ZEBRA_ROUTE_BGP
+       && ri->sub_type == BGP_ROUTE_AGGREGATE)
+      break;
+
+  /* Withdraw static BGP route from routing table. */
+  if (ri)
+    {
+      UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+      bgp_process (bgp, rn, afi, safi);
+      bgp_info_delete (rn, ri);
+      bgp_info_free (ri);
+      bgp_unlock_node (rn);
+    }
+
+  /* Unlock bgp_node_lookup. */
+  bgp_unlock_node (rn);
+}
+
+/* Aggregate route attribute. */
+#define AGGREGATE_SUMMARY_ONLY 1
+#define AGGREGATE_AS_SET       1
+
+int
+bgp_aggregate_set (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi,
+                  u_char summary_only, u_char as_set)
+{
+  int ret;
+  struct prefix p;
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct bgp_aggregate *aggregate;
+
+  /* Convert string to prefix structure. */
+  ret = str2prefix (prefix_str, &p);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask (&p);
+
+  /* Get BGP structure. */
+  bgp = vty->index;
+
+  /* Old configuration check. */
+  rn = bgp_node_get (bgp->aggregate[afi][safi], &p);
+
+  if (rn->info)
+    {
+      vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE);
+      bgp_unlock_node (rn);
+      return CMD_WARNING;
+    }
+
+  /* Make aggregate address structure. */
+  aggregate = bgp_aggregate_new ();
+  aggregate->summary_only = summary_only;
+  aggregate->as_set = as_set;
+  aggregate->safi = safi;
+  rn->info = aggregate;
+
+  /* Aggregate address insert into BGP routing table. */
+  if (safi & SAFI_UNICAST)
+    bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate);
+  if (safi & SAFI_MULTICAST)
+    bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate);
+
+  return CMD_SUCCESS;
+}
+
+int
+bgp_aggregate_unset (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi)
+{
+  int ret;
+  struct prefix p;
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct bgp_aggregate *aggregate;
+
+  /* Convert string to prefix structure. */
+  ret = str2prefix (prefix_str, &p);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask (&p);
+
+  /* Get BGP structure. */
+  bgp = vty->index;
+
+  /* Old configuration check. */
+  rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% There is no aggregate-address configuration.%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  aggregate = rn->info;
+  if (aggregate->safi & SAFI_UNICAST)
+    bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate);
+  if (aggregate->safi & SAFI_MULTICAST)
+    bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate);
+
+  /* Unlock aggregate address configuration. */
+  rn->info = NULL;
+  bgp_aggregate_free (aggregate);
+  bgp_unlock_node (rn);
+  bgp_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (aggregate_address,
+       aggregate_address_cmd,
+       "aggregate-address A.B.C.D/M",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+{
+  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), 0, 0);
+}
+
+DEFUN (aggregate_address_mask,
+       aggregate_address_mask_cmd,
+       "aggregate-address A.B.C.D A.B.C.D",
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+                           0, 0);
+}
+
+DEFUN (aggregate_address_summary_only,
+       aggregate_address_summary_only_cmd,
+       "aggregate-address A.B.C.D/M summary-only",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+{
+  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty),
+                           AGGREGATE_SUMMARY_ONLY, 0);
+}
+
+DEFUN (aggregate_address_mask_summary_only,
+       aggregate_address_mask_summary_only_cmd,
+       "aggregate-address A.B.C.D A.B.C.D summary-only",
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+                           AGGREGATE_SUMMARY_ONLY, 0);
+}
+
+DEFUN (aggregate_address_as_set,
+       aggregate_address_as_set_cmd,
+       "aggregate-address A.B.C.D/M as-set",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n")
+{
+  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty),
+                           0, AGGREGATE_AS_SET);
+}
+
+DEFUN (aggregate_address_mask_as_set,
+       aggregate_address_mask_as_set_cmd,
+       "aggregate-address A.B.C.D A.B.C.D as-set",
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+                           0, AGGREGATE_AS_SET);
+}
+
+
+DEFUN (aggregate_address_as_set_summary,
+       aggregate_address_as_set_summary_cmd,
+       "aggregate-address A.B.C.D/M as-set summary-only",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+{
+  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty),
+                           AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET);
+}
+
+ALIAS (aggregate_address_as_set_summary,
+       aggregate_address_summary_as_set_cmd,
+       "aggregate-address A.B.C.D/M summary-only as-set",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFUN (aggregate_address_mask_as_set_summary,
+       aggregate_address_mask_as_set_summary_cmd,
+       "aggregate-address A.B.C.D A.B.C.D as-set summary-only",
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty),
+                           AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET);
+}
+
+ALIAS (aggregate_address_mask_as_set_summary,
+       aggregate_address_mask_summary_as_set_cmd,
+       "aggregate-address A.B.C.D A.B.C.D summary-only as-set",
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFUN (no_aggregate_address,
+       no_aggregate_address_cmd,
+       "no aggregate-address A.B.C.D/M",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+{
+  return bgp_aggregate_unset (vty, argv[0], AFI_IP, bgp_node_safi (vty));
+}
+
+ALIAS (no_aggregate_address,
+       no_aggregate_address_summary_only_cmd,
+       "no aggregate-address A.B.C.D/M summary-only",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address,
+       no_aggregate_address_as_set_cmd,
+       "no aggregate-address A.B.C.D/M as-set",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n")
+
+ALIAS (no_aggregate_address,
+       no_aggregate_address_as_set_summary_cmd,
+       "no aggregate-address A.B.C.D/M as-set summary-only",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address,
+       no_aggregate_address_summary_as_set_cmd,
+       "no aggregate-address A.B.C.D/M summary-only as-set",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFUN (no_aggregate_address_mask,
+       no_aggregate_address_mask_cmd,
+       "no aggregate-address A.B.C.D A.B.C.D",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_aggregate_unset (vty, prefix_str, AFI_IP, bgp_node_safi (vty));
+}
+
+ALIAS (no_aggregate_address_mask,
+       no_aggregate_address_mask_summary_only_cmd,
+       "no aggregate-address A.B.C.D A.B.C.D summary-only",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address_mask,
+       no_aggregate_address_mask_as_set_cmd,
+       "no aggregate-address A.B.C.D A.B.C.D as-set",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n")
+
+ALIAS (no_aggregate_address_mask,
+       no_aggregate_address_mask_as_set_summary_cmd,
+       "no aggregate-address A.B.C.D A.B.C.D as-set summary-only",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+
+ALIAS (no_aggregate_address_mask,
+       no_aggregate_address_mask_summary_as_set_cmd,
+       "no aggregate-address A.B.C.D A.B.C.D summary-only as-set",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_aggregate_address,
+       ipv6_aggregate_address_cmd,
+       "aggregate-address X:X::X:X/M",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+{
+  return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0, 0);
+}
+
+DEFUN (ipv6_aggregate_address_summary_only,
+       ipv6_aggregate_address_summary_only_cmd,
+       "aggregate-address X:X::X:X/M summary-only",
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+{
+  return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 
+                           AGGREGATE_SUMMARY_ONLY, 0);
+}
+
+DEFUN (no_ipv6_aggregate_address,
+       no_ipv6_aggregate_address_cmd,
+       "no aggregate-address X:X::X:X/M",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+{
+  return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+DEFUN (no_ipv6_aggregate_address_summary_only,
+       no_ipv6_aggregate_address_summary_only_cmd,
+       "no aggregate-address X:X::X:X/M summary-only",
+       NO_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+{
+  return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (ipv6_aggregate_address,
+       old_ipv6_aggregate_address_cmd,
+       "ipv6 bgp aggregate-address X:X::X:X/M",
+       IPV6_STR
+       BGP_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+ALIAS (ipv6_aggregate_address_summary_only,
+       old_ipv6_aggregate_address_summary_only_cmd,
+       "ipv6 bgp aggregate-address X:X::X:X/M summary-only",
+       IPV6_STR
+       BGP_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+ALIAS (no_ipv6_aggregate_address,
+       old_no_ipv6_aggregate_address_cmd,
+       "no ipv6 bgp aggregate-address X:X::X:X/M",
+       NO_STR
+       IPV6_STR
+       BGP_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+ALIAS (no_ipv6_aggregate_address_summary_only,
+       old_no_ipv6_aggregate_address_summary_only_cmd,
+       "no ipv6 bgp aggregate-address X:X::X:X/M summary-only",
+       NO_STR
+       IPV6_STR
+       BGP_STR
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+#endif /* HAVE_IPV6 */
+\f
+/* Redistribute route treatment. */
+void
+bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
+                     u_int32_t metric, u_char type)
+{
+  struct bgp *bgp;
+  struct listnode *nn;
+  struct bgp_info *new;
+  struct bgp_info *bi;
+  struct bgp_info info;
+  struct bgp_node *bn;
+  struct attr attr;
+  struct attr attr_new;
+  struct attr *new_attr;
+  afi_t afi;
+  int ret;
+
+  /* Make default attribute. */
+  bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE);
+  if (nexthop)
+    attr.nexthop = *nexthop;
+
+  attr.med = metric;
+  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      afi = family2afi (p->family);
+
+      if (bgp->redist[afi][type])
+       {
+         /* Copy attribute for modification. */
+         attr_new = attr;
+
+         if (bgp->redist_metric_flag[afi][type])
+           attr_new.med = bgp->redist_metric[afi][type];
+
+         /* Apply route-map. */
+         if (bgp->rmap[afi][type].map)
+           {
+             info.peer = bgp->peer_self;
+             info.attr = &attr_new;
+
+             ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP,
+                                    &info);
+             if (ret == RMAP_DENYMATCH)
+               {
+                 /* Free uninterned attribute. */
+                 bgp_attr_flush (&attr_new);
+
+                 /* Unintern original. */
+                 aspath_unintern (attr.aspath);
+                 bgp_redistribute_delete (p, type);
+                 return;
+               }
+           }
+
+         bn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL);
+         new_attr = bgp_attr_intern (&attr_new);
+         for (bi = bn->info; bi; bi = bi->next)
+           if (bi->peer == bgp->peer_self
+               && bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+             break;
+         if (bi)
+           {
+             if (attrhash_cmp (bi->attr, new_attr))
+               {
+                 bgp_attr_unintern (new_attr);
+                 aspath_unintern (attr.aspath);
+                 bgp_unlock_node (bn);
+                 return;
+               }
+             else
+               {
+                 /* The attribute is changed. */
+                 SET_FLAG (bi->flags, BGP_INFO_ATTR_CHANGED);
+                 /* Rewrite BGP route information. */
+                 bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
+                 bgp_attr_unintern (bi->attr);
+                 bi->attr = new_attr;
+                 bi->uptime = time (NULL);
+                 /* Process change. */
+                 bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST);
+                 bgp_process (bgp, bn, afi, SAFI_UNICAST);
+                 bgp_unlock_node (bn);
+                 aspath_unintern (attr.aspath);
+                 return;
+               } 
+           }
+
+         new = bgp_info_new ();
+         new->type = type;
+         new->sub_type = BGP_ROUTE_REDISTRIBUTE;
+         new->peer = bgp->peer_self;
+         SET_FLAG (new->flags, BGP_INFO_VALID);
+         new->attr = new_attr;
+         new->uptime = time (NULL);
+
+         bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST);
+         bgp_info_add (bn, new);
+         bgp_process (bgp, bn, afi, SAFI_UNICAST);
+       }
+    }
+
+  /* Unintern original. */
+  aspath_unintern (attr.aspath);
+}
+
+void
+bgp_redistribute_delete (struct prefix *p, u_char type)
+{
+  struct bgp *bgp;
+  struct listnode *nn;
+  afi_t afi;
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      afi = family2afi (p->family);
+
+      if (bgp->redist[afi][type])
+       {
+         rn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL);
+
+         for (ri = rn->info; ri; ri = ri->next)
+           if (ri->peer == bgp->peer_self
+               && ri->type == type)
+             break;
+
+         if (ri)
+           {
+             bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST);
+             UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+             bgp_process (bgp, rn, afi, SAFI_UNICAST);
+             bgp_info_delete (rn, ri);
+             bgp_info_free (ri);
+             bgp_unlock_node (rn);
+           }
+         bgp_unlock_node (rn);
+       }
+    }
+}
+
+/* Withdraw specified route type's route. */
+void
+bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+  struct bgp_table *table;
+
+  table = bgp->rib[afi][SAFI_UNICAST];
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    {
+      for (ri = rn->info; ri; ri = ri->next)
+       if (ri->peer == bgp->peer_self
+           && ri->type == type)
+         break;
+
+      if (ri)
+       {
+         bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST);
+         UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+         bgp_process (bgp, rn, afi, SAFI_UNICAST);
+         bgp_info_delete (rn, ri);
+         bgp_info_free (ri);
+         bgp_unlock_node (rn);
+       }
+    }
+}
+\f
+/* Static function to display route. */
+void
+route_vty_out_route (struct prefix *p, struct vty *vty)
+{
+  int len;
+  u_int32_t destination; 
+  char buf[BUFSIZ];
+
+  if (p->family == AF_INET)
+    {
+      len = vty_out (vty, "%s", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ));
+      destination = ntohl (p->u.prefix4.s_addr);
+
+      if ((IN_CLASSC (destination) && p->prefixlen == 24)
+         || (IN_CLASSB (destination) && p->prefixlen == 16)
+         || (IN_CLASSA (destination) && p->prefixlen == 8)
+         || p->u.prefix4.s_addr == 0)
+       {
+         /* When mask is natural, mask is not displayed. */
+       }
+      else
+       len += vty_out (vty, "/%d", p->prefixlen);
+    }
+  else
+    len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                  p->prefixlen);
+
+  len = 17 - len;
+  if (len < 1)
+    vty_out (vty, "%s%*s", VTY_NEWLINE, 20, " ");
+  else
+    vty_out (vty, "%*s", len, " ");
+}
+
+/* Calculate line number of output data. */
+int
+vty_calc_line (struct vty *vty, unsigned long length)
+{
+  return vty->width ? (((vty->obuf->length - length) / vty->width) + 1) : 1;
+}
+
+enum bgp_display_type
+{
+  normal_list,
+};
+
+/* called from terminal list command */
+int
+route_vty_out (struct vty *vty, struct prefix *p,
+              struct bgp_info *binfo, int display, safi_t safi)
+{
+  struct attr *attr;
+  unsigned long length = 0;
+
+  length = vty->obuf->length;
+
+  /* Route status display. */
+  if (binfo->suppress)
+    vty_out (vty, "s");
+  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "*");
+  else
+    vty_out (vty, " ");
+
+  /* Selected */
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "h");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+    vty_out (vty, "d");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+    vty_out (vty, ">");
+  else
+    vty_out (vty, " ");
+
+  /* Internal route. */
+    if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as))
+      vty_out (vty, "i");
+    else
+      vty_out (vty, " ");
+  
+  /* print prefix and mask */
+  if (! display)
+    route_vty_out_route (p, vty);
+  else
+    vty_out (vty, "%*s", 17, " ");
+
+  /* Print attribute */
+  attr = binfo->attr;
+  if (attr) 
+    {
+      if (p->family == AF_INET)
+       {
+         if (safi == SAFI_MPLS_VPN)
+           vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in));
+         else
+           vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
+       }
+#ifdef HAVE_IPV6      
+      else if (p->family == AF_INET6)
+       {
+         int len;
+         char buf[BUFSIZ];
+
+         len = vty_out (vty, "%s", 
+                        inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ));
+         len = 16 - len;
+         if (len < 1)
+           vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " ");
+         else
+           vty_out (vty, "%*s", len, " ");
+       }
+#endif /* HAVE_IPV6 */
+
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+       vty_out (vty, "%10d", attr->med);
+      else
+       vty_out (vty, "          ");
+
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
+       vty_out (vty, "%7d", attr->local_pref);
+      else
+       vty_out (vty, "       ");
+
+      vty_out (vty, "%7u ",attr->weight);
+    
+    /* Print aspath */
+    if (attr->aspath)
+      aspath_print_vty (vty, attr->aspath);
+
+    /* Print origin */
+    if (strlen (attr->aspath->str) == 0)
+      vty_out (vty, "%s", bgp_origin_str[attr->origin]);
+    else
+      vty_out (vty, " %s", bgp_origin_str[attr->origin]);
+  }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return vty_calc_line (vty, length);
+}  
+
+/* called from terminal list command */
+void
+route_vty_out_tmp (struct vty *vty, struct prefix *p,
+                  struct attr *attr, safi_t safi)
+{
+  /* Route status display. */
+  vty_out (vty, "*");
+  vty_out (vty, ">");
+  vty_out (vty, " ");
+
+  /* print prefix and mask */
+  route_vty_out_route (p, vty);
+
+  /* Print attribute */
+  if (attr) 
+    {
+      if (p->family == AF_INET)
+       {
+         if (safi == SAFI_MPLS_VPN)
+           vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in));
+         else
+           vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
+       }
+#ifdef HAVE_IPV6
+      else if (p->family == AF_INET6)
+        {
+          int len;
+          char buf[BUFSIZ];
+
+          len = vty_out (vty, "%s",
+                         inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ));
+          len = 16 - len;
+          if (len < 1)
+            vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " ");
+          else
+            vty_out (vty, "%*s", len, " ");
+        }
+#endif /* HAVE_IPV6 */
+
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+       vty_out (vty, "%10d", attr->med);
+      else
+       vty_out (vty, "          ");
+
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
+       vty_out (vty, "%7d", attr->local_pref);
+      else
+       vty_out (vty, "       ");
+
+      vty_out (vty, "%7d ",attr->weight);
+    
+    /* Print aspath */
+    if (attr->aspath)
+      aspath_print_vty (vty, attr->aspath);
+
+    /* Print origin */
+    if (strlen (attr->aspath->str) == 0)
+      vty_out (vty, "%s", bgp_origin_str[attr->origin]);
+    else
+      vty_out (vty, " %s", bgp_origin_str[attr->origin]);
+  }
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}  
+
+int
+route_vty_out_tag (struct vty *vty, struct prefix *p,
+                  struct bgp_info *binfo, int display, safi_t safi)
+{
+  struct attr *attr;
+  unsigned long length = 0;
+  u_int32_t label = 0;
+
+  length = vty->obuf->length;
+
+  /* Route status display. */
+  if (binfo->suppress)
+    vty_out (vty, "s");
+  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "*");
+  else
+    vty_out (vty, " ");
+
+  /* Selected */
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "h");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+    vty_out (vty, "d");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+    vty_out (vty, ">");
+  else
+    vty_out (vty, " ");
+
+  /* Internal route. */
+    if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as))
+      vty_out (vty, "i");
+    else
+      vty_out (vty, " ");
+
+  /* print prefix and mask */
+  if (! display)
+    route_vty_out_route (p, vty);
+  else
+    vty_out (vty, "%*s", 17, " ");
+
+  /* Print attribute */
+  attr = binfo->attr;
+  if (attr) 
+    {
+      if (p->family == AF_INET)
+       {
+         if (safi == SAFI_MPLS_VPN)
+           vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in));
+         else
+           vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
+       }
+#ifdef HAVE_IPV6      
+      else if (p->family == AF_INET6)
+       {
+         char buf[BUFSIZ];
+         char buf1[BUFSIZ];
+         if (attr->mp_nexthop_len == 16)
+           vty_out (vty, "%s", 
+                    inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ));
+         else if (attr->mp_nexthop_len == 32)
+           vty_out (vty, "%s(%s)",
+                    inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ),
+                    inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf1, BUFSIZ));
+         
+       }
+#endif /* HAVE_IPV6 */
+    }
+
+  label = decode_label (binfo->tag);
+
+  vty_out (vty, "notag/%d", label);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return vty_calc_line (vty, length);
+}  
+
+/* dampening route */
+int
+damp_route_vty_out (struct vty *vty, struct prefix *p,
+                   struct bgp_info *binfo, int display, safi_t safi)
+{
+  struct attr *attr;
+  unsigned long length = 0;
+  int len;
+
+  length = vty->obuf->length;
+
+  /* Route status display. */
+  if (binfo->suppress)
+    vty_out (vty, "s");
+  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "*");
+  else
+    vty_out (vty, " ");
+
+  /* Selected */
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "h");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+    vty_out (vty, "d");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+    vty_out (vty, ">");
+  else
+    vty_out (vty, " ");
+
+  vty_out (vty, " ");
+
+  /* print prefix and mask */
+  if (! display)
+    route_vty_out_route (p, vty);
+  else
+    vty_out (vty, "%*s", 17, " ");
+
+  len = vty_out (vty, "%s", binfo->peer->host);
+  len = 17 - len;
+  if (len < 1)
+    vty_out (vty, "%s%*s", VTY_NEWLINE, 34, " ");
+  else
+    vty_out (vty, "%*s", len, " ");
+
+  vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo));
+
+  /* Print attribute */
+  attr = binfo->attr;
+  if (attr)
+    {
+      /* Print aspath */
+      if (attr->aspath)
+       aspath_print_vty (vty, attr->aspath);
+
+      /* Print origin */
+      if (strlen (attr->aspath->str) == 0)
+       vty_out (vty, "%s", bgp_origin_str[attr->origin]);
+      else
+       vty_out (vty, " %s", bgp_origin_str[attr->origin]);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return vty_calc_line (vty, length);
+}
+
+#define BGP_UPTIME_LEN 25
+
+/* flap route */
+int
+flap_route_vty_out (struct vty *vty, struct prefix *p,
+                   struct bgp_info *binfo, int display, safi_t safi)
+{
+  struct attr *attr;
+  struct bgp_damp_info *bdi;
+  unsigned long length = 0;
+  char timebuf[BGP_UPTIME_LEN];
+  int len;
+
+  length = vty->obuf->length;
+  bdi = binfo->damp_info;
+
+  /* Route status display. */
+  if (binfo->suppress)
+    vty_out (vty, "s");
+  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "*");
+  else
+    vty_out (vty, " ");
+
+  /* Selected */
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "h");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+    vty_out (vty, "d");
+  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+    vty_out (vty, ">");
+  else
+    vty_out (vty, " ");
+
+  vty_out (vty, " ");
+
+  /* print prefix and mask */
+  if (! display)
+    route_vty_out_route (p, vty);
+  else
+    vty_out (vty, "%*s", 17, " ");
+
+  len = vty_out (vty, "%s", binfo->peer->host);
+  len = 16 - len;
+  if (len < 1)
+    vty_out (vty, "%s%*s", VTY_NEWLINE, 33, " ");
+  else
+    vty_out (vty, "%*s", len, " ");
+
+  len = vty_out (vty, "%d", bdi->flap);
+  len = 5 - len;
+  if (len < 1)
+    vty_out (vty, " ");
+  else
+    vty_out (vty, "%*s ", len, " ");
+    
+  vty_out (vty, "%s ", peer_uptime (bdi->start_time,
+          timebuf, BGP_UPTIME_LEN));
+
+  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
+      && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+    vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo));
+  else
+    vty_out (vty, "%*s ", 8, " ");
+
+  /* Print attribute */
+  attr = binfo->attr;
+  if (attr)
+    {
+      /* Print aspath */
+      if (attr->aspath)
+       aspath_print_vty (vty, attr->aspath);
+
+      /* Print origin */
+      if (strlen (attr->aspath->str) == 0)
+       vty_out (vty, "%s", bgp_origin_str[attr->origin]);
+      else
+       vty_out (vty, " %s", bgp_origin_str[attr->origin]);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return vty_calc_line (vty, length);
+}
+
+void
+route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, 
+                     struct bgp_info *binfo, afi_t afi, safi_t safi)
+{
+  char buf[INET6_ADDRSTRLEN];
+  char buf1[BUFSIZ];
+  struct attr *attr;
+  int sockunion_vty_out (struct vty *, union sockunion *);
+       
+  attr = binfo->attr;
+
+  if (attr)
+    {
+      /* Line1 display AS-path, Aggregator */
+      if (attr->aspath)
+       {
+         vty_out (vty, "  ");
+         if (attr->aspath->length == 0)
+           vty_out (vty, "Local");
+         else
+           aspath_print_vty (vty, attr->aspath);
+       }
+
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)
+         || CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)
+         || CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
+         || CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)
+         || CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+       {
+         vty_out (vty, ",");
+
+         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))
+           vty_out (vty, " (aggregated by %d %s)", attr->aggregator_as,
+                    inet_ntoa (attr->aggregator_addr));
+         if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+           vty_out (vty, " (Received from a RR-client)");
+         if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
+           vty_out (vty, " (Received from a RS-client)");
+         if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+           vty_out (vty, " (history entry)");
+         else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+           vty_out (vty, " (suppressed due to dampening)");
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+         
+      /* Line2 display Next-hop, Neighbor, Router-id */
+      if (p->family == AF_INET)
+       {
+         vty_out (vty, "    %s", safi == SAFI_MPLS_VPN ?
+                  inet_ntoa (attr->mp_nexthop_global_in) :
+                  inet_ntoa (attr->nexthop));
+       }
+#ifdef HAVE_IPV6
+      else
+       {
+         vty_out (vty, "    %s",
+                  inet_ntop (AF_INET6, &attr->mp_nexthop_global,
+                             buf, INET6_ADDRSTRLEN));
+       }
+#endif /* HAVE_IPV6 */
+
+      if (binfo->peer == bgp->peer_self)
+       {
+         vty_out (vty, " from %s ", 
+                  p->family == AF_INET ? "0.0.0.0" : "::");
+         vty_out (vty, "(%s)", inet_ntoa(bgp->router_id));
+       }
+      else
+       {
+         if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
+           vty_out (vty, " (inaccessible)"); 
+         else if (binfo->igpmetric)
+           vty_out (vty, " (metric %d)", binfo->igpmetric);
+         vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
+         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+           vty_out (vty, " (%s)", inet_ntoa (attr->originator_id));
+         else
+           vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ));
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+#ifdef HAVE_IPV6
+      /* display nexthop local */
+      if (attr->mp_nexthop_len == 32)
+       {
+         vty_out (vty, "    (%s)%s",
+                  inet_ntop (AF_INET6, &attr->mp_nexthop_local,
+                             buf, INET6_ADDRSTRLEN),
+                  VTY_NEWLINE);
+       }
+#endif /* HAVE_IPV6 */
+
+      /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */
+      vty_out (vty, "      Origin %s", bgp_origin_long_str[attr->origin]);
+         
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
+       vty_out (vty, ", metric %d", attr->med);
+         
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
+       vty_out (vty, ", localpref %d", attr->local_pref);
+      else
+       vty_out (vty, ", localpref %d", bgp->default_local_pref);
+
+      if (attr->weight != 0)
+       vty_out (vty, ", weight %d", attr->weight);
+       
+      if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+       vty_out (vty, ", valid");
+
+      if (binfo->peer != bgp->peer_self)
+       {
+         if (binfo->peer->as == binfo->peer->local_as)
+           vty_out (vty, ", internal");
+         else 
+           vty_out (vty, ", %s", 
+                    (bgp_confederation_peers_check(bgp, binfo->peer->as) ? "confed-external" : "external"));
+       }
+      else if (binfo->sub_type == BGP_ROUTE_AGGREGATE)
+       vty_out (vty, ", aggregated, local");
+      else if (binfo->type != ZEBRA_ROUTE_BGP)
+       vty_out (vty, ", sourced");
+      else
+       vty_out (vty, ", sourced, local");
+
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
+       vty_out (vty, ", atomic-aggregate");
+         
+      if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+       vty_out (vty, ", best");
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+         
+      /* Line 4 display Community */
+      if (attr->community)
+       vty_out (vty, "      Community: %s%s", attr->community->str,
+                VTY_NEWLINE);
+         
+      /* Line 5 display Extended-community */
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))
+       vty_out (vty, "      Extended Community: %s%s", attr->ecommunity->str,
+                VTY_NEWLINE);
+         
+      /* Line 6 display Originator, Cluster-id */
+      if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
+         (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
+       {
+         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+           vty_out (vty, "      Originator: %s", inet_ntoa (attr->originator_id));
+
+         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
+           {
+             int i;
+             vty_out (vty, ", Cluster list: ");
+             for (i = 0; i < attr->cluster->length / 4; i++)
+               vty_out (vty, "%s ", inet_ntoa (attr->cluster->list[i]));
+           }
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+
+      if (binfo->damp_info)
+       bgp_damp_info_vty (vty, binfo);
+
+      /* Line 7 display Uptime */
+      vty_out (vty, "      Last update: %s", ctime (&binfo->uptime));
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}  
+\f
+#define BGP_SHOW_HEADER "   Network          Next Hop            Metric LocPrf Weight Path%s"
+#define BGP_SHOW_DAMP_HEADER "   Network          From             Reuse    Path%s"
+#define BGP_SHOW_FLAP_HEADER "   Network          From            Flaps Duration Reuse    Path%s"
+
+enum bgp_show_type
+{
+  bgp_show_type_normal,
+  bgp_show_type_regexp,
+  bgp_show_type_prefix_list,
+  bgp_show_type_filter_list,
+  bgp_show_type_route_map,
+  bgp_show_type_neighbor,
+  bgp_show_type_cidr_only,
+  bgp_show_type_prefix_longer,
+  bgp_show_type_community_all,
+  bgp_show_type_community,
+  bgp_show_type_community_exact,
+  bgp_show_type_community_list,
+  bgp_show_type_community_list_exact,
+  bgp_show_type_flap_statistics,
+  bgp_show_type_flap_address,
+  bgp_show_type_flap_prefix,
+  bgp_show_type_flap_cidr_only,
+  bgp_show_type_flap_regexp,
+  bgp_show_type_flap_filter_list,
+  bgp_show_type_flap_prefix_list,
+  bgp_show_type_flap_prefix_longer,
+  bgp_show_type_flap_route_map,
+  bgp_show_type_flap_neighbor,
+  bgp_show_type_dampend_paths,
+  bgp_show_type_damp_neighbor
+};
+
+int
+bgp_show_callback (struct vty *vty, int unlock)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+  int count;
+  int limit;
+  int display;
+
+  rn = vty->output_rn;
+  count = 0;
+  limit = ((vty->lines == 0) 
+          ? 10 : (vty->lines > 0 
+                  ? vty->lines : vty->height - 2));
+  limit = limit > 0 ? limit : 2;
+
+  /* Quit of display. */
+  if (unlock && rn)
+    {
+      bgp_unlock_node (rn);
+      if (vty->output_clean)
+       (*vty->output_clean) (vty);
+      vty->output_rn = NULL;
+      vty->output_func = NULL;
+      vty->output_clean = NULL;
+      vty->output_arg = NULL;
+      return 0;
+    }
+
+  for (; rn; rn = bgp_route_next (rn)) 
+    if (rn->info != NULL)
+      {
+       display = 0;
+
+       for (ri = rn->info; ri; ri = ri->next)
+         {
+           if (vty->output_type == bgp_show_type_flap_statistics
+               || vty->output_type == bgp_show_type_flap_address
+               || vty->output_type == bgp_show_type_flap_prefix
+               || vty->output_type == bgp_show_type_flap_cidr_only
+               || vty->output_type == bgp_show_type_flap_regexp
+               || vty->output_type == bgp_show_type_flap_filter_list
+               || vty->output_type == bgp_show_type_flap_prefix_list
+               || vty->output_type == bgp_show_type_flap_prefix_longer
+               || vty->output_type == bgp_show_type_flap_route_map
+               || vty->output_type == bgp_show_type_flap_neighbor
+               || vty->output_type == bgp_show_type_dampend_paths
+               || vty->output_type == bgp_show_type_damp_neighbor)
+             {
+               if (! ri->damp_info)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_regexp
+               || vty->output_type == bgp_show_type_flap_regexp)
+             {
+               regex_t *regex = vty->output_arg;
+
+               if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_prefix_list
+               || vty->output_type == bgp_show_type_flap_prefix_list)
+             {
+               struct prefix_list *plist = vty->output_arg;
+
+               if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_filter_list
+               || vty->output_type == bgp_show_type_flap_filter_list)
+             {
+               struct as_list *as_list = vty->output_arg;
+
+               if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_route_map
+               || vty->output_type == bgp_show_type_flap_route_map)
+             {
+               struct route_map *rmap = vty->output_arg;
+               struct bgp_info binfo;
+               struct attr dummy_attr; 
+               int ret;
+
+               dummy_attr = *ri->attr;
+               binfo.peer = ri->peer;
+               binfo.attr = &dummy_attr;
+
+               ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo);
+
+               if (ret == RMAP_DENYMATCH)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_neighbor
+               || vty->output_type == bgp_show_type_flap_neighbor
+               || vty->output_type == bgp_show_type_damp_neighbor)
+             {
+               union sockunion *su = vty->output_arg;
+
+               if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_cidr_only
+               || vty->output_type == bgp_show_type_flap_cidr_only)
+             {
+               u_int32_t destination;
+
+               destination = ntohl (rn->p.u.prefix4.s_addr);
+               if (IN_CLASSC (destination) && rn->p.prefixlen == 24)
+                 continue;
+               if (IN_CLASSB (destination) && rn->p.prefixlen == 16)
+                 continue;
+               if (IN_CLASSA (destination) && rn->p.prefixlen == 8)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_prefix_longer
+               || vty->output_type == bgp_show_type_flap_prefix_longer)
+             {
+               struct prefix *p = vty->output_arg;
+
+               if (! prefix_match (p, &rn->p))
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_community_all)
+             {
+               if (! ri->attr->community)
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_community)
+             {
+               struct community *com = vty->output_arg;
+
+               if (! ri->attr->community ||
+                   ! community_match (ri->attr->community, com))
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_community_exact)
+             {
+               struct community *com = vty->output_arg;
+
+               if (! ri->attr->community ||
+                   ! community_cmp (ri->attr->community, com))
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_community_list)
+             {
+               struct community_list *list = vty->output_arg;
+
+               if (! community_list_match (ri->attr->community, list))
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_community_list_exact)
+             {
+               struct community_list *list = vty->output_arg;
+
+               if (! community_list_exact_match (ri->attr->community, list))
+                 continue;
+             }
+           if (vty->output_type == bgp_show_type_flap_address
+               || vty->output_type == bgp_show_type_flap_prefix)
+             {
+               struct prefix *p = vty->output_arg;
+
+               if (! prefix_match (&rn->p, p))
+                 continue;
+
+               if (vty->output_type == bgp_show_type_flap_prefix)
+                 if (p->prefixlen != rn->p.prefixlen)
+                   continue;
+             }
+           if (vty->output_type == bgp_show_type_dampend_paths
+               || vty->output_type == bgp_show_type_damp_neighbor)
+             {
+               if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)
+                   || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+                 continue;
+             }
+
+           if (vty->output_type == bgp_show_type_dampend_paths
+               || vty->output_type == bgp_show_type_damp_neighbor)
+             count += damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+           else if (vty->output_type == bgp_show_type_flap_statistics
+                    || vty->output_type == bgp_show_type_flap_address
+                    || vty->output_type == bgp_show_type_flap_prefix
+                    || vty->output_type == bgp_show_type_flap_cidr_only
+                    || vty->output_type == bgp_show_type_flap_regexp
+                    || vty->output_type == bgp_show_type_flap_filter_list
+                    || vty->output_type == bgp_show_type_flap_prefix_list
+                    || vty->output_type == bgp_show_type_flap_prefix_longer
+                    || vty->output_type == bgp_show_type_flap_route_map
+                    || vty->output_type == bgp_show_type_flap_neighbor)
+             count += flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+           else
+             count += route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+           display++;
+         }
+
+       if (display)
+         vty->output_count++;
+
+       /* Remember current pointer then suspend output. */
+       if (count >= limit)
+         {
+           vty->status = VTY_CONTINUE;
+           vty->output_rn = bgp_route_next (rn);;
+           vty->output_func = bgp_show_callback;
+           return 0;
+         }
+      }
+
+  /* Total line display. */
+  if (vty->output_count)
+    vty_out (vty, "%sTotal number of prefixes %ld%s",
+            VTY_NEWLINE, vty->output_count, VTY_NEWLINE);
+
+  if (vty->output_clean)
+    (*vty->output_clean) (vty);
+
+  vty->status = VTY_CONTINUE;
+  vty->output_rn = NULL;
+  vty->output_func = NULL;
+  vty->output_clean = NULL;
+  vty->output_arg = NULL;
+
+  return 0;
+}
+
+int
+bgp_show (struct vty *vty, char *view_name, afi_t afi, safi_t safi,
+         enum bgp_show_type type)
+{
+  struct bgp *bgp;
+  struct bgp_info *ri;
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  int header = 1;
+  int count;
+  int limit;
+  int display;
+
+  limit = ((vty->lines == 0) 
+          ? 10 : (vty->lines > 0 
+                  ? vty->lines : vty->height - 2));
+  limit = limit > 0 ? limit : 2;
+
+  /* BGP structure lookup. */
+  if (view_name)
+    {
+      bgp = bgp_lookup_by_name (view_name);
+      if (bgp == NULL)
+       {
+         vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+       {
+         vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+
+  count = 0;
+
+  /* This is first entry point, so reset total line. */
+  vty->output_count = 0;
+  vty->output_type = type;
+
+  table = bgp->rib[afi][safi];
+
+  /* Start processing of routes. */
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) 
+    if (rn->info != NULL)
+      {
+       display = 0;
+
+       for (ri = rn->info; ri; ri = ri->next)
+         {
+           if (vty->output_type == bgp_show_type_flap_statistics
+               || type == bgp_show_type_flap_address
+               || type == bgp_show_type_flap_prefix
+               || type == bgp_show_type_flap_cidr_only
+               || type == bgp_show_type_flap_regexp
+               || type == bgp_show_type_flap_filter_list
+               || type == bgp_show_type_flap_prefix_list
+               || type == bgp_show_type_flap_prefix_longer
+               || type == bgp_show_type_flap_route_map
+               || type == bgp_show_type_flap_neighbor
+               || type == bgp_show_type_dampend_paths
+               || type == bgp_show_type_damp_neighbor)
+             {
+               if (! ri->damp_info)
+                 continue;
+             }
+           if (type == bgp_show_type_regexp
+               || type == bgp_show_type_flap_regexp)
+             {
+               regex_t *regex = vty->output_arg;
+                   
+               if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH)
+                 continue;
+             }
+           if (type == bgp_show_type_prefix_list
+               || type == bgp_show_type_flap_prefix_list)
+             {
+               struct prefix_list *plist = vty->output_arg;
+                   
+               if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT)
+                 continue;
+             }
+           if (type == bgp_show_type_filter_list
+               || type == bgp_show_type_flap_filter_list)
+             {
+               struct as_list *as_list = vty->output_arg;
+
+               if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT)
+                 continue;
+             }
+           if (type == bgp_show_type_route_map
+               || type == bgp_show_type_flap_route_map)
+             {
+               struct route_map *rmap = vty->output_arg;
+               struct bgp_info binfo;
+               struct attr dummy_attr; 
+               int ret;
+
+               dummy_attr = *ri->attr;
+               binfo.peer = ri->peer;
+               binfo.attr = &dummy_attr;
+
+               ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo);
+
+               if (ret == RMAP_DENYMATCH)
+                 continue;
+             }
+           if (type == bgp_show_type_neighbor
+               || type == bgp_show_type_flap_neighbor
+               || type == bgp_show_type_damp_neighbor)
+             {
+               union sockunion *su = vty->output_arg;
+
+               if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
+                 continue;
+             }
+           if (type == bgp_show_type_cidr_only
+               || type == bgp_show_type_flap_cidr_only)
+             {
+               u_int32_t destination;
+
+               destination = ntohl (rn->p.u.prefix4.s_addr);
+               if (IN_CLASSC (destination) && rn->p.prefixlen == 24)
+                 continue;
+               if (IN_CLASSB (destination) && rn->p.prefixlen == 16)
+                 continue;
+               if (IN_CLASSA (destination) && rn->p.prefixlen == 8)
+                 continue;
+             }
+           if (type == bgp_show_type_prefix_longer
+               || type == bgp_show_type_flap_prefix_longer)
+             {
+               struct prefix *p = vty->output_arg;
+
+               if (! prefix_match (p, &rn->p))
+                 continue;
+             }
+           if (type == bgp_show_type_community_all)
+             {
+               if (! ri->attr->community)
+                 continue;
+             }
+           if (type == bgp_show_type_community)
+             {
+               struct community *com = vty->output_arg;
+
+               if (! ri->attr->community ||
+                   ! community_match (ri->attr->community, com))
+                 continue;
+             }
+           if (type == bgp_show_type_community_exact)
+             {
+               struct community *com = vty->output_arg;
+
+               if (! ri->attr->community ||
+                   ! community_cmp (ri->attr->community, com))
+                 continue;
+             }
+           if (type == bgp_show_type_community_list)
+             {
+               struct community_list *list = vty->output_arg;
+
+               if (! community_list_match (ri->attr->community, list))
+                 continue;
+             }
+           if (type == bgp_show_type_community_list_exact)
+             {
+               struct community_list *list = vty->output_arg;
+
+               if (! community_list_exact_match (ri->attr->community, list))
+                 continue;
+             }
+           if (type == bgp_show_type_flap_address
+               || type == bgp_show_type_flap_prefix)
+             {
+               struct prefix *p = vty->output_arg;
+
+               if (! prefix_match (&rn->p, p))
+                 continue;
+
+               if (type == bgp_show_type_flap_prefix)
+                 if (p->prefixlen != rn->p.prefixlen)
+                   continue;
+             }
+           if (type == bgp_show_type_dampend_paths
+               || type == bgp_show_type_damp_neighbor)
+             {
+               if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)
+                   || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+                 continue;
+             }
+
+           if (header)
+             {
+               vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+               vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
+               vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+               if (type == bgp_show_type_dampend_paths
+                   || type == bgp_show_type_damp_neighbor)
+                 vty_out (vty, BGP_SHOW_DAMP_HEADER, VTY_NEWLINE);
+               else if (type == bgp_show_type_flap_statistics
+                        || type == bgp_show_type_flap_address
+                        || type == bgp_show_type_flap_prefix
+                        || type == bgp_show_type_flap_cidr_only
+                        || type == bgp_show_type_flap_regexp
+                        || type == bgp_show_type_flap_filter_list
+                        || type == bgp_show_type_flap_prefix_list
+                        || type == bgp_show_type_flap_prefix_longer
+                        || type == bgp_show_type_flap_route_map
+                        || type == bgp_show_type_flap_neighbor)
+                 vty_out (vty, BGP_SHOW_FLAP_HEADER, VTY_NEWLINE);
+               else
+                 vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
+               count += 5;
+               header = 0;
+             }
+
+           if (type == bgp_show_type_dampend_paths
+               || type == bgp_show_type_damp_neighbor)
+             count += damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+           else if (type == bgp_show_type_flap_statistics
+                    || type == bgp_show_type_flap_address
+                    || type == bgp_show_type_flap_prefix
+                    || type == bgp_show_type_flap_cidr_only
+                    || type == bgp_show_type_flap_regexp
+                    || type == bgp_show_type_flap_filter_list
+                    || type == bgp_show_type_flap_prefix_list
+                    || type == bgp_show_type_flap_prefix_longer
+                    || type == bgp_show_type_flap_route_map
+                    || type == bgp_show_type_flap_neighbor)
+             count += flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+           else
+             count += route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+           display++;
+         }
+       if (display)
+         vty->output_count++;
+
+       /* Remember current pointer then suspend output. */
+       if (count >= limit  && vty->type != VTY_SHELL_SERV)
+         {
+           vty->status = VTY_START;
+           vty->output_rn = bgp_route_next (rn);
+           vty->output_func = bgp_show_callback;
+           vty->output_type = type;
+
+           return CMD_SUCCESS;
+         }
+      }
+
+  /* No route is displayed */
+  if (vty->output_count == 0)
+    {
+      if (type == bgp_show_type_normal)
+       vty_out (vty, "No BGP network exists%s", VTY_NEWLINE);
+    }
+  else
+    vty_out (vty, "%sTotal number of prefixes %ld%s",
+            VTY_NEWLINE, vty->output_count, VTY_NEWLINE);
+
+  /* Clean up allocated resources. */
+  if (vty->output_clean)
+    (*vty->output_clean) (vty);
+
+  vty->status = VTY_START;
+  vty->output_rn = NULL;
+  vty->output_func = NULL;
+  vty->output_clean = NULL;
+  vty->output_arg = NULL;
+
+  return CMD_SUCCESS;
+}
+
+/* Header of detailed BGP route information */
+void
+route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
+                            struct bgp_node *rn,
+                             struct prefix_rd *prd, afi_t afi, safi_t safi)
+{
+  struct bgp_info *ri;
+  struct prefix *p;
+  struct peer *peer;
+  struct listnode *nn;
+  char buf1[INET6_ADDRSTRLEN];
+  char buf2[INET6_ADDRSTRLEN];
+  int count = 0;
+  int best = 0;
+  int suppress = 0;
+  int no_export = 0;
+  int no_advertise = 0;
+  int local_as = 0;
+  int first = 0;
+
+  p = &rn->p;
+  vty_out (vty, "BGP routing table entry for %s%s%s/%d%s",
+          (safi == SAFI_MPLS_VPN ?
+          prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""),
+          safi == SAFI_MPLS_VPN ? ":" : "",
+          inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN),
+          p->prefixlen, VTY_NEWLINE);
+
+  for (ri = rn->info; ri; ri = ri->next)
+    {
+      count++;
+      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+       {
+         best = count;
+         if (ri->suppress)
+           suppress = 1;
+         if (ri->attr->community != NULL)
+           {
+             if (community_include (ri->attr->community, COMMUNITY_NO_ADVERTISE))
+               no_advertise = 1;
+             if (community_include (ri->attr->community, COMMUNITY_NO_EXPORT))
+               no_export = 1;
+             if (community_include (ri->attr->community, COMMUNITY_LOCAL_AS))
+               local_as = 1;
+           }
+       }
+    }
+
+  vty_out (vty, "Paths: (%d available", count);
+  if (best)
+    {
+      vty_out (vty, ", best #%d", best);
+      if (safi == SAFI_UNICAST)
+       vty_out (vty, ", table Default-IP-Routing-Table");
+    }
+  else
+    vty_out (vty, ", no best path");
+  if (no_advertise)
+    vty_out (vty, ", not advertised to any peer");
+  else if (no_export)
+    vty_out (vty, ", not advertised to EBGP peer");
+  else if (local_as)
+    vty_out (vty, ", not advertised outside local AS");
+  if (suppress)
+    vty_out (vty, ", Advertisements suppressed by an aggregate.");
+  vty_out (vty, ")%s", VTY_NEWLINE);
+
+  /* advertised peer */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (bgp_adj_out_lookup (peer, p, afi, safi, rn))
+       {
+         if (! first)
+           vty_out (vty, "  Advertised to non peer-group peers:%s ", VTY_NEWLINE);
+         vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
+         first = 1;
+       }
+    }
+  if (! first)
+    vty_out (vty, "  Not advertised to any peer");
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+/* Display specified route of BGP table. */
+int
+bgp_show_route (struct vty *vty, char *view_name, char *ip_str,
+               afi_t afi, safi_t safi, struct prefix_rd *prd,
+               int prefix_check)
+{
+  int ret;
+  int header;
+  int display = 0;
+  struct prefix match;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp_info *ri;
+  struct bgp *bgp;
+  struct bgp_table *table;
+
+  /* BGP structure lookup. */
+  if (view_name)
+    {
+      bgp = bgp_lookup_by_name (view_name);
+      if (bgp == NULL)
+       {
+         vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+       {
+         vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+
+  /* Check IP address argument. */
+  ret = str2prefix (ip_str, &match);
+  if (! ret)
+    {
+      vty_out (vty, "address is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  match.family = afi2family (afi);
+
+  if (safi == SAFI_MPLS_VPN)
+    {
+      for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn))
+        {
+          if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+            continue;
+
+          if ((table = rn->info) != NULL)
+            {
+              header = 1;
+
+              if ((rm = bgp_node_match (table, &match)) != NULL)
+                {
+                  if (prefix_check && rm->p.prefixlen != match.prefixlen)
+                    continue;
+
+                  for (ri = rm->info; ri; ri = ri->next)
+                    {
+                      if (header)
+                        {
+                          route_vty_out_detail_header (vty, bgp, rm, (struct prefix_rd *)&rn->p,
+                                                       AFI_IP, SAFI_MPLS_VPN);
+
+                          header = 0;
+                        }
+                      display++;
+                      route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN);
+                    }
+                }
+            }
+        }
+    }
+  else
+    {
+      header = 1;
+
+      if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL)
+        {
+          if (! prefix_check || rn->p.prefixlen == match.prefixlen)
+            {
+              for (ri = rn->info; ri; ri = ri->next)
+                {
+                  if (header)
+                    {
+                      route_vty_out_detail_header (vty, bgp, rn, NULL, afi, safi);
+                      header = 0;
+                    }
+                  display++;
+                  route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi);
+                }
+            }
+        }
+    }
+
+  if (! display)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* BGP route print out function. */
+DEFUN (show_ip_bgp,
+       show_ip_bgp_cmd,
+       "show ip bgp",
+       SHOW_STR
+       IP_STR
+       BGP_STR)
+{
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+DEFUN (show_ip_bgp_ipv4,
+       show_ip_bgp_ipv4_cmd,
+       "show ip bgp ipv4 (unicast|multicast)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_normal);
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+DEFUN (show_ip_bgp_route,
+       show_ip_bgp_route_cmd,
+       "show ip bgp A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Network in the BGP routing table to display\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_ipv4_route,
+       show_ip_bgp_ipv4_route_cmd,
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Network in the BGP routing table to display\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0);
+
+  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_route,
+       show_ip_bgp_vpnv4_all_route_cmd,
+       "show ip bgp vpnv4 all A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Network in the BGP routing table to display\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_route,
+       show_ip_bgp_vpnv4_rd_route_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Network in the BGP routing table to display\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0);
+}
+
+DEFUN (show_ip_bgp_prefix,
+       show_ip_bgp_prefix_cmd,
+       "show ip bgp A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_ipv4_prefix,
+       show_ip_bgp_ipv4_prefix_cmd,
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1);
+
+  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_prefix,
+       show_ip_bgp_vpnv4_all_prefix_cmd,
+       "show ip bgp vpnv4 all A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_prefix,
+       show_ip_bgp_vpnv4_rd_prefix_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1);
+}
+
+DEFUN (show_ip_bgp_view,
+       show_ip_bgp_view_cmd,
+       "show ip bgp view WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n")
+{
+  return bgp_show (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+DEFUN (show_ip_bgp_view_route,
+       show_ip_bgp_view_route_cmd,
+       "show ip bgp view WORD A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Network in the BGP routing table to display\n")
+{
+  return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (show_ip_bgp_view_prefix,
+       show_ip_bgp_view_prefix_cmd,
+       "show ip bgp view WORD A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp,
+       show_bgp_cmd,
+       "show bgp",
+       SHOW_STR
+       BGP_STR)
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+ALIAS (show_bgp,
+       show_bgp_ipv6_cmd,
+       "show bgp ipv6",
+       SHOW_STR
+       BGP_STR
+       "Address family\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp,
+       show_ipv6_bgp_cmd,
+       "show ipv6 bgp",
+       SHOW_STR
+       IP_STR
+       BGP_STR)
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal);
+}
+
+DEFUN (show_bgp_route,
+       show_bgp_route_cmd,
+       "show bgp X:X::X:X",
+       SHOW_STR
+       BGP_STR
+       "Network in the BGP routing table to display\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
+ALIAS (show_bgp_route,
+       show_bgp_ipv6_route_cmd,
+       "show bgp ipv6 X:X::X:X",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Network in the BGP routing table to display\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_route,
+       show_ipv6_bgp_route_cmd,
+       "show ipv6 bgp X:X::X:X",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Network in the BGP routing table to display\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (show_bgp_prefix,
+       show_bgp_prefix_cmd,
+       "show bgp X:X::X:X/M",
+       SHOW_STR
+       BGP_STR
+       "IPv6 prefix <network>/<length>\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+}
+
+ALIAS (show_bgp_prefix,
+       show_bgp_ipv6_prefix_cmd,
+       "show bgp ipv6 X:X::X:X/M",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "IPv6 prefix <network>/<length>\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_prefix,
+       show_ipv6_bgp_prefix_cmd,
+       "show ipv6 bgp X:X::X:X/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp,
+       show_ipv6_mbgp_cmd,
+       "show ipv6 mbgp",
+       SHOW_STR
+       IP_STR
+       MBGP_STR)
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_route,
+       show_ipv6_mbgp_route_cmd,
+       "show ipv6 mbgp X:X::X:X",
+       SHOW_STR
+       IP_STR
+       MBGP_STR
+       "Network in the MBGP routing table to display\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_prefix,
+       show_ipv6_mbgp_prefix_cmd,
+       "show ipv6 mbgp X:X::X:X/M",
+       SHOW_STR
+       IP_STR
+       MBGP_STR
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1);
+}
+#endif
+\f
+void
+bgp_show_regexp_clean (struct vty *vty)
+{
+  bgp_regex_free (vty->output_arg);
+}
+
+int
+bgp_show_regexp (struct vty *vty, int argc, char **argv, afi_t afi,
+                safi_t safi, enum bgp_show_type type)
+{
+  int i;
+  struct buffer *b;
+  char *regstr;
+  int first;
+  regex_t *regex;
+  
+  first = 0;
+  b = buffer_new (1024);
+  for (i = 0; i < argc; i++)
+    {
+      if (first)
+       buffer_putc (b, ' ');
+      else
+       {
+         if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0))
+           continue;
+         first = 1;
+       }
+
+      buffer_putstr (b, argv[i]);
+    }
+  buffer_putc (b, '\0');
+
+  regstr = buffer_getstr (b);
+  buffer_free (b);
+
+  regex = bgp_regcomp (regstr);
+  if (! regex)
+    {
+      vty_out (vty, "Can't compile regexp %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = regex;
+  vty->output_clean = bgp_show_regexp_clean;
+
+  return bgp_show (vty, NULL, afi, safi, type);
+}
+
+DEFUN (show_ip_bgp_regexp, 
+       show_ip_bgp_regexp_cmd,
+       "show ip bgp regexp .LINE",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST,
+                         bgp_show_type_regexp);
+}
+
+DEFUN (show_ip_bgp_flap_regexp, 
+       show_ip_bgp_flap_regexp_cmd,
+       "show ip bgp flap-statistics regexp .LINE",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST,
+                         bgp_show_type_flap_regexp);
+}
+
+DEFUN (show_ip_bgp_ipv4_regexp, 
+       show_ip_bgp_ipv4_regexp_cmd,
+       "show ip bgp ipv4 (unicast|multicast) regexp .LINE",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST,
+                           bgp_show_type_regexp);
+
+  return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST,
+                         bgp_show_type_regexp);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_regexp, 
+       show_bgp_regexp_cmd,
+       "show bgp regexp .LINE",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST,
+                         bgp_show_type_regexp);
+}
+
+ALIAS (show_bgp_regexp, 
+       show_bgp_ipv6_regexp_cmd,
+       "show bgp ipv6 regexp .LINE",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_regexp, 
+       show_ipv6_bgp_regexp_cmd,
+       "show ipv6 bgp regexp .LINE",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+{
+  return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST,
+                         bgp_show_type_regexp);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_regexp, 
+       show_ipv6_mbgp_regexp_cmd,
+       "show ipv6 mbgp regexp .LINE",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the MBGP AS paths\n")
+{
+  return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST,
+                         bgp_show_type_regexp);
+}
+#endif /* HAVE_IPV6 */
+\f
+int
+bgp_show_prefix_list (struct vty *vty, char *prefix_list_str, afi_t afi,
+                     safi_t safi, enum bgp_show_type type)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (afi, prefix_list_str);
+  if (plist == NULL)
+    {
+      vty_out (vty, "%% %s is not a valid prefix-list name%s",
+               prefix_list_str, VTY_NEWLINE);      
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = plist;
+
+  return bgp_show (vty, NULL, afi, safi, type);
+}
+
+DEFUN (show_ip_bgp_prefix_list, 
+       show_ip_bgp_prefix_list_cmd,
+       "show ip bgp prefix-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes conforming to the prefix-list\n"
+       "IP prefix-list name\n")
+{
+  return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                              bgp_show_type_prefix_list);
+}
+
+DEFUN (show_ip_bgp_flap_prefix_list, 
+       show_ip_bgp_flap_prefix_list_cmd,
+       "show ip bgp flap-statistics prefix-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "Display routes conforming to the prefix-list\n"
+       "IP prefix-list name\n")
+{
+  return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                              bgp_show_type_flap_prefix_list);
+}
+
+DEFUN (show_ip_bgp_ipv4_prefix_list, 
+       show_ip_bgp_ipv4_prefix_list_cmd,
+       "show ip bgp ipv4 (unicast|multicast) prefix-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes conforming to the prefix-list\n"
+       "IP prefix-list name\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST,
+                                bgp_show_type_prefix_list);
+
+  return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST,
+                              bgp_show_type_prefix_list);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_prefix_list, 
+       show_bgp_prefix_list_cmd,
+       "show bgp prefix-list WORD",
+       SHOW_STR
+       BGP_STR
+       "Display routes conforming to the prefix-list\n"
+       "IPv6 prefix-list name\n")
+{
+  return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                              bgp_show_type_prefix_list);
+}
+
+ALIAS (show_bgp_prefix_list, 
+       show_bgp_ipv6_prefix_list_cmd,
+       "show bgp ipv6 prefix-list WORD",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes conforming to the prefix-list\n"
+       "IPv6 prefix-list name\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_prefix_list, 
+       show_ipv6_bgp_prefix_list_cmd,
+       "show ipv6 bgp prefix-list WORD",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the prefix-list\n"
+       "IPv6 prefix-list name\n")
+{
+  return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                              bgp_show_type_prefix_list);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_prefix_list, 
+       show_ipv6_mbgp_prefix_list_cmd,
+       "show ipv6 mbgp prefix-list WORD",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the prefix-list\n"
+       "IPv6 prefix-list name\n")
+{
+  return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST,
+                              bgp_show_type_prefix_list);
+}
+#endif /* HAVE_IPV6 */
+\f
+int
+bgp_show_filter_list (struct vty *vty, char *filter, afi_t afi,
+                     safi_t safi, enum bgp_show_type type)
+{
+  struct as_list *as_list;
+
+  as_list = as_list_lookup (filter);
+  if (as_list == NULL)
+    {
+      vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE);       
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = as_list;
+
+  return bgp_show (vty, NULL, afi, safi, type);
+}
+
+DEFUN (show_ip_bgp_filter_list, 
+       show_ip_bgp_filter_list_cmd,
+       "show ip bgp filter-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+{
+  return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                              bgp_show_type_filter_list);
+}
+
+DEFUN (show_ip_bgp_flap_filter_list, 
+       show_ip_bgp_flap_filter_list_cmd,
+       "show ip bgp flap-statistics filter-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+{
+  return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                              bgp_show_type_flap_filter_list);
+}
+
+DEFUN (show_ip_bgp_ipv4_filter_list, 
+       show_ip_bgp_ipv4_filter_list_cmd,
+       "show ip bgp ipv4 (unicast|multicast) filter-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST,
+                                bgp_show_type_filter_list);
+  
+  return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST,
+                              bgp_show_type_filter_list);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_filter_list, 
+       show_bgp_filter_list_cmd,
+       "show bgp filter-list WORD",
+       SHOW_STR
+       BGP_STR
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+{
+  return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                              bgp_show_type_filter_list);
+}
+
+ALIAS (show_bgp_filter_list, 
+       show_bgp_ipv6_filter_list_cmd,
+       "show bgp ipv6 filter-list WORD",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_filter_list, 
+       show_ipv6_bgp_filter_list_cmd,
+       "show ipv6 bgp filter-list WORD",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+{
+  return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                              bgp_show_type_filter_list);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_filter_list, 
+       show_ipv6_mbgp_filter_list_cmd,
+       "show ipv6 mbgp filter-list WORD",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+{
+  return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST,
+                              bgp_show_type_filter_list);
+}
+#endif /* HAVE_IPV6 */
+\f
+int
+bgp_show_route_map (struct vty *vty, char *rmap_str, afi_t afi,
+                   safi_t safi, enum bgp_show_type type)
+{
+  struct route_map *rmap;
+
+  rmap = route_map_lookup_by_name (rmap_str);
+  if (! rmap)
+    {
+      vty_out (vty, "%% %s is not a valid route-map name%s",
+              rmap_str, VTY_NEWLINE);      
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = rmap;
+
+  return bgp_show (vty, NULL, afi, safi, type);
+}
+
+DEFUN (show_ip_bgp_route_map, 
+       show_ip_bgp_route_map_cmd,
+       "show ip bgp route-map WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+{
+  return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                            bgp_show_type_route_map);
+}
+
+DEFUN (show_ip_bgp_flap_route_map, 
+       show_ip_bgp_flap_route_map_cmd,
+       "show ip bgp flap-statistics route-map WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+{
+  return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                            bgp_show_type_flap_route_map);
+}
+
+DEFUN (show_ip_bgp_ipv4_route_map, 
+       show_ip_bgp_ipv4_route_map_cmd,
+       "show ip bgp ipv4 (unicast|multicast) route-map WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST,
+                              bgp_show_type_route_map);
+
+  return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST,
+                            bgp_show_type_route_map);
+}
+
+DEFUN (show_bgp_route_map, 
+       show_bgp_route_map_cmd,
+       "show bgp route-map WORD",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+{
+  return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                            bgp_show_type_route_map);
+}
+
+ALIAS (show_bgp_route_map, 
+       show_bgp_ipv6_route_map_cmd,
+       "show bgp ipv6 route-map WORD",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+\f
+DEFUN (show_ip_bgp_cidr_only,
+       show_ip_bgp_cidr_only_cmd,
+       "show ip bgp cidr-only",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display only routes with non-natural netmasks\n")
+{
+    return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+                    bgp_show_type_cidr_only);
+}
+
+DEFUN (show_ip_bgp_flap_cidr_only,
+       show_ip_bgp_flap_cidr_only_cmd,
+       "show ip bgp flap-statistics cidr-only",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "Display only routes with non-natural netmasks\n")
+{
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+                  bgp_show_type_flap_cidr_only);
+}
+
+DEFUN (show_ip_bgp_ipv4_cidr_only,
+       show_ip_bgp_ipv4_cidr_only_cmd,
+       "show ip bgp ipv4 (unicast|multicast) cidr-only",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display only routes with non-natural netmasks\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
+                    bgp_show_type_cidr_only);
+
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+                    bgp_show_type_cidr_only);
+}
+\f
+DEFUN (show_ip_bgp_community_all,
+       show_ip_bgp_community_all_cmd,
+       "show ip bgp community",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+                    bgp_show_type_community_all);
+}
+
+DEFUN (show_ip_bgp_ipv4_community_all,
+       show_ip_bgp_ipv4_community_all_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
+                    bgp_show_type_community_all);
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+                  bgp_show_type_community_all);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_community_all,
+       show_bgp_community_all_cmd,
+       "show bgp community",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST,
+                  bgp_show_type_community_all);
+}
+
+ALIAS (show_bgp_community_all,
+       show_bgp_ipv6_community_all_cmd,
+       "show bgp ipv6 community",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_community_all,
+       show_ipv6_bgp_community_all_cmd,
+       "show ipv6 bgp community",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST,
+                  bgp_show_type_community_all);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_community_all,
+       show_ipv6_mbgp_community_all_cmd,
+       "show ipv6 mbgp community",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST,
+                  bgp_show_type_community_all);
+}
+#endif /* HAVE_IPV6 */
+\f
+int
+bgp_show_community (struct vty *vty, int argc, char **argv, int exact,
+                                         u_int16_t afi, u_char safi)
+{
+  struct community *com;
+  struct buffer *b;
+  int i;
+  char *str;
+  int first = 0;
+
+  b = buffer_new (1024);
+  for (i = 0; i < argc; i++)
+    {
+      if (first)
+        buffer_putc (b, ' ');
+      else
+       {
+         if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0))
+           continue;
+         first = 1;
+       }
+      
+      buffer_putstr (b, argv[i]);
+    }
+  buffer_putc (b, '\0');
+
+  str = buffer_getstr (b);
+  buffer_free (b);
+
+  com = community_str2com (str);
+  free (str);
+  if (! com)
+    {
+      vty_out (vty, "%% Community malformed: %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = com;
+
+  if (exact)
+    return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_exact);
+
+  return bgp_show (vty, NULL, afi, safi, bgp_show_type_community);
+}
+
+DEFUN (show_ip_bgp_community,
+       show_ip_bgp_community_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+{
+  return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_community,
+       show_ip_bgp_community2_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+       
+ALIAS (show_ip_bgp_community,
+       show_ip_bgp_community3_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+       
+ALIAS (show_ip_bgp_community,
+       show_ip_bgp_community4_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFUN (show_ip_bgp_ipv4_community,
+       show_ip_bgp_ipv4_community_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST);
+  return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_ipv4_community,
+       show_ip_bgp_ipv4_community2_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+       
+ALIAS (show_ip_bgp_ipv4_community,
+       show_ip_bgp_ipv4_community3_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+       
+ALIAS (show_ip_bgp_ipv4_community,
+       show_ip_bgp_ipv4_community4_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFUN (show_ip_bgp_community_exact,
+       show_ip_bgp_community_exact_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+{
+  return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_community_exact,
+       show_ip_bgp_community2_exact_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_ip_bgp_community_exact,
+       show_ip_bgp_community3_exact_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_ip_bgp_community_exact,
+       show_ip_bgp_community4_exact_cmd,
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFUN (show_ip_bgp_ipv4_community_exact,
+       show_ip_bgp_ipv4_community_exact_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST);
+  return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_ipv4_community_exact,
+       show_ip_bgp_ipv4_community2_exact_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_ip_bgp_ipv4_community_exact,
+       show_ip_bgp_ipv4_community3_exact_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+       
+ALIAS (show_ip_bgp_ipv4_community_exact,
+       show_ip_bgp_ipv4_community4_exact_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_community,
+       show_bgp_community_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+{
+  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_community,
+       show_bgp_ipv6_community_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_community,
+       show_bgp_community2_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_community,
+       show_bgp_ipv6_community2_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+       
+ALIAS (show_bgp_community,
+       show_bgp_community3_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_community,
+       show_bgp_ipv6_community3_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_community,
+       show_bgp_community4_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_community,
+       show_bgp_ipv6_community4_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_community,
+       show_ipv6_bgp_community_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+{
+  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_bgp_community,
+       show_ipv6_bgp_community2_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+/* old command */
+ALIAS (show_ipv6_bgp_community,
+       show_ipv6_bgp_community3_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+/* old command */
+ALIAS (show_ipv6_bgp_community,
+       show_ipv6_bgp_community4_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFUN (show_bgp_community_exact,
+       show_bgp_community_exact_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+{
+  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_community_exact,
+       show_bgp_ipv6_community_exact_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_bgp_community_exact,
+       show_bgp_community2_exact_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_bgp_community_exact,
+       show_bgp_ipv6_community2_exact_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_bgp_community_exact,
+       show_bgp_community3_exact_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_bgp_community_exact,
+       show_bgp_ipv6_community3_exact_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+ALIAS (show_bgp_community_exact,
+       show_bgp_community4_exact_cmd,
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+ALIAS (show_bgp_community_exact,
+       show_bgp_ipv6_community4_exact_cmd,
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+/* old command */
+DEFUN (show_ipv6_bgp_community_exact,
+       show_ipv6_bgp_community_exact_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+{
+  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_bgp_community_exact,
+       show_ipv6_bgp_community2_exact_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+/* old command */
+ALIAS (show_ipv6_bgp_community_exact,
+       show_ipv6_bgp_community3_exact_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+/* old command */
+ALIAS (show_ipv6_bgp_community_exact,
+       show_ipv6_bgp_community4_exact_cmd,
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+/* old command */
+DEFUN (show_ipv6_mbgp_community,
+       show_ipv6_mbgp_community_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+{
+  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_MULTICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_mbgp_community,
+       show_ipv6_mbgp_community2_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_community,
+       show_ipv6_mbgp_community3_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_community,
+       show_ipv6_mbgp_community4_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+/* old command */
+DEFUN (show_ipv6_mbgp_community_exact,
+       show_ipv6_mbgp_community_exact_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+{
+  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_MULTICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_mbgp_community_exact,
+       show_ipv6_mbgp_community2_exact_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_community_exact,
+       show_ipv6_mbgp_community3_exact_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_community_exact,
+       show_ipv6_mbgp_community4_exact_cmd,
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+#endif /* HAVE_IPV6 */
+\f
+int
+bgp_show_community_list (struct vty *vty, char *com, int exact,
+                        u_int16_t afi, u_char safi)
+{
+  struct community_list *list;
+
+  list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_AUTO);
+  if (list == NULL)
+    {
+      vty_out (vty, "%% %s is not a valid community-list name%s", com,
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = list;
+
+  if (exact)
+    return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_list_exact);
+
+  return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_list);
+}
+
+DEFUN (show_ip_bgp_community_list,
+       show_ip_bgp_community_list_cmd,
+       "show ip bgp community-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+{
+  return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_ipv4_community_list,
+       show_ip_bgp_ipv4_community_list_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community-list WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST);
+  
+  return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_community_list_exact,
+       show_ip_bgp_community_list_exact_cmd,
+       "show ip bgp community-list WORD exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+{
+  return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_ipv4_community_list_exact,
+       show_ip_bgp_ipv4_community_list_exact_cmd,
+       "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST);
+  return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_community_list,
+       show_bgp_community_list_cmd,
+       "show bgp community-list WORD",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+{
+  return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_community_list,
+       show_bgp_ipv6_community_list_cmd,
+       "show bgp ipv6 community-list WORD",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_community_list,
+       show_ipv6_bgp_community_list_cmd,
+       "show ipv6 bgp community-list WORD",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+{
+  return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_community_list,
+       show_ipv6_mbgp_community_list_cmd,
+       "show ipv6 mbgp community-list WORD",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+{
+  return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST);
+}
+
+DEFUN (show_bgp_community_list_exact,
+       show_bgp_community_list_exact_cmd,
+       "show bgp community-list WORD exact-match",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+{
+  return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_community_list_exact,
+       show_bgp_ipv6_community_list_exact_cmd,
+       "show bgp ipv6 community-list WORD exact-match",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_community_list_exact,
+       show_ipv6_bgp_community_list_exact_cmd,
+       "show ipv6 bgp community-list WORD exact-match",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+{
+  return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_community_list_exact,
+       show_ipv6_mbgp_community_list_exact_cmd,
+       "show ipv6 mbgp community-list WORD exact-match",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+{
+  return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST);
+}
+#endif /* HAVE_IPV6 */
+\f
+void
+bgp_show_prefix_longer_clean (struct vty *vty)
+{
+  struct prefix *p;
+
+  p = vty->output_arg;
+  prefix_free (p);
+}
+
+int
+bgp_show_prefix_longer (struct vty *vty, char *prefix, afi_t afi,
+                       safi_t safi, enum bgp_show_type type)
+{
+  int ret;
+  struct prefix *p;
+
+  p = prefix_new();
+
+  ret = str2prefix (prefix, p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty->output_arg = p;
+  vty->output_clean = bgp_show_prefix_longer_clean;
+
+  return bgp_show (vty, NULL, afi, safi, type);
+}
+
+DEFUN (show_ip_bgp_prefix_longer,
+       show_ip_bgp_prefix_longer_cmd,
+       "show ip bgp A.B.C.D/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Display route and more specific routes\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                bgp_show_type_prefix_longer);
+}
+
+DEFUN (show_ip_bgp_flap_prefix_longer,
+       show_ip_bgp_flap_prefix_longer_cmd,
+       "show ip bgp flap-statistics A.B.C.D/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Display route and more specific routes\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                bgp_show_type_flap_prefix_longer);
+}
+
+DEFUN (show_ip_bgp_ipv4_prefix_longer,
+       show_ip_bgp_ipv4_prefix_longer_cmd,
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Display route and more specific routes\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST,
+                                  bgp_show_type_prefix_longer);
+
+  return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST,
+                                bgp_show_type_prefix_longer);
+}
+
+DEFUN (show_ip_bgp_flap_address,
+       show_ip_bgp_flap_address_cmd,
+       "show ip bgp flap-statistics A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "Network in the BGP routing table to display\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                bgp_show_type_flap_address);
+}
+
+DEFUN (show_ip_bgp_flap_prefix,
+       show_ip_bgp_flap_prefix_cmd,
+       "show ip bgp flap-statistics A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                bgp_show_type_flap_prefix);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_prefix_longer,
+       show_bgp_prefix_longer_cmd,
+       "show bgp X:X::X:X/M longer-prefixes",
+       SHOW_STR
+       BGP_STR
+       "IPv6 prefix <network>/<length>\n"
+       "Display route and more specific routes\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                                bgp_show_type_prefix_longer);
+}
+
+ALIAS (show_bgp_prefix_longer,
+       show_bgp_ipv6_prefix_longer_cmd,
+       "show bgp ipv6 X:X::X:X/M longer-prefixes",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Display route and more specific routes\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_prefix_longer,
+       show_ipv6_bgp_prefix_longer_cmd,
+       "show ipv6 bgp X:X::X:X/M longer-prefixes",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Display route and more specific routes\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                                bgp_show_type_prefix_longer);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_prefix_longer,
+       show_ipv6_mbgp_prefix_longer_cmd,
+       "show ipv6 mbgp X:X::X:X/M longer-prefixes",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Display route and more specific routes\n")
+{
+  return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST,
+                                bgp_show_type_prefix_longer);
+}
+#endif /* HAVE_IPV6 */
+\f
+void
+show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
+               int in)
+{
+  struct bgp_table *table;
+  struct bgp_adj_in *ain;
+  struct bgp_adj_out *adj;
+  unsigned long output_count;
+  struct bgp_node *rn;
+  int header1 = 1;
+  struct bgp *bgp;
+  int header2 = 1;
+
+  bgp = bgp_get_default ();
+
+  if (! bgp)
+    return;
+
+  table = bgp->rib[afi][safi];
+
+  output_count = 0;
+       
+  if (! in && CHECK_FLAG (peer->af_sflags[afi][safi],
+                         PEER_STATUS_DEFAULT_ORIGINATE))
+    {
+      vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+      vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
+      vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+
+      vty_out (vty, "Originating default network 0.0.0.0%s%s",
+              VTY_NEWLINE, VTY_NEWLINE);
+      header1 = 0;
+    }
+
+  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+    if (in)
+      {
+       for (ain = rn->adj_in; ain; ain = ain->next)
+         if (ain->peer == peer)
+           {
+             if (header1)
+               {
+                 vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                 vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
+                 vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+                 header1 = 0;
+               }
+             if (header2)
+               {
+                 vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
+                 header2 = 0;
+               }
+             if (ain->attr)
+               { 
+                 route_vty_out_tmp (vty, &rn->p, ain->attr, safi);
+                 output_count++;
+               }
+           }
+      }
+    else
+      {
+       for (adj = rn->adj_out; adj; adj = adj->next)
+         if (adj->peer == peer)
+           {
+             if (header1)
+               {
+                 vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                 vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
+                 vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+                 header1 = 0;
+               }
+             if (header2)
+               {
+                 vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
+                 header2 = 0;
+               }
+             if (adj->attr)
+               {       
+                 route_vty_out_tmp (vty, &rn->p, adj->attr, safi);
+                 output_count++;
+               }
+           }
+      }
+  
+  if (output_count != 0)
+    vty_out (vty, "%sTotal number of prefixes %ld%s",
+            VTY_NEWLINE, output_count, VTY_NEWLINE);
+}
+
+int
+peer_adj_routes (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, int in)
+{
+  int ret;
+  struct peer *peer;
+  union sockunion su;
+
+  ret = str2sockunion (ip_str, &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[afi][safi])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (in && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+    {
+      vty_out (vty, "%% Inbound soft reconfiguration not enabled%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  show_adj_route (vty, peer, afi, safi, in);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_neighbor_advertised_route,
+       show_ip_bgp_neighbor_advertised_route_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 0);
+}
+
+DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route,
+       show_ip_bgp_ipv4_neighbor_advertised_route_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 0);
+
+  return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 0);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_neighbor_advertised_route,
+       show_bgp_neighbor_advertised_route_cmd,
+       "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+       SHOW_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0);
+}
+
+ALIAS (show_bgp_neighbor_advertised_route,
+       show_bgp_ipv6_neighbor_advertised_route_cmd,
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+/* old command */
+DEFUN (ipv6_bgp_neighbor_advertised_route,
+       ipv6_bgp_neighbor_advertised_route_cmd,
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0);
+}
+
+/* old command */
+DEFUN (ipv6_mbgp_neighbor_advertised_route,
+       ipv6_mbgp_neighbor_advertised_route_cmd,
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 0);
+}
+#endif /* HAVE_IPV6 */
+\f
+DEFUN (show_ip_bgp_neighbor_received_routes,
+       show_ip_bgp_neighbor_received_routes_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 1);
+}
+
+DEFUN (show_ip_bgp_ipv4_neighbor_received_routes,
+       show_ip_bgp_ipv4_neighbor_received_routes_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 1);
+
+  return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 1);
+}
+
+DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
+       show_ip_bgp_neighbor_received_prefix_filter_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+{
+  char name[BUFSIZ];
+  union sockunion *su;
+  struct peer *peer;
+  int count;
+
+  su = sockunion_str2su (argv[0]);
+  if (su == NULL)
+    return CMD_WARNING;
+
+  peer = peer_lookup (NULL, su);
+  if (! peer)
+    return CMD_WARNING;
+
+  sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST);
+  count =  prefix_bgp_show_prefix_list (NULL, AFI_IP, name);
+  if (count)
+    {
+      vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE);
+      prefix_bgp_show_prefix_list (vty, AFI_IP, name);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter,
+       show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+{
+  char name[BUFSIZ];
+  union sockunion *su;
+  struct peer *peer;
+  int count;
+
+  su = sockunion_str2su (argv[1]);
+  if (su == NULL)
+    return CMD_WARNING;
+
+  peer = peer_lookup (NULL, su);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (strncmp (argv[0], "m", 1) == 0)
+    {
+      sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST);
+      count =  prefix_bgp_show_prefix_list (NULL, AFI_IP, name);
+      if (count)
+       {
+         vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE);
+         prefix_bgp_show_prefix_list (vty, AFI_IP, name);
+       }
+    }
+  else 
+    {
+      sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST);
+      count =  prefix_bgp_show_prefix_list (NULL, AFI_IP, name);
+      if (count)
+       {
+         vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE);
+         prefix_bgp_show_prefix_list (vty, AFI_IP, name);
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_neighbor_received_routes,
+       show_bgp_neighbor_received_routes_cmd,
+       "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+       SHOW_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1);
+}
+
+ALIAS (show_bgp_neighbor_received_routes,
+       show_bgp_ipv6_neighbor_received_routes_cmd,
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFUN (show_bgp_neighbor_received_prefix_filter,
+       show_bgp_neighbor_received_prefix_filter_cmd,
+       "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+       SHOW_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+{
+  char name[BUFSIZ];
+  union sockunion *su;
+  struct peer *peer;
+  int count;
+
+  su = sockunion_str2su (argv[0]);
+  if (su == NULL)
+    return CMD_WARNING;
+
+  peer = peer_lookup (NULL, su);
+  if (! peer)
+    return CMD_WARNING;
+
+  sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST);
+  count =  prefix_bgp_show_prefix_list (NULL, AFI_IP6, name);
+  if (count)
+    {
+      vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE);
+      prefix_bgp_show_prefix_list (vty, AFI_IP6, name);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_bgp_neighbor_received_prefix_filter,
+       show_bgp_ipv6_neighbor_received_prefix_filter_cmd,
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+
+/* old command */
+DEFUN (ipv6_bgp_neighbor_received_routes,
+       ipv6_bgp_neighbor_received_routes_cmd,
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1);
+}
+
+/* old command */
+DEFUN (ipv6_mbgp_neighbor_received_routes,
+       ipv6_mbgp_neighbor_received_routes_cmd,
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+{
+  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 1);
+}
+#endif /* HAVE_IPV6 */
+\f
+void
+bgp_show_neighbor_route_clean (struct vty *vty)
+{
+  union sockunion *su;
+
+  su = vty->output_arg;
+  XFREE (MTYPE_SOCKUNION, su);
+}
+
+int
+bgp_show_neighbor_route (struct vty *vty, char *ip_str, afi_t afi,
+                        safi_t safi, enum bgp_show_type type)
+{
+  union sockunion *su;
+  struct peer *peer;
+
+  su = sockunion_str2su (ip_str);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE);
+              return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[afi][safi])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      XFREE (MTYPE_SOCKUNION, su);
+      return CMD_WARNING;
+    }
+  vty->output_arg = su;
+  vty->output_clean = bgp_show_neighbor_route_clean;
+
+  return bgp_show (vty, NULL, afi, safi, type);
+}
+
+DEFUN (show_ip_bgp_neighbor_routes,
+       show_ip_bgp_neighbor_routes_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                 bgp_show_type_neighbor);
+}
+
+DEFUN (show_ip_bgp_neighbor_flap,
+       show_ip_bgp_neighbor_flap_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display flap statistics of the routes learned from neighbor\n")
+{
+  return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                 bgp_show_type_flap_neighbor);
+}
+
+DEFUN (show_ip_bgp_neighbor_damp,
+       show_ip_bgp_neighbor_damp_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the dampened routes received from neighbor\n")
+{
+  return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST,
+                                 bgp_show_type_damp_neighbor);
+}
+
+DEFUN (show_ip_bgp_ipv4_neighbor_routes,
+       show_ip_bgp_ipv4_neighbor_routes_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_MULTICAST,
+                                   bgp_show_type_neighbor);
+
+  return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_UNICAST,
+                                 bgp_show_type_neighbor);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_neighbor_routes,
+       show_bgp_neighbor_routes_cmd,
+       "show bgp neighbors (A.B.C.D|X:X::X:X) routes",
+       SHOW_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                                 bgp_show_type_neighbor);
+}
+
+ALIAS (show_bgp_neighbor_routes,
+       show_bgp_ipv6_neighbor_routes_cmd,
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+/* old command */
+DEFUN (ipv6_bgp_neighbor_routes,
+       ipv6_bgp_neighbor_routes_cmd,
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+                                 bgp_show_type_neighbor);
+}
+
+/* old command */
+DEFUN (ipv6_mbgp_neighbor_routes,
+       ipv6_mbgp_neighbor_routes_cmd,
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_MULTICAST,
+                                 bgp_show_type_neighbor);
+}
+#endif /* HAVE_IPV6 */
+\f
+struct bgp_table *bgp_distance_table;
+
+struct bgp_distance
+{
+  /* Distance value for the IP source prefix. */
+  u_char distance;
+
+  /* Name of the access-list to be matched. */
+  char *access_list;
+};
+
+struct bgp_distance *
+bgp_distance_new ()
+{
+  struct bgp_distance *new;
+  new = XMALLOC (MTYPE_BGP_DISTANCE, sizeof (struct bgp_distance));
+  memset (new, 0, sizeof (struct bgp_distance));
+  return new;
+}
+
+void
+bgp_distance_free (struct bgp_distance *bdistance)
+{
+  XFREE (MTYPE_BGP_DISTANCE, bdistance);
+}
+
+int
+bgp_distance_set (struct vty *vty, char *distance_str, char *ip_str,
+                 char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct bgp_node *rn;
+  struct bgp_distance *bdistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  /* Get BGP distance node. */
+  rn = bgp_node_get (bgp_distance_table, (struct prefix *) &p);
+  if (rn->info)
+    {
+      bdistance = rn->info;
+      bgp_unlock_node (rn);
+    }
+  else
+    {
+      bdistance = bgp_distance_new ();
+      rn->info = bdistance;
+    }
+
+  /* Set distance value. */
+  bdistance->distance = distance;
+
+  /* Reset access-list configuration. */
+  if (bdistance->access_list)
+    {
+      free (bdistance->access_list);
+      bdistance->access_list = NULL;
+    }
+  if (access_list_str)
+    bdistance->access_list = strdup (access_list_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+bgp_distance_unset (struct vty *vty, char *distance_str, char *ip_str,
+                   char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct bgp_node *rn;
+  struct bgp_distance *bdistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  rn = bgp_node_lookup (bgp_distance_table, (struct prefix *)&p);
+  if (! rn)
+    {
+      vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bdistance = rn->info;
+
+  if (bdistance->access_list)
+    free (bdistance->access_list);
+  bgp_distance_free (bdistance);
+
+  rn->info = NULL;
+  bgp_unlock_node (rn);
+  bgp_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+bgp_distance_reset ()
+{
+  struct bgp_node *rn;
+  struct bgp_distance *bdistance;
+
+  for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn))
+    if ((bdistance = rn->info) != NULL)
+      {
+       if (bdistance->access_list)
+         free (bdistance->access_list);
+       bgp_distance_free (bdistance);
+       rn->info = NULL;
+       bgp_unlock_node (rn);
+      }
+}
+
+/* Apply BGP information to distance method. */
+u_char
+bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp)
+{
+  struct bgp_node *rn;
+  struct prefix_ipv4 q;
+  struct peer *peer;
+  struct bgp_distance *bdistance;
+  struct access_list *alist;
+  struct bgp_static *bgp_static;
+
+  if (! bgp)
+    return 0;
+
+  if (p->family != AF_INET)
+    return 0;
+
+  peer = rinfo->peer;
+
+  if (peer->su.sa.sa_family != AF_INET)
+    return 0;
+
+  memset (&q, 0, sizeof (struct prefix_ipv4));
+  q.family = AF_INET;
+  q.prefix = peer->su.sin.sin_addr;
+  q.prefixlen = IPV4_MAX_BITLEN;
+
+  /* Check source address. */
+  rn = bgp_node_match (bgp_distance_table, (struct prefix *) &q);
+  if (rn)
+    {
+      bdistance = rn->info;
+      bgp_unlock_node (rn);
+
+      if (bdistance->access_list)
+       {
+         alist = access_list_lookup (AFI_IP, bdistance->access_list);
+         if (alist && access_list_apply (alist, p) == FILTER_PERMIT)
+           return bdistance->distance;
+       }
+      else
+       return bdistance->distance;
+    }
+
+  /* Backdoor check. */
+  rn = bgp_node_lookup (bgp->route[AFI_IP][SAFI_UNICAST], p);
+  if (rn)
+    {
+      bgp_static = rn->info;
+      bgp_unlock_node (rn);
+
+      if (bgp_static->backdoor)
+       {
+         if (bgp->distance_local)
+           return bgp->distance_local;
+         else
+           return ZEBRA_IBGP_DISTANCE_DEFAULT;
+       }
+    }
+
+  if (peer_sort (peer) == BGP_PEER_EBGP)
+    {
+      if (bgp->distance_ebgp)
+       return bgp->distance_ebgp;
+      return ZEBRA_EBGP_DISTANCE_DEFAULT;
+    }
+  else
+    {
+      if (bgp->distance_ibgp)
+       return bgp->distance_ibgp;
+      return ZEBRA_IBGP_DISTANCE_DEFAULT;
+    }
+}
+
+DEFUN (bgp_distance,
+       bgp_distance_cmd,
+       "distance bgp <1-255> <1-255> <1-255>",
+       "Define an administrative distance\n"
+       "BGP distance\n"
+       "Distance for routes external to the AS\n"
+       "Distance for routes internal to the AS\n"
+       "Distance for local routes\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+
+  bgp->distance_ebgp = atoi (argv[0]);
+  bgp->distance_ibgp = atoi (argv[1]);
+  bgp->distance_local = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_distance,
+       no_bgp_distance_cmd,
+       "no distance bgp <1-255> <1-255> <1-255>",
+       NO_STR
+       "Define an administrative distance\n"
+       "BGP distance\n"
+       "Distance for routes external to the AS\n"
+       "Distance for routes internal to the AS\n"
+       "Distance for local routes\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+
+  bgp->distance_ebgp= 0;
+  bgp->distance_ibgp = 0;
+  bgp->distance_local = 0;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_distance,
+       no_bgp_distance2_cmd,
+       "no distance bgp",
+       NO_STR
+       "Define an administrative distance\n"
+       "BGP distance\n")
+
+DEFUN (bgp_distance_source,
+       bgp_distance_source_cmd,
+       "distance <1-255> A.B.C.D/M",
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n")
+{
+  bgp_distance_set (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_distance_source,
+       no_bgp_distance_source_cmd,
+       "no distance <1-255> A.B.C.D/M",
+       NO_STR
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n")
+{
+  bgp_distance_unset (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (bgp_distance_source_access_list,
+       bgp_distance_source_access_list_cmd,
+       "distance <1-255> A.B.C.D/M WORD",
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  bgp_distance_set (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_distance_source_access_list,
+       no_bgp_distance_source_access_list_cmd,
+       "no distance <1-255> A.B.C.D/M WORD",
+       NO_STR
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  bgp_distance_unset (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+\f
+DEFUN (bgp_damp_set,
+       bgp_damp_set_cmd,
+       "bgp dampening <1-45> <1-20000> <1-20000> <1-255>",
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n"
+       "Half-life time for the penalty\n"
+       "Value to start reusing a route\n"
+       "Value to start suppressing a route\n"
+       "Maximum duration to suppress a stable route\n")
+{
+  struct bgp *bgp;
+  int half = DEFAULT_HALF_LIFE * 60;
+  int reuse = DEFAULT_REUSE;
+  int suppress = DEFAULT_SUPPRESS;
+  int max = 4 * half;
+
+  if (argc == 4)
+    {
+      half = atoi (argv[0]) * 60;
+      reuse = atoi (argv[1]);
+      suppress = atoi (argv[2]);
+      max = atoi (argv[3]) * 60;
+    }
+  else if (argc == 1)
+    {
+      half = atoi (argv[0]) * 60;
+      max = 4 * half;
+    }
+
+  bgp = vty->index;
+  return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty),
+                         half, reuse, suppress, max);
+}
+
+ALIAS (bgp_damp_set,
+       bgp_damp_set2_cmd,
+       "bgp dampening <1-45>",
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n"
+       "Half-life time for the penalty\n")
+
+ALIAS (bgp_damp_set,
+       bgp_damp_set3_cmd,
+       "bgp dampening",
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n")
+
+DEFUN (bgp_damp_unset,
+       bgp_damp_unset_cmd,
+       "no bgp dampening",
+       NO_STR
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  return bgp_damp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty));
+}
+
+ALIAS (bgp_damp_unset,
+       bgp_damp_unset2_cmd,
+       "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>",
+       NO_STR
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n"
+       "Half-life time for the penalty\n"
+       "Value to start reusing a route\n"
+       "Value to start suppressing a route\n"
+       "Maximum duration to suppress a stable route\n")
+
+DEFUN (show_ip_bgp_dampened_paths,
+       show_ip_bgp_dampened_paths_cmd,
+       "show ip bgp dampened-paths",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display paths suppressed due to dampening\n")
+{
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths);
+}
+
+DEFUN (show_ip_bgp_flap_statistics,
+       show_ip_bgp_flap_statistics_cmd,
+       "show ip bgp flap-statistics",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display flap statistics of routes\n")
+{
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_statistics);
+}
+\f
+/* Display specified route of BGP table. */
+int
+bgp_clear_damp_route (struct vty *vty, char *view_name, char *ip_str,
+                     afi_t afi, safi_t safi, struct prefix_rd *prd,
+                     int prefix_check)
+{
+  int ret;
+  struct prefix match;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp_info *ri;
+  struct bgp_info *ri_temp;
+  struct bgp *bgp;
+  struct bgp_table *table;
+
+  /* BGP structure lookup. */
+  if (view_name)
+    {
+      bgp = bgp_lookup_by_name (view_name);
+      if (bgp == NULL)
+       {
+         vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+       {
+         vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+
+  /* Check IP address argument. */
+  ret = str2prefix (ip_str, &match);
+  if (! ret)
+    {
+      vty_out (vty, "%% address is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  match.family = afi2family (afi);
+
+  if (safi == SAFI_MPLS_VPN)
+    {
+      for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn))
+        {
+          if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+            continue;
+
+         if ((table = rn->info) != NULL)
+           if ((rm = bgp_node_match (table, &match)) != NULL)
+             if (! prefix_check || rm->p.prefixlen == match.prefixlen)
+               {
+                 ri = rm->info;
+                 while (ri)
+                   {
+                     if (ri->damp_info)
+                       {
+                         ri_temp = ri->next;
+                         bgp_damp_info_free (ri->damp_info, 1);
+                         ri = ri_temp;
+                       }
+                     else
+                       ri = ri->next;
+                   }
+               }
+        }
+    }
+  else
+    {
+      if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL)
+       if (! prefix_check || rn->p.prefixlen == match.prefixlen)
+         {
+           ri = rn->info;
+           while (ri)
+             {
+               if (ri->damp_info)
+                 {
+                   ri_temp = ri->next;
+                   bgp_damp_info_free (ri->damp_info, 1);
+                   ri = ri_temp;
+                 }
+               else
+                 ri = ri->next;
+             }
+         }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (clear_ip_bgp_dampening,
+       clear_ip_bgp_dampening_cmd,
+       "clear ip bgp dampening",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear route flap dampening information\n")
+{
+  bgp_damp_info_clean ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (clear_ip_bgp_dampening_prefix,
+       clear_ip_bgp_dampening_prefix_cmd,
+       "clear ip bgp dampening A.B.C.D/M",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear route flap dampening information\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP,
+                              SAFI_UNICAST, NULL, 1);
+}
+
+DEFUN (clear_ip_bgp_dampening_address,
+       clear_ip_bgp_dampening_address_cmd,
+       "clear ip bgp dampening A.B.C.D",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear route flap dampening information\n"
+       "Network to clear damping information\n")
+{
+  return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP,
+                              SAFI_UNICAST, NULL, 0);
+}
+
+DEFUN (clear_ip_bgp_dampening_address_mask,
+       clear_ip_bgp_dampening_address_mask_cmd,
+       "clear ip bgp dampening A.B.C.D A.B.C.D",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear route flap dampening information\n"
+       "Network to clear damping information\n"
+       "Network mask\n")
+{
+  int ret;
+  char prefix_str[BUFSIZ];
+
+  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
+  if (! ret)
+    {
+      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP,
+                              SAFI_UNICAST, NULL, 0);
+}
+\f
+int
+bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,
+                               afi_t afi, safi_t safi, int *write)
+{
+  struct bgp_node *prn;
+  struct bgp_node *rn;
+  struct bgp_table *table;
+  struct prefix *p;
+  struct prefix_rd *prd;
+  struct bgp_static *bgp_static;
+  u_int32_t label;
+  char buf[SU_ADDRSTRLEN];
+  char rdbuf[RD_ADDRSTRLEN];
+  
+  /* Network configuration. */
+  for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn))
+    if ((table = prn->info) != NULL)
+      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) 
+       if ((bgp_static = rn->info) != NULL)
+         {
+           p = &rn->p;
+           prd = (struct prefix_rd *) &prn->p;
+
+           /* "address-family" display.  */
+           bgp_config_write_family_header (vty, afi, safi, write);
+
+           /* "network" configuration display.  */
+           prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN);
+           label = decode_label (bgp_static->tag);
+
+           vty_out (vty, " network %s/%d rd %s tag %d",
+                    inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), 
+                    p->prefixlen,
+                    rdbuf, label);
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+  return 0;
+}
+
+/* Configuration of static route announcement and aggregate
+   information. */
+int
+bgp_config_write_network (struct vty *vty, struct bgp *bgp,
+                         afi_t afi, safi_t safi, int *write)
+{
+  struct bgp_node *rn;
+  struct prefix *p;
+  struct bgp_static *bgp_static;
+  struct bgp_aggregate *bgp_aggregate;
+  char buf[SU_ADDRSTRLEN];
+  
+  if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
+    return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write);
+
+  /* Network configuration. */
+  for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) 
+    if ((bgp_static = rn->info) != NULL)
+      {
+       p = &rn->p;
+
+       /* "address-family" display.  */
+       bgp_config_write_family_header (vty, afi, safi, write);
+
+       /* "network" configuration display.  */
+       if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP)
+         {
+           u_int32_t destination; 
+           struct in_addr netmask;
+
+           destination = ntohl (p->u.prefix4.s_addr);
+           masklen2ip (p->prefixlen, &netmask);
+           vty_out (vty, " network %s",
+                    inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN));
+
+           if ((IN_CLASSC (destination) && p->prefixlen == 24)
+               || (IN_CLASSB (destination) && p->prefixlen == 16)
+               || (IN_CLASSA (destination) && p->prefixlen == 8)
+               || p->u.prefix4.s_addr == 0)
+             {
+               /* Natural mask is not display. */
+             }
+           else
+             vty_out (vty, " mask %s", inet_ntoa (netmask));
+         }
+       else
+         {
+           vty_out (vty, " network %s/%d",
+                    inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), 
+                    p->prefixlen);
+         }
+
+       if (bgp_static->rmap.name)
+         vty_out (vty, " route-map %s", bgp_static->rmap.name);
+       else if (bgp_static->backdoor)
+         vty_out (vty, " backdoor");
+
+       vty_out (vty, "%s", VTY_NEWLINE);
+      }
+
+  /* Aggregate-address configuration. */
+  for (rn = bgp_table_top (bgp->aggregate[afi][safi]); rn; rn = bgp_route_next (rn))
+    if ((bgp_aggregate = rn->info) != NULL)
+      {
+       p = &rn->p;
+
+       /* "address-family" display.  */
+       bgp_config_write_family_header (vty, afi, safi, write);
+
+       if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP)
+         {
+           struct in_addr netmask;
+
+           masklen2ip (p->prefixlen, &netmask);
+           vty_out (vty, " aggregate-address %s %s",
+                    inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+                    inet_ntoa (netmask));
+         }
+       else
+         {
+           vty_out (vty, " aggregate-address %s/%d",
+                    inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+                    p->prefixlen);
+         }
+
+       if (bgp_aggregate->as_set)
+         vty_out (vty, " as-set");
+       
+       if (bgp_aggregate->summary_only)
+         vty_out (vty, " summary-only");
+
+       vty_out (vty, "%s", VTY_NEWLINE);
+      }
+
+  return 0;
+}
+
+int
+bgp_config_write_distance (struct vty *vty, struct bgp *bgp)
+{
+  struct bgp_node *rn;
+  struct bgp_distance *bdistance;
+
+  /* Distance configuration. */
+  if (bgp->distance_ebgp
+      && bgp->distance_ibgp
+      && bgp->distance_local
+      && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT
+         || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT
+         || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT))
+    vty_out (vty, " distance bgp %d %d %d%s",
+            bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local,
+            VTY_NEWLINE);
+  
+  for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn))
+    if ((bdistance = rn->info) != NULL)
+      {
+       vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance,
+                inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+                bdistance->access_list ? bdistance->access_list : "",
+                VTY_NEWLINE);
+      }
+
+  return 0;
+}
+
+/* Allocate routing table structure and install commands. */
+void
+bgp_route_init ()
+{
+  /* Init BGP distance table. */
+  bgp_distance_table = bgp_table_init ();
+
+  /* IPv4 BGP commands. */
+  install_element (BGP_NODE, &bgp_network_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_natural_cmd);
+  install_element (BGP_NODE, &bgp_network_route_map_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_route_map_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_NODE, &bgp_network_backdoor_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
+  install_element (BGP_NODE, &no_bgp_network_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd);
+  install_element (BGP_NODE, &no_bgp_network_route_map_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_NODE, &no_bgp_network_backdoor_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd);
+
+  install_element (BGP_NODE, &aggregate_address_cmd);
+  install_element (BGP_NODE, &aggregate_address_mask_cmd);
+  install_element (BGP_NODE, &aggregate_address_summary_only_cmd);
+  install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd);
+  install_element (BGP_NODE, &aggregate_address_as_set_cmd);
+  install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd);
+  install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd);
+  install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd);
+  install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd);
+  install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_as_set_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_mask_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd);
+  install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
+
+  /* IPv4 unicast configuration.  */
+  install_element (BGP_IPV4_NODE, &bgp_network_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
+
+  /* IPv4 multicast configuration.  */
+  install_element (BGP_IPV4M_NODE, &bgp_network_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
+
+  install_element (VIEW_NODE, &show_ip_bgp_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_view_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community2_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community3_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community4_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd);
+
+  install_element (ENABLE_NODE, &show_ip_bgp_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_view_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd);
+
+ /* BGP dampening clear commands */
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);
+
+#ifdef HAVE_IPV6
+  /* New config IPv6 BGP commands.  */
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd);
+
+  install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
+  install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd);
+
+  /* Old config IPv6 BGP commands.  */
+  install_element (BGP_NODE, &old_ipv6_bgp_network_cmd);
+  install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd);
+
+  install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd);
+  install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd);
+  install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd);
+  install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd);
+
+  install_element (VIEW_NODE, &show_bgp_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
+  install_element (VIEW_NODE, &show_bgp_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_regexp_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd);
+  install_element (VIEW_NODE, &show_bgp_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_filter_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_route_map_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd);
+  install_element (VIEW_NODE, &show_bgp_community_all_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd);
+  install_element (VIEW_NODE, &show_bgp_community_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd);
+  install_element (VIEW_NODE, &show_bgp_community2_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd);
+  install_element (VIEW_NODE, &show_bgp_community3_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd);
+  install_element (VIEW_NODE, &show_bgp_community4_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd);
+  install_element (VIEW_NODE, &show_bgp_community_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_community2_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_community3_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_community4_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_community_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd);
+
+  install_element (ENABLE_NODE, &show_bgp_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_cmd);
+  install_element (ENABLE_NODE, &show_bgp_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_regexp_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd);
+  install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_bgp_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_bgp_route_map_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community_all_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community2_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community3_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community4_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community_list_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd);
+  install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd);
+  install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd);
+
+  /* old command */
+  install_element (VIEW_NODE, &show_ipv6_bgp_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd);
+
+  /* old command */
+  install_element (ENABLE_NODE, &show_ipv6_bgp_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd);
+
+  /* old command */
+  install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd);
+  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd);
+  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd);
+  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd);
+
+  /* old command */
+  install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd);
+  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd);
+
+  /* old command */
+  install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd);
+#endif /* HAVE_IPV6 */
+
+  install_element (BGP_NODE, &bgp_distance_cmd);
+  install_element (BGP_NODE, &no_bgp_distance_cmd);
+  install_element (BGP_NODE, &no_bgp_distance2_cmd);
+  install_element (BGP_NODE, &bgp_distance_source_cmd);
+  install_element (BGP_NODE, &no_bgp_distance_source_cmd);
+  install_element (BGP_NODE, &bgp_distance_source_access_list_cmd);
+  install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd);
+
+  install_element (BGP_NODE, &bgp_damp_set_cmd);
+  install_element (BGP_NODE, &bgp_damp_set2_cmd);
+  install_element (BGP_NODE, &bgp_damp_set3_cmd);
+  install_element (BGP_NODE, &bgp_damp_unset_cmd);
+  install_element (BGP_NODE, &bgp_damp_unset2_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd);
+}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
new file mode 100644 (file)
index 0000000..a11aa14
--- /dev/null
@@ -0,0 +1,159 @@
+/* BGP routing information base
+   Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+struct bgp_info
+{
+  /* For linked list. */
+  struct bgp_info *next;
+  struct bgp_info *prev;
+
+  /* BGP route type.  This can be static, RIP, OSPF, BGP etc.  */
+  u_char type;
+
+  /* When above type is BGP.  This sub type specify BGP sub type
+     information.  */
+  u_char sub_type;
+#define BGP_ROUTE_NORMAL       0
+#define BGP_ROUTE_STATIC       1
+#define BGP_ROUTE_AGGREGATE    2
+#define BGP_ROUTE_REDISTRIBUTE 3 
+
+  /* BGP information status.  */
+  u_char flags;
+#define BGP_INFO_IGP_CHANGED    (1 << 0)
+#define BGP_INFO_DAMPED         (1 << 1)
+#define BGP_INFO_HISTORY        (1 << 2)
+#define BGP_INFO_SELECTED       (1 << 3)
+#define BGP_INFO_VALID          (1 << 4)
+#define BGP_INFO_ATTR_CHANGED   (1 << 5)
+#define BGP_INFO_DMED_CHECK     (1 << 6)
+#define BGP_INFO_DMED_SELECTED  (1 << 7)
+
+  /* Peer structure.  */
+  struct peer *peer;
+
+  /* Attribute structure.  */
+  struct attr *attr;
+
+  /* This route is suppressed with aggregation.  */
+  int suppress;
+  
+  /* Nexthop reachability check.  */
+  u_int32_t igpmetric;
+
+  /* Uptime.  */
+  time_t uptime;
+
+  /* Pointer to dampening structure.  */
+  struct bgp_damp_info *damp_info;
+
+  /* MPLS label.  */
+  u_char tag[3];
+};
+
+/* BGP static route configuration. */
+struct bgp_static
+{
+  /* Backdoor configuration.  */
+  int backdoor;
+
+  /* Import check status.  */
+  u_char valid;
+
+  /* IGP metric. */
+  u_int32_t igpmetric;
+
+  /* IGP nexthop. */
+  struct in_addr igpnexthop;
+
+  /* BGP redistribute route-map.  */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } rmap;
+
+  /* MPLS label.  */
+  u_char tag[3];
+};
+
+#define DISTRIBUTE_IN_NAME(F)   ((F)->dlist[FILTER_IN].name)
+#define DISTRIBUTE_IN(F)        ((F)->dlist[FILTER_IN].alist)
+#define DISTRIBUTE_OUT_NAME(F)  ((F)->dlist[FILTER_OUT].name)
+#define DISTRIBUTE_OUT(F)       ((F)->dlist[FILTER_OUT].alist)
+
+#define PREFIX_LIST_IN_NAME(F)  ((F)->plist[FILTER_IN].name)
+#define PREFIX_LIST_IN(F)       ((F)->plist[FILTER_IN].plist)
+#define PREFIX_LIST_OUT_NAME(F) ((F)->plist[FILTER_OUT].name)
+#define PREFIX_LIST_OUT(F)      ((F)->plist[FILTER_OUT].plist)
+
+#define FILTER_LIST_IN_NAME(F)  ((F)->aslist[FILTER_IN].name)
+#define FILTER_LIST_IN(F)       ((F)->aslist[FILTER_IN].aslist)
+#define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name)
+#define FILTER_LIST_OUT(F)      ((F)->aslist[FILTER_OUT].aslist)
+
+#define ROUTE_MAP_IN_NAME(F)    ((F)->map[FILTER_IN].name)
+#define ROUTE_MAP_IN(F)         ((F)->map[FILTER_IN].map)
+#define ROUTE_MAP_OUT_NAME(F)   ((F)->map[FILTER_OUT].name)
+#define ROUTE_MAP_OUT(F)        ((F)->map[FILTER_OUT].map)
+
+#define UNSUPPRESS_MAP_NAME(F)  ((F)->usmap.name)
+#define UNSUPPRESS_MAP(F)       ((F)->usmap.map)
+
+/* Prototypes. */
+void bgp_route_init ();
+void bgp_announce_route (struct peer *, afi_t, safi_t);
+void bgp_announce_route_all (struct peer *);
+void bgp_default_originate (struct peer *, afi_t, safi_t, int);
+void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t);
+void bgp_clear_route (struct peer *, afi_t, safi_t);
+void bgp_clear_route_all (struct peer *);
+void bgp_clear_adj_in (struct peer *, afi_t, safi_t);
+
+int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t);
+int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
+
+int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t);
+
+void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char);
+void bgp_redistribute_delete (struct prefix *, u_char);
+void bgp_redistribute_withdraw (struct bgp *, afi_t, int);
+
+void bgp_static_delete (struct bgp *);
+void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *,
+                       afi_t, safi_t);
+void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t);
+                     
+int bgp_static_set_vpnv4 (struct vty *vty, char *, char *, char *);
+
+int bgp_static_unset_vpnv4 (struct vty *, char *, char *, char *);
+
+int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *);
+int bgp_config_write_distance (struct vty *, struct bgp *);
+
+void bgp_aggregate_increment (struct bgp *, struct prefix *, struct bgp_info *,
+                             afi_t, safi_t);
+void bgp_aggregate_decrement (struct bgp *, struct prefix *, struct bgp_info *,
+                             afi_t, safi_t);
+
+u_char bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *);
+
+afi_t bgp_node_afi (struct vty *);
+safi_t bgp_node_safi (struct vty *);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
new file mode 100644 (file)
index 0000000..498a600
--- /dev/null
@@ -0,0 +1,3207 @@
+/* Route map function of bgpd.
+   Copyright (C) 1998, 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "routemap.h"
+#include "command.h"
+#include "linklist.h"
+#include "plist.h"
+#include "memory.h"
+#include "log.h"
+#ifdef HAVE_GNU_REGEX
+#include <regex.h>
+#else
+#include "regex-gnu.h"
+#endif /* HAVE_GNU_REGEX */
+#include "buffer.h"
+#include "sockunion.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_ecommunity.h"
+
+/* Memo of route-map commands.
+
+o Cisco route-map
+
+ match as-path          :  Done
+       community        :  Done
+       interface        :  Not yet
+       ip address       :  Done
+       ip next-hop      :  Done
+       ip route-source  :  (This will not be implemented by bgpd)
+       ip prefix-list   :  Done
+       ipv6 address     :  Done
+       ipv6 next-hop    :  Done
+       ipv6 route-source:  (This will not be implemented by bgpd)
+       ipv6 prefix-list :  Done
+       length           :  (This will not be implemented by bgpd)
+       metric           :  Done
+       route-type       :  (This will not be implemented by bgpd)
+       tag              :  (This will not be implemented by bgpd)
+
+ set  as-path prepend   :  Done
+      as-path tag       :  Not yet
+      automatic-tag     :  (This will not be implemented by bgpd)
+      community         :  Done
+      comm-list         :  Not yet
+      dampning          :  Not yet
+      default           :  (This will not be implemented by bgpd)
+      interface         :  (This will not be implemented by bgpd)
+      ip default        :  (This will not be implemented by bgpd)
+      ip next-hop       :  Done
+      ip precedence     :  (This will not be implemented by bgpd)
+      ip tos            :  (This will not be implemented by bgpd)
+      level             :  (This will not be implemented by bgpd)
+      local-preference  :  Done
+      metric            :  Done
+      metric-type       :  Not yet
+      origin            :  Done
+      tag               :  (This will not be implemented by bgpd)
+      weight            :  Done
+
+o Local extention
+
+  set ipv6 next-hop global: Done
+  set ipv6 next-hop local : Done
+
+*/ 
+\f
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+   zero. */
+route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix, 
+                       route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  /* struct prefix_ipv4 match; */
+
+  if (type == RMAP_BGP)
+    {
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+       return RMAP_NOMATCH;
+    
+      return (access_list_apply (alist, prefix) == FILTER_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement.  `arg' should be
+   access-list name. */
+void *
+route_match_ip_address_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_address_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+  "ip address",
+  route_match_ip_address,
+  route_match_ip_address_compile,
+  route_match_ip_address_free
+};
+\f
+/* `match ip next-hop IP_ADDRESS' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_next_hop (void *rule, struct prefix *prefix, 
+                        route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  struct bgp_info *bgp_info;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      p.family = AF_INET;
+      p.prefix = bgp_info->attr->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+       return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, &p) == FILTER_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement. `arg' is
+   access-list name. */
+void *
+route_match_ip_next_hop_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_next_hop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+{
+  "ip next-hop",
+  route_match_ip_next_hop,
+  route_match_ip_next_hop_compile,
+  route_match_ip_next_hop_free
+};
+\f
+/* `match ip address prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, 
+                                   route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+
+  if (type == RMAP_BGP)
+    {
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+       return RMAP_NOMATCH;
+    
+      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_address_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+  "ip address prefix-list",
+  route_match_ip_address_prefix_list,
+  route_match_ip_address_prefix_list_compile,
+  route_match_ip_address_prefix_list_free
+};
+\f
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+  struct bgp_info *bgp_info;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      p.family = AF_INET;
+      p.prefix = bgp_info->attr->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_next_hop_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+  "ip next-hop prefix-list",
+  route_match_ip_next_hop_prefix_list,
+  route_match_ip_next_hop_prefix_list_compile,
+  route_match_ip_next_hop_prefix_list_free
+};
+\f
+/* `match metric METRIC' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix, 
+                   route_map_object_t type, void *object)
+{
+  u_int32_t *med;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      med = rule;
+      bgp_info = object;
+    
+      if (bgp_info->attr->med == *med)
+       return RMAP_MATCH;
+      else
+       return RMAP_NOMATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is MED value */
+void *
+route_match_metric_compile (char *arg)
+{
+  u_int32_t *med;
+  char *endptr = NULL;
+
+  med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *med = strtoul (arg, &endptr, 10);
+  if (*endptr != '\0' || *med == ULONG_MAX)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, med);
+      return NULL;
+    }
+  return med;
+}
+
+/* Free route map's compiled `match metric' value. */
+void
+route_match_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+  "metric",
+  route_match_metric,
+  route_match_metric_compile,
+  route_match_metric_free
+};
+\f
+/* `match as-path ASPATH' */
+
+/* Match function for as-path match.  I assume given object is */
+route_map_result_t
+route_match_aspath (void *rule, struct prefix *prefix, 
+                   route_map_object_t type, void *object)
+{
+  
+  struct as_list *as_list;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      as_list = as_list_lookup ((char *) rule);
+      if (as_list == NULL)
+       return RMAP_NOMATCH;
+    
+      bgp_info = object;
+    
+      /* Perform match. */
+      return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Compile function for as-path match. */
+void *
+route_match_aspath_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Compile function for as-path match. */
+void
+route_match_aspath_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for aspath matching. */
+struct route_map_rule_cmd route_match_aspath_cmd = 
+{
+  "as-path",
+  route_match_aspath,
+  route_match_aspath_compile,
+  route_match_aspath_free
+};
+
+#if ROUTE_MATCH_ASPATH_OLD
+/* `match as-path ASPATH' */
+
+/* Match function for as-path match.  I assume given object is */
+int
+route_match_aspath (void *rule, struct prefix *prefix, void *object)
+{
+  regex_t *regex;
+  struct bgp_info *bgp_info;
+
+  regex = rule;
+  bgp_info = object;
+  
+  /* Perform match. */
+  return bgp_regexec (regex, bgp_info->attr->aspath);
+}
+
+/* Compile function for as-path match. */
+void *
+route_match_aspath_compile (char *arg)
+{
+  regex_t *regex;
+
+  regex = bgp_regcomp (arg);
+  if (! regex)
+    return NULL;
+
+  return regex;
+}
+
+/* Compile function for as-path match. */
+void
+route_match_aspath_free (void *rule)
+{
+  regex_t *regex = rule;
+
+  bgp_regex_free (regex);
+}
+
+/* Route map commands for aspath matching. */
+struct route_map_rule_cmd route_match_aspath_cmd = 
+{
+  "as-path",
+  route_match_aspath,
+  route_match_aspath_compile,
+  route_match_aspath_free
+};
+#endif /* ROUTE_MATCH_ASPATH_OLD */
+\f
+/* `match community COMMUNIY' */
+struct rmap_community
+{
+  char *name;
+  int exact;
+};
+
+/* Match function for community match. */
+route_map_result_t
+route_match_community (void *rule, struct prefix *prefix, 
+                      route_map_object_t type, void *object)
+{
+  struct community_list *list;
+  struct bgp_info *bgp_info;
+  struct rmap_community *rcom;
+
+  if (type == RMAP_BGP) 
+    {
+      bgp_info = object;
+      rcom = rule;
+
+      list = community_list_lookup (bgp_clist, rcom->name, COMMUNITY_LIST_AUTO);
+      if (! list)
+       return RMAP_NOMATCH;
+
+      if (rcom->exact)
+       {
+         if (community_list_exact_match (bgp_info->attr->community, list))
+           return RMAP_MATCH;
+       }
+      else
+       {
+         if (community_list_match (bgp_info->attr->community, list))
+           return RMAP_MATCH;
+       }
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Compile function for community match. */
+void *
+route_match_community_compile (char *arg)
+{
+  struct rmap_community *rcom;
+  int len;
+  char *p;
+
+  rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
+
+  p = strchr (arg, ' ');
+  if (p)
+    {
+      len = p - arg;
+      rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+      memcpy (rcom->name, arg, len);
+      rcom->exact = 1;
+    }
+  else
+    {
+      rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+      rcom->exact = 0;
+    }
+  return rcom;
+}
+
+/* Compile function for community match. */
+void
+route_match_community_free (void *rule)
+{
+  struct rmap_community *rcom = rule;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name); 
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
+}
+
+/* Route map commands for community matching. */
+struct route_map_rule_cmd route_match_community_cmd = 
+{
+  "community",
+  route_match_community,
+  route_match_community_compile,
+  route_match_community_free
+};
+\f
+/* `match nlri` and `set nlri` are replaced by `address-family ipv4`
+   and `address-family vpnv4'.  */
+\f
+/* `match origin' */
+route_map_result_t
+route_match_origin (void *rule, struct prefix *prefix, 
+                   route_map_object_t type, void *object)
+{
+  u_char *origin;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      origin = rule;
+      bgp_info = object;
+    
+      if (bgp_info->attr->origin == *origin)
+       return RMAP_MATCH;
+    }
+
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_origin_compile (char *arg)
+{
+  u_char *origin;
+
+  origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char));
+
+  if (strcmp (arg, "igp") == 0)
+    *origin = 0;
+  else if (strcmp (arg, "egp") == 0)
+    *origin = 1;
+  else
+    *origin = 2;
+
+  return origin;
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_origin_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for origin matching. */
+struct route_map_rule_cmd route_match_origin_cmd =
+{
+  "origin",
+  route_match_origin,
+  route_match_origin_compile,
+  route_match_origin_free
+};
+/* `set ip next-hop IP_ADDRESS' */
+
+/* Set nexthop to object.  ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ip_nexthop (void *rule, struct prefix *prefix,
+                     route_map_object_t type, void *object)
+{
+  struct in_addr *address;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      address = rule;
+      bgp_info = object;
+    
+      /* Set next hop value. */ 
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
+      bgp_info->attr->nexthop = *address;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function.  Given string is converted
+   to struct in_addr structure. */
+void *
+route_set_ip_nexthop_compile (char *arg)
+{
+  int ret;
+  struct in_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+  ret = inet_aton (arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_ip_nexthop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ip_nexthop_cmd =
+{
+  "ip next-hop",
+  route_set_ip_nexthop,
+  route_set_ip_nexthop_compile,
+  route_set_ip_nexthop_free
+};
+\f
+/* `set local-preference LOCAL_PREF' */
+
+/* Set local preference. */
+route_map_result_t
+route_set_local_pref (void *rule, struct prefix *prefix,
+                     route_map_object_t type, void *object)
+{
+  u_int32_t *local_pref;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      local_pref = rule;
+      bgp_info = object;
+    
+      /* Set local preference value. */ 
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
+      bgp_info->attr->local_pref = *local_pref;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* set local preference compilation. */
+void *
+route_set_local_pref_compile (char *arg)
+{
+  u_int32_t *local_pref;
+  char *endptr = NULL;
+
+  /* Local preference value shoud be integer. */
+  if (! all_digit (arg))
+    return NULL;
+
+  local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *local_pref = strtoul (arg, &endptr, 10);
+  if (*endptr != '\0' || *local_pref == ULONG_MAX)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, local_pref);
+      return NULL;
+    }
+  return local_pref;
+}
+
+/* Free route map's local preference value. */
+void
+route_set_local_pref_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set local preference rule structure. */
+struct route_map_rule_cmd route_set_local_pref_cmd = 
+{
+  "local-preference",
+  route_set_local_pref,
+  route_set_local_pref_compile,
+  route_set_local_pref_free,
+};
+\f
+/* `set weight WEIGHT' */
+
+/* Set weight. */
+route_map_result_t
+route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
+                 void *object)
+{
+  u_int32_t *weight;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      weight = rule;
+      bgp_info = object;
+    
+      /* Set weight value. */ 
+      bgp_info->attr->weight = *weight;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* set local preference compilation. */
+void *
+route_set_weight_compile (char *arg)
+{
+  u_int32_t *weight;
+  char *endptr = NULL;
+
+  /* Local preference value shoud be integer. */
+  if (! all_digit (arg))
+    return NULL;
+
+  weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *weight = strtoul (arg, &endptr, 10);
+  if (*endptr != '\0' || *weight == ULONG_MAX)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, weight);
+      return NULL;
+    }
+  return weight;
+}
+
+/* Free route map's local preference value. */
+void
+route_set_weight_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set local preference rule structure. */
+struct route_map_rule_cmd route_set_weight_cmd = 
+{
+  "weight",
+  route_set_weight,
+  route_set_weight_compile,
+  route_set_weight_free,
+};
+\f
+/* `set metric METRIC' */
+
+/* Set metric to attribute. */
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix, 
+                 route_map_object_t type, void *object)
+{
+  char *metric;
+  u_int32_t metric_val;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      metric = rule;
+      bgp_info = object;
+
+      if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)))
+       bgp_info->attr->med = 0;
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+
+      if (all_digit (metric))
+       {
+         metric_val = strtoul (metric, (char **)NULL, 10);
+         bgp_info->attr->med = metric_val;
+       }
+      else
+       {
+         metric_val = strtoul (metric+1, (char **)NULL, 10);
+
+         if (strncmp (metric, "+", 1) == 0)
+           {
+             if (bgp_info->attr->med/2 + metric_val/2 > ULONG_MAX/2)
+               bgp_info->attr->med = ULONG_MAX-1;
+             else
+               bgp_info->attr->med += metric_val;
+           }
+         else if (strncmp (metric, "-", 1) == 0)
+           {
+             if (bgp_info->attr->med <= metric_val) 
+               bgp_info->attr->med = 0;
+             else
+               bgp_info->attr->med -= metric_val;
+           }
+       }
+    }
+  return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+void *
+route_set_metric_compile (char *arg)
+{
+  u_int32_t metric;
+  char *endptr = NULL;
+
+  if (all_digit (arg))
+    {
+      /* set metric value check*/
+      metric = strtoul (arg, &endptr, 10);
+      if (*endptr != '\0' || metric == ULONG_MAX)
+        return NULL;
+    }
+  else
+    {
+      /* set metric +/-value check */
+      if ((strncmp (arg, "+", 1) != 0
+          && strncmp (arg, "-", 1) != 0)
+          || (! all_digit (arg+1)))
+       return NULL;
+
+      metric = strtoul (arg+1, &endptr, 10);
+      if (*endptr != '\0' || metric == ULONG_MAX)
+       return NULL;
+    }
+
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `set metric' value. */
+void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_cmd = 
+{
+  "metric",
+  route_set_metric,
+  route_set_metric_compile,
+  route_set_metric_free,
+};
+\f
+/* `set as-path prepend ASPATH' */
+
+/* For AS path prepend mechanism. */
+route_map_result_t
+route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t type, void *object)
+{
+  struct aspath *aspath;
+  struct aspath *new;
+  struct bgp_info *binfo;
+
+  if (type == RMAP_BGP)
+    {
+      aspath = rule;
+      binfo = object;
+    
+      if (binfo->attr->aspath->refcnt)
+       new = aspath_dup (binfo->attr->aspath);
+      else
+       new = binfo->attr->aspath;
+
+      aspath_prepend (aspath, new);
+      binfo->attr->aspath = new;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for as-path prepend. */
+void *
+route_set_aspath_prepend_compile (char *arg)
+{
+  struct aspath *aspath;
+
+  aspath = aspath_str2aspath (arg);
+  if (! aspath)
+    return NULL;
+  return aspath;
+}
+
+/* Compile function for as-path prepend. */
+void
+route_set_aspath_prepend_free (void *rule)
+{
+  struct aspath *aspath = rule;
+  aspath_free (aspath);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_aspath_prepend_cmd = 
+{
+  "as-path prepend",
+  route_set_aspath_prepend,
+  route_set_aspath_prepend_compile,
+  route_set_aspath_prepend_free,
+};
+\f
+/* `set community COMMUNITY' */
+struct rmap_com_set
+{
+  struct community *com;
+  int additive;
+  int none;
+};
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_community (void *rule, struct prefix *prefix,
+                    route_map_object_t type, void *object)
+{
+  struct rmap_com_set *rcs;
+  struct bgp_info *binfo;
+  struct attr *attr;
+  struct community *new = NULL;
+  struct community *old;
+  struct community *merge;
+
+  if (type == RMAP_BGP)
+    {
+      rcs = rule;
+      binfo = object;
+      attr = binfo->attr;
+      old = attr->community;
+
+      /* "none" case.  */
+      if (rcs->none)
+       {
+         attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
+         attr->community = NULL;
+         return RMAP_OKAY;
+       }
+
+      /* "additive" case.  */
+      if (rcs->additive && old)
+       {
+         merge = community_merge (community_dup (old), rcs->com);
+         new = community_uniq_sort (merge);
+         community_free (merge);
+       }
+      else
+       new = community_dup (rcs->com);
+
+      attr->community = new;
+      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_community_compile (char *arg)
+{
+  struct rmap_com_set *rcs;
+  struct community *com = NULL;
+  char *sp;
+  int additive = 0;
+  int none = 0;
+  
+  if (strcmp (arg, "none") == 0)
+    none = 1;
+  else
+    {
+      sp = strstr (arg, "additive");
+
+      if (sp && sp > arg)
+       {
+         /* "additive" keyworkd is included.  */
+         additive = 1;
+         *(sp - 1) = '\0';
+       }
+
+      com = community_str2com (arg);
+
+      if (additive)
+       *(sp - 1) = ' ';
+
+      if (! com)
+       return NULL;
+    }
+  
+  rcs = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set));
+  memset (rcs, 0, sizeof (struct rmap_com_set));
+  
+  rcs->com = com;
+  rcs->additive = additive;
+  rcs->none = none;
+  
+  return rcs;
+}
+
+/* Free function for set community. */
+void
+route_set_community_free (void *rule)
+{
+  struct rmap_com_set *rcs = rule;
+
+  if (rcs->com)
+    community_free (rcs->com);
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_community_cmd = 
+{
+  "community",
+  route_set_community,
+  route_set_community_compile,
+  route_set_community_free,
+};
+\f
+/* `set comm-list (<1-99>|<100-199>|WORD) delete' */
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_community_delete (void *rule, struct prefix *prefix,
+                           route_map_object_t type, void *object)
+{
+  struct community_list *list;
+  struct community *merge;
+  struct community *new;
+  struct community *old;
+  struct bgp_info *binfo;
+
+  if (type == RMAP_BGP)
+    {
+      if (! rule)
+       return RMAP_OKAY;
+
+      binfo = object;
+      list = community_list_lookup (bgp_clist, rule, COMMUNITY_LIST_AUTO);
+      old = binfo->attr->community;
+
+      if (list && old)
+       {
+         merge = community_list_match_delete (community_dup (old), list);
+         new = community_uniq_sort (merge);
+         community_free (merge);
+
+         if (new->size == 0)
+           {
+             binfo->attr->community = NULL;
+             binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+             community_free (new);
+           }
+         else
+           {
+             binfo->attr->community = new;
+             binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+           }
+       }
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_community_delete_compile (char *arg)
+{
+  char *p;
+  char *str;
+  int len;
+
+  p = strchr (arg, ' ');
+  if (p)
+    {
+      len = p - arg;
+      str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+      memcpy (str, arg, len);
+    }
+  else
+    str = NULL;
+
+  return str;
+}
+
+/* Free function for set community. */
+void
+route_set_community_delete_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_community_delete_cmd =
+{
+  "comm-list",
+  route_set_community_delete,
+  route_set_community_delete_compile,
+  route_set_community_delete_free,
+};
+\f
+/* `set extcommunity rt COMMUNITY' */
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_ecommunity_rt (void *rule, struct prefix *prefix, 
+                        route_map_object_t type, void *object)
+{
+  struct ecommunity *ecom;
+  struct ecommunity *new_ecom;
+  struct ecommunity *old_ecom;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      ecom = rule;
+      bgp_info = object;
+    
+      if (! ecom)
+       return RMAP_OKAY;
+    
+      /* We assume additive for Extended Community. */
+      old_ecom = bgp_info->attr->ecommunity;
+
+      if (old_ecom)
+       new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom);
+      else
+       new_ecom = ecommunity_dup (ecom);
+
+      bgp_info->attr->ecommunity = new_ecom;
+
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
+    }
+  return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_ecommunity_rt_compile (char *arg)
+{
+  struct ecommunity *ecom;
+
+  ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0);
+  if (! ecom)
+    return NULL;
+  return ecom;
+}
+
+/* Free function for set community. */
+void
+route_set_ecommunity_rt_free (void *rule)
+{
+  struct ecommunity *ecom = rule;
+  ecommunity_free (ecom);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_ecommunity_rt_cmd = 
+{
+  "extcommunity rt",
+  route_set_ecommunity_rt,
+  route_set_ecommunity_rt_compile,
+  route_set_ecommunity_rt_free,
+};
+
+/* `set extcommunity soo COMMUNITY' */
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_ecommunity_soo (void *rule, struct prefix *prefix, 
+                        route_map_object_t type, void *object)
+{
+  struct ecommunity *ecom;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      ecom = rule;
+      bgp_info = object;
+    
+      if (! ecom)
+       return RMAP_OKAY;
+    
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
+      bgp_info->attr->ecommunity = ecommunity_dup (ecom);
+    }
+  return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_ecommunity_soo_compile (char *arg)
+{
+  struct ecommunity *ecom;
+
+  ecom = ecommunity_str2com (arg, ECOMMUNITY_SITE_ORIGIN, 0);
+  if (! ecom)
+    return NULL;
+  
+  return ecom;
+}
+
+/* Free function for set community. */
+void
+route_set_ecommunity_soo_free (void *rule)
+{
+  struct ecommunity *ecom = rule;
+  ecommunity_free (ecom);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_ecommunity_soo_cmd = 
+{
+  "extcommunity soo",
+  route_set_ecommunity_soo,
+  route_set_ecommunity_soo_compile,
+  route_set_ecommunity_soo_free,
+};
+\f
+/* `set origin ORIGIN' */
+
+/* For origin set. */
+route_map_result_t
+route_set_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object)
+{
+  u_char *origin;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      origin = rule;
+      bgp_info = object;
+    
+      bgp_info->attr->origin = *origin;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for origin set. */
+void *
+route_set_origin_compile (char *arg)
+{
+  u_char *origin;
+
+  origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char));
+
+  if (strcmp (arg, "igp") == 0)
+    *origin = 0;
+  else if (strcmp (arg, "egp") == 0)
+    *origin = 1;
+  else
+    *origin = 2;
+
+  return origin;
+}
+
+/* Compile function for origin set. */
+void
+route_set_origin_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_origin_cmd = 
+{
+  "origin",
+  route_set_origin,
+  route_set_origin_compile,
+  route_set_origin_free,
+};
+\f
+/* `set atomic-aggregate' */
+
+/* For atomic aggregate set. */
+route_map_result_t
+route_set_atomic_aggregate (void *rule, struct prefix *prefix,
+                           route_map_object_t type, void *object)
+{
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for atomic aggregate. */
+void *
+route_set_atomic_aggregate_compile (char *arg)
+{
+  return (void *)1;
+}
+
+/* Compile function for atomic aggregate. */
+void
+route_set_atomic_aggregate_free (void *rule)
+{
+  return;
+}
+
+/* Set atomic aggregate rule structure. */
+struct route_map_rule_cmd route_set_atomic_aggregate_cmd = 
+{
+  "atomic-aggregate",
+  route_set_atomic_aggregate,
+  route_set_atomic_aggregate_compile,
+  route_set_atomic_aggregate_free,
+};
+\f
+/* `set aggregator as AS A.B.C.D' */
+struct aggregator
+{
+  as_t as;
+  struct in_addr address;
+};
+
+route_map_result_t
+route_set_aggregator_as (void *rule, struct prefix *prefix, 
+                        route_map_object_t type, void *object)
+{
+  struct bgp_info *bgp_info;
+  struct aggregator *aggregator;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      aggregator = rule;
+    
+      bgp_info->attr->aggregator_as = aggregator->as;
+      bgp_info->attr->aggregator_addr = aggregator->address;
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
+    }
+
+  return RMAP_OKAY;
+}
+
+void *
+route_set_aggregator_as_compile (char *arg)
+{
+  struct aggregator *aggregator;
+  char as[10];
+  char address[20];
+
+  aggregator = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator));
+  memset (aggregator, 0, sizeof (struct aggregator));
+
+  sscanf (arg, "%s %s", as, address);
+
+  aggregator->as = strtoul (as, NULL, 10);
+  inet_aton (address, &aggregator->address);
+
+  return aggregator;
+}
+
+void
+route_set_aggregator_as_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_set_aggregator_as_cmd = 
+{
+  "aggregator as",
+  route_set_aggregator_as,
+  route_set_aggregator_as_compile,
+  route_set_aggregator_as_free,
+};
+\f
+#ifdef HAVE_IPV6
+/* `match ipv6 address IP_ACCESS_LIST' */
+
+route_map_result_t
+route_match_ipv6_address (void *rule, struct prefix *prefix, 
+                         route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+
+  if (type == RMAP_BGP)
+    {
+      alist = access_list_lookup (AFI_IP6, (char *) rule);
+      if (alist == NULL)
+       return RMAP_NOMATCH;
+    
+      return (access_list_apply (alist, prefix) == FILTER_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ipv6_address_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ipv6_address_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ipv6_address_cmd =
+{
+  "ipv6 address",
+  route_match_ipv6_address,
+  route_match_ipv6_address_compile,
+  route_match_ipv6_address_free
+};
+\f
+/* `match ipv6 next-hop IP_ADDRESS' */
+
+route_map_result_t
+route_match_ipv6_next_hop (void *rule, struct prefix *prefix, 
+                          route_map_object_t type, void *object)
+{
+  struct in6_addr *addr;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      addr = rule;
+      bgp_info = object;
+    
+      if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, rule))
+       return RMAP_MATCH;
+
+      if (bgp_info->attr->mp_nexthop_len == 32 &&
+         IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule))
+       return RMAP_MATCH;
+
+      return RMAP_NOMATCH;
+    }
+
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ipv6_next_hop_compile (char *arg)
+{
+  struct in6_addr *address;
+  int ret;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
+
+  ret = inet_pton (AF_INET6, arg, address);
+  if (!ret)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+void
+route_match_ipv6_next_hop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ipv6_next_hop_cmd =
+{
+  "ipv6 next-hop",
+  route_match_ipv6_next_hop,
+  route_match_ipv6_next_hop_compile,
+  route_match_ipv6_next_hop_free
+};
+\f
+/* `match ipv6 address prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ipv6_address_prefix_list (void *rule, struct prefix *prefix, 
+                             route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+
+  if (type == RMAP_BGP)
+    {
+      plist = prefix_list_lookup (AFI_IP6, (char *) rule);
+      if (plist == NULL)
+       return RMAP_NOMATCH;
+    
+      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ipv6_address_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ipv6_address_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd =
+{
+  "ipv6 address prefix-list",
+  route_match_ipv6_address_prefix_list,
+  route_match_ipv6_address_prefix_list_compile,
+  route_match_ipv6_address_prefix_list_free
+};
+\f
+/* `set ipv6 nexthop global IP_ADDRESS' */
+
+/* Set nexthop to object.  ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix, 
+                              route_map_object_t type, void *object)
+{
+  struct in6_addr *address;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      address = rule;
+      bgp_info = object;
+    
+      /* Set next hop value. */ 
+      bgp_info->attr->mp_nexthop_global = *address;
+    
+      /* Set nexthop length. */
+      if (bgp_info->attr->mp_nexthop_len == 0)
+       bgp_info->attr->mp_nexthop_len = 16;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `ip next-hop' compile function.  Given string is converted
+   to struct in_addr structure. */
+void *
+route_set_ipv6_nexthop_global_compile (char *arg)
+{
+  int ret;
+  struct in6_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
+
+  ret = inet_pton (AF_INET6, arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+/* Free route map's compiled `ip next-hop' value. */
+void
+route_set_ipv6_nexthop_global_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd =
+{
+  "ipv6 next-hop global",
+  route_set_ipv6_nexthop_global,
+  route_set_ipv6_nexthop_global_compile,
+  route_set_ipv6_nexthop_global_free
+};
+\f
+/* `set ipv6 nexthop local IP_ADDRESS' */
+
+/* Set nexthop to object.  ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, 
+                             route_map_object_t type, void *object)
+{
+  struct in6_addr *address;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      address = rule;
+      bgp_info = object;
+    
+      /* Set next hop value. */ 
+      bgp_info->attr->mp_nexthop_local = *address;
+    
+      /* Set nexthop length. */
+      if (bgp_info->attr->mp_nexthop_len != 32)
+       bgp_info->attr->mp_nexthop_len = 32;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function.  Given string is converted
+   to struct in_addr structure. */
+void *
+route_set_ipv6_nexthop_local_compile (char *arg)
+{
+  int ret;
+  struct in6_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
+
+  ret = inet_pton (AF_INET6, arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_ipv6_nexthop_local_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd =
+{
+  "ipv6 next-hop local",
+  route_set_ipv6_nexthop_local,
+  route_set_ipv6_nexthop_local_compile,
+  route_set_ipv6_nexthop_local_free
+};
+#endif /* HAVE_IPV6 */
+\f
+/* `set vpnv4 nexthop A.B.C.D' */
+
+route_map_result_t
+route_set_vpnv4_nexthop (void *rule, struct prefix *prefix, 
+                        route_map_object_t type, void *object)
+{
+  struct in_addr *address;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      address = rule;
+      bgp_info = object;
+    
+      /* Set next hop value. */ 
+      bgp_info->attr->mp_nexthop_global_in = *address;
+    }
+
+  return RMAP_OKAY;
+}
+
+void *
+route_set_vpnv4_nexthop_compile (char *arg)
+{
+  int ret;
+  struct in_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+  ret = inet_aton (arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+void
+route_set_vpnv4_nexthop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd =
+{
+  "vpnv4 next-hop",
+  route_set_vpnv4_nexthop,
+  route_set_vpnv4_nexthop_compile,
+  route_set_vpnv4_nexthop_free
+};
+\f
+/* `set originator-id' */
+
+/* For origin set. */
+route_map_result_t
+route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t type, void *object)
+{
+  struct in_addr *address;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP) 
+    {
+      address = rule;
+      bgp_info = object;
+    
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
+      bgp_info->attr->originator_id = *address;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for originator-id set. */
+void *
+route_set_originator_id_compile (char *arg)
+{
+  int ret;
+  struct in_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+  ret = inet_aton (arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+/* Compile function for originator_id set. */
+void
+route_set_originator_id_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_originator_id_cmd = 
+{
+  "originator-id",
+  route_set_originator_id,
+  route_set_originator_id_compile,
+  route_set_originator_id_free,
+};
+\f
+/* Add bgp route map rule. */
+int
+bgp_route_match_add (struct vty *vty, struct route_map_index *index,
+                   char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete bgp route map rule. */
+int
+bgp_route_match_delete (struct vty *vty, struct route_map_index *index,
+                       char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Add bgp route map rule. */
+int
+bgp_route_set_add (struct vty *vty, struct route_map_index *index,
+                  char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete bgp route map rule. */
+int
+bgp_route_set_delete (struct vty *vty, struct route_map_index *index,
+                     char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+void
+bgp_route_map_update ()
+{
+  int i;
+  afi_t afi;
+  safi_t safi;
+  int direct;
+  struct listnode *nn, *nm;
+  struct bgp *bgp;
+  struct peer *peer;
+  struct peer_group *group;
+  struct bgp_filter *filter;
+  struct bgp_node *bn;
+  struct bgp_static *bgp_static;
+
+  /* For neighbor route-map updates. */
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      LIST_LOOP (bgp->peer, peer, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &peer->filter[afi][safi];
+         
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->map[direct].name)
+                     filter->map[direct].map = 
+                       route_map_lookup_by_name (filter->map[direct].name);
+                   else
+                     filter->map[direct].map = NULL;
+                 }
+
+               if (filter->usmap.name)
+                 filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+               else
+                 filter->usmap.map = NULL;
+             }
+       }
+      LIST_LOOP (bgp->group, group, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &group->conf->filter[afi][safi];
+         
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->map[direct].name)
+                     filter->map[direct].map = 
+                       route_map_lookup_by_name (filter->map[direct].name);
+                   else
+                     filter->map[direct].map = NULL;
+                 }
+
+               if (filter->usmap.name)
+                 filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+               else
+                 filter->usmap.map = NULL;
+             }
+       }
+    }
+
+  /* For default-originate route-map updates. */
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      LIST_LOOP (bgp->peer, peer, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               if (peer->default_rmap[afi][safi].name)
+                 peer->default_rmap[afi][safi].map =
+                   route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
+               else
+                 peer->default_rmap[afi][safi].map = NULL;
+             }
+       }
+    }
+
+  /* For network route-map updates. */
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      for (afi = AFI_IP; afi < AFI_MAX; afi++)
+       for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+         for (bn = bgp_table_top (bgp->route[afi][safi]); bn;
+              bn = bgp_route_next (bn))
+           if ((bgp_static = bn->info) != NULL)
+             {
+               if (bgp_static->rmap.name)
+                 bgp_static->rmap.map =
+                        route_map_lookup_by_name (bgp_static->rmap.name);
+               else
+                 bgp_static->rmap.map = NULL;
+             }
+    }
+
+  /* For redistribute route-map updates. */
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+       {
+         if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name)
+           bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = 
+             route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name);
+#ifdef HAVE_IPV6
+         if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name)
+           bgp->rmap[ZEBRA_FAMILY_IPV6][i].map =
+             route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name);
+#endif /* HAVE_IPV6 */
+       }
+    }
+}
+\f
+DEFUN (match_ip_address, 
+       match_ip_address_cmd,
+       "match ip address (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address, 
+       no_match_ip_address_cmd,
+       "no match ip address",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "ip address", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address, 
+       no_match_ip_address_val_cmd,
+       "no match ip address (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+
+DEFUN (match_ip_next_hop, 
+       match_ip_next_hop_cmd,
+       "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop,
+       no_match_ip_next_hop_cmd,
+       "no match ip next-hop",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+       no_match_ip_next_hop_val_cmd,
+       "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+
+DEFUN (match_ip_address_prefix_list, 
+       match_ip_address_prefix_list_cmd,
+       "match ip address prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_cmd,
+       "no match ip address prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_val_cmd,
+       "no match ip address prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list, 
+       match_ip_next_hop_prefix_list_cmd,
+       "match ip next-hop prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_cmd,
+       "no match ip next-hop prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_val_cmd,
+       "no match ip next-hop prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_metric, 
+       match_metric_cmd,
+       "match metric <0-4294967295>",
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+{
+  return bgp_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+       no_match_metric_cmd,
+       "no match metric",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "metric", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+       no_match_metric_val_cmd,
+       "no match metric <0-4294967295>",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+
+DEFUN (match_community, 
+       match_community_cmd,
+       "match community (<1-99>|<100-199>|WORD)",
+       MATCH_STR
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "community", argv[0]);
+}
+
+DEFUN (match_community_exact, 
+       match_community_exact_cmd,
+       "match community (<1-99>|<100-199>|WORD) exact-match",
+       MATCH_STR
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n"
+       "Do exact matching of communities\n")
+{
+  int ret;
+  char *argstr;
+
+  argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+                   strlen (argv[0]) + strlen ("exact-match") + 2);
+
+  sprintf (argstr, "%s exact-match", argv[0]);
+
+  ret = bgp_route_match_add (vty, vty->index, "community", argstr);
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
+
+  return ret;
+}
+
+DEFUN (no_match_community,
+       no_match_community_cmd,
+       "no match community",
+       NO_STR
+       MATCH_STR
+       "Match BGP community list\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "community", NULL);
+}
+
+ALIAS (no_match_community,
+       no_match_community_val_cmd,
+       "no match community (<1-99>|<100-199>|WORD)",
+       NO_STR
+       MATCH_STR
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n")
+
+ALIAS (no_match_community,
+       no_match_community_exact_cmd,
+       "no match community (<1-99>|<100-199>|WORD) exact-match",
+       NO_STR
+       MATCH_STR
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n"
+       "Do exact matching of communities\n")
+
+DEFUN (match_aspath,
+       match_aspath_cmd,
+       "match as-path WORD",
+       MATCH_STR
+       "Match BGP AS path list\n"
+       "AS path access-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "as-path", argv[0]);
+}
+
+DEFUN (no_match_aspath,
+       no_match_aspath_cmd,
+       "no match as-path",
+       NO_STR
+       MATCH_STR
+       "Match BGP AS path list\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "as-path", NULL);
+}
+
+ALIAS (no_match_aspath,
+       no_match_aspath_val_cmd,
+       "no match as-path WORD",
+       NO_STR
+       MATCH_STR
+       "Match BGP AS path list\n"
+       "AS path access-list name\n")
+
+DEFUN (match_origin,
+       match_origin_cmd,
+       "match origin (egp|igp|incomplete)",
+       MATCH_STR
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+{
+  if (strncmp (argv[0], "igp", 2) == 0)
+    return bgp_route_match_add (vty, vty->index, "origin", "igp");
+  if (strncmp (argv[0], "egp", 1) == 0)
+    return bgp_route_match_add (vty, vty->index, "origin", "egp");
+  if (strncmp (argv[0], "incomplete", 2) == 0)
+    return bgp_route_match_add (vty, vty->index, "origin", "incomplete");
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_match_origin,
+       no_match_origin_cmd,
+       "no match origin",
+       NO_STR
+       MATCH_STR
+       "BGP origin code\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "origin", NULL);
+}
+
+ALIAS (no_match_origin,
+       no_match_origin_val_cmd,
+       "no match origin (egp|igp|incomplete)",
+       NO_STR
+       MATCH_STR
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+
+DEFUN (set_ip_nexthop,
+       set_ip_nexthop_cmd,
+       "set ip next-hop A.B.C.D",
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+{
+  union sockunion su;
+  int ret;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed Next-hop address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_set_ip_nexthop,
+       no_set_ip_nexthop_cmd,
+       "no set ip next-hop",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return bgp_route_set_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_set_ip_nexthop,
+       no_set_ip_nexthop_val_cmd,
+       "no set ip next-hop A.B.C.D",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric (<0-4294967295>|<+/-metric>)",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n"
+       "Add or subtract metric\n")
+{
+  return bgp_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "metric", NULL);
+
+  return bgp_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+       no_set_metric_val_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+
+DEFUN (set_local_pref,
+       set_local_pref_cmd,
+       "set local-preference <0-4294967295>",
+       SET_STR
+       "BGP local preference path attribute\n"
+       "Preference value\n")
+{
+  return bgp_route_set_add (vty, vty->index, "local-preference", argv[0]);
+}
+
+DEFUN (no_set_local_pref,
+       no_set_local_pref_cmd,
+       "no set local-preference",
+       NO_STR
+       SET_STR
+       "BGP local preference path attribute\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "local-preference", NULL);
+
+  return bgp_route_set_delete (vty, vty->index, "local-preference", argv[0]);
+}
+
+ALIAS (no_set_local_pref,
+       no_set_local_pref_val_cmd,
+       "no set local-preference <0-4294967295>",
+       NO_STR
+       SET_STR
+       "BGP local preference path attribute\n"
+       "Preference value\n")
+
+DEFUN (set_weight,
+       set_weight_cmd,
+       "set weight <0-4294967295>",
+       SET_STR
+       "BGP weight for routing table\n"
+       "Weight value\n")
+{
+  return bgp_route_set_add (vty, vty->index, "weight", argv[0]);
+}
+
+DEFUN (no_set_weight,
+       no_set_weight_cmd,
+       "no set weight",
+       NO_STR
+       SET_STR
+       "BGP weight for routing table\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "weight", NULL);
+  
+  return bgp_route_set_delete (vty, vty->index, "weight", argv[0]);
+}
+
+ALIAS (no_set_weight,
+       no_set_weight_val_cmd,
+       "no set weight <0-4294967295>",
+       NO_STR
+       SET_STR
+       "BGP weight for routing table\n"
+       "Weight value\n")
+
+DEFUN (set_aspath_prepend,
+       set_aspath_prepend_cmd,
+       "set as-path prepend .<1-65535>",
+       SET_STR
+       "Prepend string for a BGP AS-path attribute\n"
+       "Prepend to the as-path\n"
+       "AS number\n")
+{
+  int ret;
+  char *str;
+
+  str = argv_concat (argv, argc, 0);
+  ret = bgp_route_set_add (vty, vty->index, "as-path prepend", str);
+  XFREE (MTYPE_TMP, str);
+
+  return ret;
+}
+
+DEFUN (no_set_aspath_prepend,
+       no_set_aspath_prepend_cmd,
+       "no set as-path prepend",
+       NO_STR
+       SET_STR
+       "Prepend string for a BGP AS-path attribute\n"
+       "Prepend to the as-path\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "as-path prepend", NULL);
+}
+
+ALIAS (no_set_aspath_prepend,
+       no_set_aspath_prepend_val_cmd,
+       "no set as-path prepend .<1-65535>",
+       NO_STR
+       SET_STR
+       "Prepend string for a BGP AS-path attribute\n"
+       "Prepend to the as-path\n"
+       "AS number\n")
+
+DEFUN (set_community,
+       set_community_cmd,
+       "set community .AA:NN",
+       SET_STR
+       "BGP community attribute\n"
+       "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+{
+  int i;
+  int first = 0;
+  int additive = 0;
+  struct buffer *b;
+  struct community *com = NULL;
+  char *str;
+  char *argstr;
+  int ret;
+
+  b = buffer_new (1024);
+
+  for (i = 0; i < argc; i++)
+    {
+      if (strncmp (argv[i], "additive", strlen (argv[i])) == 0)
+       {
+         additive = 1;
+         continue;
+       }
+
+      if (first)
+       buffer_putc (b, ' ');
+      else
+       first = 1;
+
+      if (strncmp (argv[i], "internet", strlen (argv[i])) == 0)
+       {
+         buffer_putstr (b, "internet");
+         continue;
+       }
+      if (strncmp (argv[i], "local-AS", strlen (argv[i])) == 0)
+       {
+         buffer_putstr (b, "local-AS");
+         continue;
+       }
+      if (strncmp (argv[i], "no-a", strlen ("no-a")) == 0
+         && strncmp (argv[i], "no-advertise", strlen (argv[i])) == 0)
+       {
+         buffer_putstr (b, "no-advertise");
+         continue;
+       }
+      if (strncmp (argv[i], "no-e", strlen ("no-e"))== 0
+         && strncmp (argv[i], "no-export", strlen (argv[i])) == 0)
+       {
+         buffer_putstr (b, "no-export");
+         continue;
+       }
+      buffer_putstr (b, argv[i]);
+    }
+  buffer_putc (b, '\0');
+
+  /* Fetch result string then compile it to communities attribute.  */
+  str = buffer_getstr (b);
+  buffer_free (b);
+
+  if (str)
+    {
+      com = community_str2com (str);
+      free (str);
+    }
+
+  /* Can't compile user input into communities attribute.  */
+  if (! com)
+    {
+      vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Set communites attribute string.  */
+  str = community_str (com);
+
+  if (additive)
+    {
+      argstr = XCALLOC (MTYPE_TMP, strlen (str) + strlen (" additive") + 1);
+      strcpy (argstr, str);
+      strcpy (argstr + strlen (str), " additive");
+      ret =  bgp_route_set_add (vty, vty->index, "community", argstr);
+      XFREE (MTYPE_TMP, argstr);
+    }
+  else
+    ret =  bgp_route_set_add (vty, vty->index, "community", str);
+
+  community_free (com);
+
+  return ret;
+}
+
+DEFUN (set_community_none,
+       set_community_none_cmd,
+       "set community none",
+       SET_STR
+       "BGP community attribute\n"
+       "No community attribute\n")
+{
+  return bgp_route_set_add (vty, vty->index, "community", "none");
+}
+
+DEFUN (no_set_community,
+       no_set_community_cmd,
+       "no set community",
+       NO_STR
+       SET_STR
+       "BGP community attribute\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "community", NULL);
+}
+
+ALIAS (no_set_community,
+       no_set_community_val_cmd,
+       "no set community .AA:NN",
+       NO_STR
+       SET_STR
+       "BGP community attribute\n"
+       "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+
+ALIAS (no_set_community,
+       no_set_community_none_cmd,
+       "no set community none",
+       NO_STR
+       SET_STR
+       "BGP community attribute\n"
+       "No community attribute\n")
+
+DEFUN (set_community_delete,
+       set_community_delete_cmd,
+       "set comm-list (<1-99>|<100-199>|WORD) delete",
+       SET_STR
+       "set BGP community list (for deletion)\n"
+       "Community-list number (standard)\n"
+       "Communitly-list number (expanded)\n"
+       "Community-list name\n"
+       "Delete matching communities\n")
+{
+  char *str;
+
+  str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1);
+  strcpy (str, argv[0]);
+  strcpy (str + strlen (argv[0]), " delete");
+
+  bgp_route_set_add (vty, vty->index, "comm-list", str);
+
+  XFREE (MTYPE_TMP, str);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_set_community_delete,
+       no_set_community_delete_cmd,
+       "no set comm-list",
+       NO_STR
+       SET_STR
+       "set BGP community list (for deletion)\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "comm-list", NULL);
+}
+
+ALIAS (no_set_community_delete,
+       no_set_community_delete_val_cmd,
+       "no set comm-list (<1-99>|<100-199>|WORD) delete",
+       NO_STR
+       SET_STR
+       "set BGP community list (for deletion)\n"
+       "Community-list number (standard)\n"
+       "Communitly-list number (expanded)\n"
+       "Community-list name\n"
+       "Delete matching communities\n")
+
+DEFUN (set_ecommunity_rt,
+       set_ecommunity_rt_cmd,
+       "set extcommunity rt .ASN:nn_or_IP-address:nn",
+       SET_STR
+       "BGP extended community attribute\n"
+       "Route Target extened communityt\n"
+       "VPN extended community\n")
+{
+  int ret;
+  char *str;
+
+  str = argv_concat (argv, argc, 0);
+  ret = bgp_route_set_add (vty, vty->index, "extcommunity rt", str);
+  XFREE (MTYPE_TMP, str);
+
+  return ret;
+}
+
+DEFUN (no_set_ecommunity_rt,
+       no_set_ecommunity_rt_cmd,
+       "no set extcommunity rt",
+       NO_STR
+       SET_STR
+       "BGP extended community attribute\n"
+       "Route Target extened communityt\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "extcommunity rt", NULL);
+}
+
+ALIAS (no_set_ecommunity_rt,
+       no_set_ecommunity_rt_val_cmd,
+       "no set extcommunity rt .ASN:nn_or_IP-address:nn",
+       NO_STR
+       SET_STR
+       "BGP extended community attribute\n"
+       "Route Target extened communityt\n"
+       "VPN extended community\n")
+
+DEFUN (set_ecommunity_soo,
+       set_ecommunity_soo_cmd,
+       "set extcommunity soo .ASN:nn_or_IP-address:nn",
+       SET_STR
+       "BGP extended community attribute\n"
+       "Site-of-Origin extended community\n"
+       "VPN extended community\n")
+{
+  int ret;
+  char *str;
+
+  str = argv_concat (argv, argc, 0);
+  ret = bgp_route_set_add (vty, vty->index, "extcommunity soo", str);
+  XFREE (MTYPE_TMP, str);
+  return ret;
+}
+
+DEFUN (no_set_ecommunity_soo,
+       no_set_ecommunity_soo_cmd,
+       "no set extcommunity soo",
+       NO_STR
+       SET_STR
+       "BGP extended community attribute\n"
+       "Site-of-Origin extended community\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "extcommunity soo", NULL);
+}
+
+ALIAS (no_set_ecommunity_soo,
+       no_set_ecommunity_soo_val_cmd,
+       "no set extcommunity soo .ASN:nn_or_IP-address:nn",
+       NO_STR
+       SET_STR
+       "BGP extended community attribute\n"
+       "Site-of-Origin extended community\n"
+       "VPN extended community\n")
+
+DEFUN (set_origin,
+       set_origin_cmd,
+       "set origin (egp|igp|incomplete)",
+       SET_STR
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+{
+  if (strncmp (argv[0], "igp", 2) == 0)
+    return bgp_route_set_add (vty, vty->index, "origin", "igp");
+  if (strncmp (argv[0], "egp", 1) == 0)
+    return bgp_route_set_add (vty, vty->index, "origin", "egp");
+  if (strncmp (argv[0], "incomplete", 2) == 0)
+    return bgp_route_set_add (vty, vty->index, "origin", "incomplete");
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_set_origin,
+       no_set_origin_cmd,
+       "no set origin",
+       NO_STR
+       SET_STR
+       "BGP origin code\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "origin", NULL);
+}
+
+ALIAS (no_set_origin,
+       no_set_origin_val_cmd,
+       "no set origin (egp|igp|incomplete)",
+       NO_STR
+       SET_STR
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+
+DEFUN (set_atomic_aggregate,
+       set_atomic_aggregate_cmd,
+       "set atomic-aggregate",
+       SET_STR
+       "BGP atomic aggregate attribute\n" )
+{
+  return bgp_route_set_add (vty, vty->index, "atomic-aggregate", NULL);
+}
+
+DEFUN (no_set_atomic_aggregate,
+       no_set_atomic_aggregate_cmd,
+       "no set atomic-aggregate",
+       NO_STR
+       SET_STR
+       "BGP atomic aggregate attribute\n" )
+{
+  return bgp_route_set_delete (vty, vty->index, "atomic-aggregate", NULL);
+}
+
+DEFUN (set_aggregator_as,
+       set_aggregator_as_cmd,
+       "set aggregator as <1-65535> A.B.C.D",
+       SET_STR
+       "BGP aggregator attribute\n"
+       "AS number of aggregator\n"
+       "AS number\n"
+       "IP address of aggregator\n")
+{
+  int ret;
+  as_t as;
+  struct in_addr address;
+  char *endptr = NULL;
+  char *argstr;
+
+  as = strtoul (argv[0], &endptr, 10);
+  if (as == 0 || as == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "AS path value malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (argv[1], &address);
+  if (ret == 0)
+    {
+      vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+                   strlen (argv[0]) + strlen (argv[1]) + 2);
+
+  sprintf (argstr, "%s %s", argv[0], argv[1]);
+
+  ret = bgp_route_set_add (vty, vty->index, "aggregator as", argstr);
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
+
+  return ret;
+}
+
+DEFUN (no_set_aggregator_as,
+       no_set_aggregator_as_cmd,
+       "no set aggregator as",
+       NO_STR
+       SET_STR
+       "BGP aggregator attribute\n"
+       "AS number of aggregator\n")
+{
+  int ret;
+  as_t as;
+  struct in_addr address;
+  char *endptr = NULL;
+  char *argstr;
+
+  if (argv == 0)
+    return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL);
+  
+  as = strtoul (argv[0], &endptr, 10);
+  if (as == 0 || as == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "AS path value malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (argv[1], &address);
+  if (ret == 0)
+    {
+      vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+                   strlen (argv[0]) + strlen (argv[1]) + 2);
+
+  sprintf (argstr, "%s %s", argv[0], argv[1]);
+
+  ret = bgp_route_set_delete (vty, vty->index, "aggregator as", argstr);
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
+
+  return ret;
+}
+
+ALIAS (no_set_aggregator_as,
+       no_set_aggregator_as_val_cmd,
+       "no set aggregator as <1-65535> A.B.C.D",
+       NO_STR
+       SET_STR
+       "BGP aggregator attribute\n"
+       "AS number of aggregator\n"
+       "AS number\n"
+       "IP address of aggregator\n")
+
+\f
+#ifdef HAVE_IPV6
+DEFUN (match_ipv6_address, 
+       match_ipv6_address_cmd,
+       "match ipv6 address WORD",
+       MATCH_STR
+       IPV6_STR
+       "Match IPv6 address of route\n"
+       "IPv6 access-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]);
+}
+
+DEFUN (no_match_ipv6_address, 
+       no_match_ipv6_address_cmd,
+       "no match ipv6 address WORD",
+       NO_STR
+       MATCH_STR
+       IPV6_STR
+       "Match IPv6 address of route\n"
+       "IPv6 access-list name\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]);
+}
+
+DEFUN (match_ipv6_next_hop, 
+       match_ipv6_next_hop_cmd,
+       "match ipv6 next-hop X:X::X:X",
+       MATCH_STR
+       IPV6_STR
+       "Match IPv6 next-hop address of route\n"
+       "IPv6 address of next hop\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]);
+}
+
+DEFUN (no_match_ipv6_next_hop,
+       no_match_ipv6_next_hop_cmd,
+       "no match ipv6 next-hop X:X::X:X",
+       NO_STR
+       MATCH_STR
+       IPV6_STR
+       "Match IPv6 next-hop address of route\n"
+       "IPv6 address of next hop\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]);
+}
+
+DEFUN (match_ipv6_address_prefix_list, 
+       match_ipv6_address_prefix_list_cmd,
+       "match ipv6 address prefix-list WORD",
+       MATCH_STR
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ipv6_address_prefix_list,
+       no_match_ipv6_address_prefix_list_cmd,
+       "no match ipv6 address prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+}
+
+DEFUN (set_ipv6_nexthop_global,
+       set_ipv6_nexthop_global_cmd,
+       "set ipv6 next-hop global X:X::X:X",
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 global address\n"
+       "IPv6 address of next hop\n")
+{
+  return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]);
+}
+
+DEFUN (no_set_ipv6_nexthop_global,
+       no_set_ipv6_nexthop_global_cmd,
+       "no set ipv6 next-hop global",
+       NO_STR
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 global address\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL);
+
+  return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]);
+}
+
+ALIAS (no_set_ipv6_nexthop_global,
+       no_set_ipv6_nexthop_global_val_cmd,
+       "no set ipv6 next-hop global X:X::X:X",
+       NO_STR
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 global address\n"
+       "IPv6 address of next hop\n")
+
+DEFUN (set_ipv6_nexthop_local,
+       set_ipv6_nexthop_local_cmd,
+       "set ipv6 next-hop local X:X::X:X",
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n"
+       "IPv6 address of next hop\n")
+{
+  return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]);
+}
+
+DEFUN (no_set_ipv6_nexthop_local,
+       no_set_ipv6_nexthop_local_cmd,
+       "no set ipv6 next-hop local",
+       NO_STR
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL);
+  
+  return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]);
+}
+
+ALIAS (no_set_ipv6_nexthop_local,
+       no_set_ipv6_nexthop_local_val_cmd,
+       "no set ipv6 next-hop local X:X::X:X",
+       NO_STR
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n"
+       "IPv6 address of next hop\n")
+#endif /* HAVE_IPV6 */
+
+DEFUN (set_vpnv4_nexthop,
+       set_vpnv4_nexthop_cmd,
+       "set vpnv4 next-hop A.B.C.D",
+       SET_STR
+       "VPNv4 information\n"
+       "VPNv4 next-hop address\n"
+       "IP address of next hop\n")
+{
+  return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]);
+}
+
+DEFUN (no_set_vpnv4_nexthop,
+       no_set_vpnv4_nexthop_cmd,
+       "no set vpnv4 next-hop",
+       NO_STR
+       SET_STR
+       "VPNv4 information\n"
+       "VPNv4 next-hop address\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL);
+
+  return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]);
+}
+
+ALIAS (no_set_vpnv4_nexthop,
+       no_set_vpnv4_nexthop_val_cmd,
+       "no set vpnv4 next-hop A.B.C.D",
+       NO_STR
+       SET_STR
+       "VPNv4 information\n"
+       "VPNv4 next-hop address\n"
+       "IP address of next hop\n")
+
+DEFUN (set_originator_id,
+       set_originator_id_cmd,
+       "set originator-id A.B.C.D",
+       SET_STR
+       "BGP originator ID attribute\n"
+       "IP address of originator\n")
+{
+  return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]);
+}
+
+DEFUN (no_set_originator_id,
+       no_set_originator_id_cmd,
+       "no set originator-id",
+       NO_STR
+       SET_STR
+       "BGP originator ID attribute\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "originator-id", NULL);
+  
+  return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]);
+}
+
+ALIAS (no_set_originator_id,
+       no_set_originator_id_val_cmd,
+       "no set originator-id A.B.C.D",
+       NO_STR
+       SET_STR
+       "BGP originator ID attribute\n"
+       "IP address of originator\n")
+
+\f
+/* Initialization of route map. */
+void
+bgp_route_map_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+  route_map_add_hook (bgp_route_map_update);
+  route_map_delete_hook (bgp_route_map_update);
+
+  route_map_install_match (&route_match_ip_address_cmd);
+  route_map_install_match (&route_match_ip_next_hop_cmd);
+  route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+  route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+  route_map_install_match (&route_match_aspath_cmd);
+  route_map_install_match (&route_match_community_cmd);
+  route_map_install_match (&route_match_metric_cmd);
+  route_map_install_match (&route_match_origin_cmd);
+
+  route_map_install_set (&route_set_ip_nexthop_cmd);
+  route_map_install_set (&route_set_local_pref_cmd);
+  route_map_install_set (&route_set_weight_cmd);
+  route_map_install_set (&route_set_metric_cmd);
+  route_map_install_set (&route_set_aspath_prepend_cmd);
+  route_map_install_set (&route_set_origin_cmd);
+  route_map_install_set (&route_set_atomic_aggregate_cmd);
+  route_map_install_set (&route_set_aggregator_as_cmd);
+  route_map_install_set (&route_set_community_cmd);
+  route_map_install_set (&route_set_community_delete_cmd);
+  route_map_install_set (&route_set_vpnv4_nexthop_cmd);
+  route_map_install_set (&route_set_originator_id_cmd);
+  route_map_install_set (&route_set_ecommunity_rt_cmd);
+  route_map_install_set (&route_set_ecommunity_soo_cmd);
+
+  install_element (RMAP_NODE, &match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+
+  install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+
+  install_element (RMAP_NODE, &match_aspath_cmd);
+  install_element (RMAP_NODE, &no_match_aspath_cmd);
+  install_element (RMAP_NODE, &no_match_aspath_val_cmd);
+  install_element (RMAP_NODE, &match_metric_cmd);
+  install_element (RMAP_NODE, &no_match_metric_cmd);
+  install_element (RMAP_NODE, &no_match_metric_val_cmd);
+  install_element (RMAP_NODE, &match_community_cmd);
+  install_element (RMAP_NODE, &match_community_exact_cmd);
+  install_element (RMAP_NODE, &no_match_community_cmd);
+  install_element (RMAP_NODE, &no_match_community_val_cmd);
+  install_element (RMAP_NODE, &no_match_community_exact_cmd);
+  install_element (RMAP_NODE, &match_origin_cmd);
+  install_element (RMAP_NODE, &no_match_origin_cmd);
+  install_element (RMAP_NODE, &no_match_origin_val_cmd);
+
+  install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+  install_element (RMAP_NODE, &set_local_pref_cmd);
+  install_element (RMAP_NODE, &no_set_local_pref_cmd);
+  install_element (RMAP_NODE, &no_set_local_pref_val_cmd);
+  install_element (RMAP_NODE, &set_weight_cmd);
+  install_element (RMAP_NODE, &no_set_weight_cmd);
+  install_element (RMAP_NODE, &no_set_weight_val_cmd);
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_val_cmd);
+  install_element (RMAP_NODE, &set_aspath_prepend_cmd);
+  install_element (RMAP_NODE, &no_set_aspath_prepend_cmd);
+  install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd);
+  install_element (RMAP_NODE, &set_origin_cmd);
+  install_element (RMAP_NODE, &no_set_origin_cmd);
+  install_element (RMAP_NODE, &no_set_origin_val_cmd);
+  install_element (RMAP_NODE, &set_atomic_aggregate_cmd);
+  install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd);
+  install_element (RMAP_NODE, &set_aggregator_as_cmd);
+  install_element (RMAP_NODE, &no_set_aggregator_as_cmd);
+  install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd);
+  install_element (RMAP_NODE, &set_community_cmd);
+  install_element (RMAP_NODE, &set_community_none_cmd);
+  install_element (RMAP_NODE, &no_set_community_cmd);
+  install_element (RMAP_NODE, &no_set_community_val_cmd);
+  install_element (RMAP_NODE, &no_set_community_none_cmd);
+  install_element (RMAP_NODE, &set_community_delete_cmd);
+  install_element (RMAP_NODE, &no_set_community_delete_cmd);
+  install_element (RMAP_NODE, &no_set_community_delete_val_cmd);
+  install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
+  install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
+  install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd);
+  install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
+  install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd);
+  install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd);
+  install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd);
+  install_element (RMAP_NODE, &set_originator_id_cmd);
+  install_element (RMAP_NODE, &no_set_originator_id_cmd);
+  install_element (RMAP_NODE, &no_set_originator_id_val_cmd);
+
+#ifdef HAVE_IPV6
+  route_map_install_match (&route_match_ipv6_address_cmd);
+  route_map_install_match (&route_match_ipv6_next_hop_cmd);
+  route_map_install_match (&route_match_ipv6_address_prefix_list_cmd);
+  route_map_install_set (&route_set_ipv6_nexthop_global_cmd);
+  route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
+
+  install_element (RMAP_NODE, &match_ipv6_address_cmd);
+  install_element (RMAP_NODE, &no_match_ipv6_address_cmd);
+  install_element (RMAP_NODE, &match_ipv6_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd);
+  install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd);
+  install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd);
+#endif /* HAVE_IPV6 */
+}
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
new file mode 100644 (file)
index 0000000..bf9c7f8
--- /dev/null
@@ -0,0 +1,875 @@
+/* BGP4 SNMP support
+   Copyright (C) 1999, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "thread.h"
+#include "smux.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_fsm.h"
+\f
+/* BGP4-MIB described in RFC1657. */
+#define BGP4MIB 1,3,6,1,2,1,15
+
+/* Zebra enterprise BGP MIB.  This variable is used for register
+   OSPF MIB to SNMP agent under SMUX protocol.  */
+#define BGPDMIB 1,3,6,1,4,1,3317,1,2,2
+
+/* BGP MIB bgpVersion. */
+#define BGPVERSION                           0
+
+/* BGP MIB bgpLocalAs. */
+#define BGPLOCALAS                           0
+
+/* BGP MIB bgpPeerTable. */
+#define BGPPEERIDENTIFIER                     1
+#define BGPPEERSTATE                          2
+#define BGPPEERADMINSTATUS                    3
+#define BGPPEERNEGOTIATEDVERSION              4
+#define BGPPEERLOCALADDR                      5
+#define BGPPEERLOCALPORT                      6
+#define BGPPEERREMOTEADDR                     7
+#define BGPPEERREMOTEPORT                     8
+#define BGPPEERREMOTEAS                       9
+#define BGPPEERINUPDATES                     10
+#define BGPPEEROUTUPDATES                    11
+#define BGPPEERINTOTALMESSAGES               12
+#define BGPPEEROUTTOTALMESSAGES              13
+#define BGPPEERLASTERROR                     14
+#define BGPPEERFSMESTABLISHEDTRANSITIONS     15
+#define BGPPEERFSMESTABLISHEDTIME            16
+#define BGPPEERCONNECTRETRYINTERVAL          17
+#define BGPPEERHOLDTIME                      18
+#define BGPPEERKEEPALIVE                     19
+#define BGPPEERHOLDTIMECONFIGURED            20
+#define BGPPEERKEEPALIVECONFIGURED           21
+#define BGPPEERMINASORIGINATIONINTERVAL      22
+#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23
+#define BGPPEERINUPDATEELAPSEDTIME           24
+
+/* BGP MIB bgpIdentifier. */
+#define BGPIDENTIFIER                         0
+
+/* BGP MIB bgpRcvdPathAttrTable */
+#define BGPPATHATTRPEER                       1
+#define BGPPATHATTRDESTNETWORK                2
+#define BGPPATHATTRORIGIN                     3
+#define BGPPATHATTRASPATH                     4
+#define BGPPATHATTRNEXTHOP                    5
+#define BGPPATHATTRINTERASMETRIC              6
+
+/* BGP MIB bgp4PathAttrTable. */
+#define BGP4PATHATTRPEER                      1
+#define BGP4PATHATTRIPADDRPREFIXLEN           2
+#define BGP4PATHATTRIPADDRPREFIX              3
+#define BGP4PATHATTRORIGIN                    4
+#define BGP4PATHATTRASPATHSEGMENT             5
+#define BGP4PATHATTRNEXTHOP                   6
+#define BGP4PATHATTRMULTIEXITDISC             7
+#define BGP4PATHATTRLOCALPREF                 8
+#define BGP4PATHATTRATOMICAGGREGATE           9
+#define BGP4PATHATTRAGGREGATORAS             10
+#define BGP4PATHATTRAGGREGATORADDR           11
+#define BGP4PATHATTRCALCLOCALPREF            12
+#define BGP4PATHATTRBEST                     13
+#define BGP4PATHATTRUNKNOWN                  14
+
+/* SNMP value hack. */
+#define INTEGER ASN_INTEGER
+#define INTEGER32 ASN_INTEGER
+#define COUNTER32 ASN_COUNTER
+#define OCTET_STRING ASN_OCTET_STR
+#define IPADDRESS ASN_IPADDRESS
+#define GAUGE32 ASN_UNSIGNED
+\f
+/* Declare static local variables for convenience. */
+SNMP_LOCAL_VARIABLES
+
+/* BGP-MIB instances. */
+oid bgp_oid [] = { BGP4MIB };
+oid bgpd_oid [] = { BGPDMIB };
+
+/* IP address 0.0.0.0. */
+static struct in_addr bgp_empty_addr = {0};
+
+/* Hook functions. */
+static u_char *bgpVersion ();
+static u_char *bgpLocalAs ();
+static u_char *bgpPeerTable ();
+static u_char *bgpRcvdPathAttrTable ();
+static u_char *bgpIdentifier ();
+static u_char *bgp4PathAttrTable ();
+/* static u_char *bgpTraps (); */
+
+struct variable bgp_variables[] = 
+{
+  /* BGP version. */
+  {BGPVERSION,                OCTET_STRING, RONLY, bgpVersion,
+   1, {1}},
+  /* BGP local AS. */
+  {BGPLOCALAS,                INTEGER, RONLY, bgpLocalAs,
+   1, {2}},
+  /* BGP peer table. */
+  {BGPPEERIDENTIFIER,         IPADDRESS, RONLY, bgpPeerTable,
+   3, {3, 1, 1}},
+  {BGPPEERSTATE,              INTEGER, RONLY, bgpPeerTable,
+   3, {3, 1, 2}},
+  {BGPPEERADMINSTATUS,        INTEGER, RWRITE, bgpPeerTable,
+   3, {3, 1, 3}},
+  {BGPPEERNEGOTIATEDVERSION,  INTEGER32, RONLY, bgpPeerTable,
+   3, {3, 1, 4}},
+  {BGPPEERLOCALADDR,          IPADDRESS, RONLY, bgpPeerTable,
+   3, {3, 1, 5}},
+  {BGPPEERLOCALPORT,          INTEGER, RONLY, bgpPeerTable,
+   3, {3, 1, 6}},
+  {BGPPEERREMOTEADDR,         IPADDRESS, RONLY, bgpPeerTable,
+   3, {3, 1, 7}},
+  {BGPPEERREMOTEPORT,         INTEGER, RONLY, bgpPeerTable,
+   3, {3, 1, 8}},
+  {BGPPEERREMOTEAS,           INTEGER, RONLY, bgpPeerTable,
+   3, {3, 1, 9}},
+  {BGPPEERINUPDATES,          COUNTER32, RONLY, bgpPeerTable,
+   3, {3, 1, 10}},
+  {BGPPEEROUTUPDATES,         COUNTER32, RONLY, bgpPeerTable,
+   3, {3, 1, 11}},
+  {BGPPEERINTOTALMESSAGES,    COUNTER32, RONLY, bgpPeerTable,
+   3, {3, 1, 12}},
+  {BGPPEEROUTTOTALMESSAGES,   COUNTER32, RONLY, bgpPeerTable,
+   3, {3, 1, 13}},
+  {BGPPEERLASTERROR,          OCTET_STRING, RONLY, bgpPeerTable,
+   3, {3, 1, 14}},
+  {BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable,
+   3, {3, 1, 15}},
+  {BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable,
+   3, {3, 1, 16}},
+  {BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable,
+   3, {3, 1, 17}},
+  {BGPPEERHOLDTIME,           INTEGER, RONLY, bgpPeerTable,
+   3, {3, 1, 18}},
+  {BGPPEERKEEPALIVE,          INTEGER, RONLY, bgpPeerTable,
+   3, {3, 1, 19}},
+  {BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable,
+   3, {3, 1, 20}},
+  {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable,
+   3, {3, 1, 21}},
+  {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable,
+   3, {3, 1, 22}},
+  {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable,
+   3, {3, 1, 23}},
+  {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable,
+   3, {3, 1, 24}},
+  /* BGP identifier. */
+  {BGPIDENTIFIER,             IPADDRESS, RONLY, bgpIdentifier,
+   1, {4}},
+  /* BGP received path attribute table. */
+  {BGPPATHATTRPEER,           IPADDRESS, RONLY, bgpRcvdPathAttrTable,
+   3, {5, 1, 1}},
+  {BGPPATHATTRDESTNETWORK,    IPADDRESS, RONLY, bgpRcvdPathAttrTable,
+   3, {5, 1, 2}},
+  {BGPPATHATTRORIGIN,         INTEGER, RONLY, bgpRcvdPathAttrTable,
+   3, {5, 1, 3}},
+  {BGPPATHATTRASPATH,         OCTET_STRING, RONLY, bgpRcvdPathAttrTable,
+   3, {5, 1, 4}},
+  {BGPPATHATTRNEXTHOP,        IPADDRESS, RONLY, bgpRcvdPathAttrTable,
+   3, {5, 1, 5}},
+  {BGPPATHATTRINTERASMETRIC,  INTEGER32, RONLY, bgpRcvdPathAttrTable,
+   3, {5, 1, 6}},
+  /* BGP-4 received path attribute table. */
+  {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 1}},
+  {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 2}},
+  {BGP4PATHATTRIPADDRPREFIX,  IPADDRESS, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 3}},
+  {BGP4PATHATTRORIGIN,        INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 4}},
+  {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 5}},
+  {BGP4PATHATTRNEXTHOP,       IPADDRESS, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 6}},
+  {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 7}},
+  {BGP4PATHATTRLOCALPREF,     INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 8}},
+  {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 9}},
+  {BGP4PATHATTRAGGREGATORAS,  INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 10}},
+  {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 11}},
+  {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 12}},
+  {BGP4PATHATTRBEST,          INTEGER, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 13}},
+  {BGP4PATHATTRUNKNOWN,       OCTET_STRING, RONLY, bgp4PathAttrTable,
+   3, {6, 1, 14}},
+};
+\f
+static u_char *
+bgpVersion (struct variable *v, oid name[], size_t *length, int exact,
+           size_t *var_len, WriteMethod **write_method)
+{
+  static u_char version;
+
+  if (smux_header_generic(v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Retrun BGP version.  Zebra bgpd only support version 4. */
+  version = (0x80 >> (BGP_VERSION_4 - 1));
+
+  /* Return octet string length 1. */
+  *var_len = 1;
+  return (u_char *)&version;
+}
+
+static u_char *
+bgpLocalAs (struct variable *v, oid name[], size_t *length,
+           int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct bgp *bgp;
+
+  if (smux_header_generic(v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Get BGP structure. */
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return NULL;
+
+  return SNMP_INTEGER (bgp->as);
+}
+
+struct peer *
+peer_lookup_addr_ipv4 (struct in_addr *src)
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  struct listnode *nn;
+  struct in_addr addr;
+  int ret;
+
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return NULL;
+
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      ret = inet_pton (AF_INET, peer->host, &addr);
+      if (ret > 0)
+       {
+         if (IPV4_ADDR_SAME (&addr, src))
+           return peer;
+       }
+    }
+  return NULL;
+}
+
+struct peer *
+bgp_peer_lookup_next (struct in_addr *src)
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  struct listnode *nn;
+  struct in_addr *p;
+  union sockunion su;
+  int ret;
+
+  memset (&su, 0, sizeof (union sockunion));
+
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return NULL;
+
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr);
+      if (ret > 0)
+       {
+         p = &su.sin.sin_addr;
+
+         if (ntohl (p->s_addr) > ntohl (src->s_addr))
+           {
+             src->s_addr = p->s_addr;
+             return peer;
+           }
+       }
+    }
+  return NULL;
+}
+
+struct peer *
+bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, 
+                    struct in_addr *addr, int exact)
+{
+  struct peer *peer = NULL;
+  int len;
+
+  if (exact)
+    {
+      /* Check the length. */
+      if (*length - v->namelen != sizeof (struct in_addr))
+       return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr);
+
+      peer = peer_lookup_addr_ipv4 (addr);
+      return peer;
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4) len = 4;
+      
+      oid2in_addr (name + v->namelen, len, addr);
+      
+      peer = bgp_peer_lookup_next (addr);
+
+      if (peer == NULL)
+       return NULL;
+
+      oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
+      *length = sizeof (struct in_addr) + v->namelen;
+
+      return peer;
+    }
+  return NULL;
+}
+
+/* BGP write methods. */
+int
+write_bgpPeerTable (int action, u_char *var_val,
+                   u_char var_val_type, size_t var_val_len,
+                   u_char *statP, oid *name, size_t length,
+                   struct variable *v)
+{
+  struct in_addr addr;
+  struct peer *peer;
+  long intval;
+  int bigsize = SNMP_MAX_LEN;
+  
+  if (var_val_type != ASN_INTEGER) 
+    {
+      return SNMP_ERR_WRONGTYPE;
+    }
+  if (var_val_len != sizeof (long)) 
+    {
+      return SNMP_ERR_WRONGLENGTH;
+    }
+
+  if (! asn_parse_int(var_val, &bigsize, &var_val_type,
+                      &intval, sizeof(long)))
+    {
+      return SNMP_ERR_WRONGENCODING;
+    }
+
+  memset (&addr, 0, sizeof (struct in_addr));
+
+  peer = bgpPeerTable_lookup (v, name, &length, &addr, 1);
+  if (! peer)
+    return SNMP_ERR_NOSUCHNAME;
+
+  printf ("val: %ld\n", intval);
+
+  switch (v->magic)
+    {
+    case BGPPEERADMINSTATUS:
+#define BGP_PeerAdmin_stop  1
+#define BGP_PeerAdmin_start 2
+      /* When the peer is established,   */
+      if (intval == BGP_PeerAdmin_stop)
+       BGP_EVENT_ADD (peer, BGP_Stop);
+      else if (intval == BGP_PeerAdmin_start)
+       ;                       /* Do nothing. */
+      else
+       return SNMP_ERR_NOSUCHNAME;
+      break;
+    case BGPPEERCONNECTRETRYINTERVAL:
+      SET_FLAG (peer->config, PEER_CONFIG_CONNECT);
+      peer->connect = intval;
+      peer->v_connect = intval;
+      break;
+    case BGPPEERHOLDTIMECONFIGURED:
+      SET_FLAG (peer->config, PEER_CONFIG_TIMER);
+      peer->holdtime = intval;
+      peer->v_holdtime = intval;
+      break;
+    case BGPPEERKEEPALIVECONFIGURED:
+      SET_FLAG (peer->config, PEER_CONFIG_TIMER);
+      peer->keepalive = intval;
+      peer->v_keepalive = intval;
+      break;
+    case BGPPEERMINASORIGINATIONINTERVAL:
+      peer->v_asorig = intval;
+      break;
+    case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
+      peer->v_routeadv = intval;
+      break;
+    }
+  return SNMP_ERR_NOERROR;
+}
+
+u_char *
+bgpPeerTable (struct variable *v, oid name[], size_t *length,
+             int exact, size_t *var_len, WriteMethod **write_method)
+{
+  static struct in_addr addr;
+  struct peer *peer;
+
+  *write_method = NULL;
+  memset (&addr, 0, sizeof (struct in_addr));
+
+  peer = bgpPeerTable_lookup (v, name, length, &addr, exact);
+  if (! peer)
+    return NULL;
+
+  switch (v->magic)
+    {
+    case BGPPEERIDENTIFIER:
+      return SNMP_IPADDRESS (peer->remote_id);
+      break;
+    case BGPPEERSTATE:
+      return SNMP_INTEGER (peer->status);
+      break;
+    case BGPPEERADMINSTATUS:
+      *write_method = write_bgpPeerTable;
+#define BGP_PeerAdmin_stop  1
+#define BGP_PeerAdmin_start 2
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
+       return SNMP_INTEGER (BGP_PeerAdmin_stop);
+      else
+       return SNMP_INTEGER (BGP_PeerAdmin_start);
+      break;
+    case BGPPEERNEGOTIATEDVERSION:
+      return SNMP_INTEGER (peer->version);
+      break;
+    case BGPPEERLOCALADDR:
+      if (peer->su_local)
+       return SNMP_IPADDRESS (peer->su_local->sin.sin_addr);
+      else
+       return SNMP_IPADDRESS (bgp_empty_addr);
+      break;
+    case BGPPEERLOCALPORT:
+      if (peer->su_local)
+       return SNMP_INTEGER (ntohs (peer->su_local->sin.sin_port));
+      else
+       return SNMP_INTEGER (0);
+      break;
+    case BGPPEERREMOTEADDR:
+      if (peer->su_remote)
+       return SNMP_IPADDRESS (peer->su_remote->sin.sin_addr);
+      else
+       return SNMP_IPADDRESS (bgp_empty_addr);
+      break;
+    case BGPPEERREMOTEPORT:
+      if (peer->su_remote)
+       return SNMP_INTEGER (ntohs (peer->su_remote->sin.sin_port));
+      else
+       return SNMP_INTEGER (0);
+      break;
+    case BGPPEERREMOTEAS:
+      return SNMP_INTEGER (peer->as);
+      break;
+    case BGPPEERINUPDATES:
+      return SNMP_INTEGER (peer->update_in);
+      break;
+    case BGPPEEROUTUPDATES:
+      return SNMP_INTEGER (peer->update_out);
+      break;
+    case BGPPEERINTOTALMESSAGES:
+      return SNMP_INTEGER (peer->open_in + peer->update_in
+                          + peer->keepalive_in + peer->notify_in
+                          + peer->refresh_in + peer->dynamic_cap_in);
+      break;
+    case BGPPEEROUTTOTALMESSAGES:
+      return SNMP_INTEGER (peer->open_out + peer->update_out
+                          + peer->keepalive_out + peer->notify_out
+                          + peer->refresh_out, peer->dynamic_cap_out);
+      break;
+    case BGPPEERLASTERROR:
+      {
+       static u_char lasterror[2];
+       lasterror[0] = peer->notify.code;
+       lasterror[1] = peer->notify.subcode;
+       *var_len = 2;
+       return (u_char *)&lasterror;
+      }
+      break;
+    case BGPPEERFSMESTABLISHEDTRANSITIONS:
+      return SNMP_INTEGER (peer->established);
+      break;
+    case BGPPEERFSMESTABLISHEDTIME:
+      if (peer->uptime == 0)
+       return SNMP_INTEGER (0);
+      else
+       return SNMP_INTEGER (time (NULL) - peer->uptime);
+      break;
+    case BGPPEERCONNECTRETRYINTERVAL:
+      *write_method = write_bgpPeerTable;
+      return SNMP_INTEGER (peer->v_connect);
+      break;
+    case BGPPEERHOLDTIME:
+      return SNMP_INTEGER (peer->v_holdtime);
+      break;
+    case BGPPEERKEEPALIVE:
+      return SNMP_INTEGER (peer->v_keepalive);
+      break;
+    case BGPPEERHOLDTIMECONFIGURED:
+      *write_method = write_bgpPeerTable;
+      if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
+       return SNMP_INTEGER (peer->holdtime);
+      else
+       return SNMP_INTEGER (peer->v_holdtime);
+      break;
+    case BGPPEERKEEPALIVECONFIGURED:
+      *write_method = write_bgpPeerTable;
+      if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
+       return SNMP_INTEGER (peer->keepalive);
+      else
+       return SNMP_INTEGER (peer->v_keepalive);
+      break;
+    case BGPPEERMINASORIGINATIONINTERVAL:
+      *write_method = write_bgpPeerTable;
+      return SNMP_INTEGER (peer->v_asorig);
+      break;
+    case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
+      *write_method = write_bgpPeerTable;
+      return SNMP_INTEGER (peer->v_routeadv);
+      break;
+    case BGPPEERINUPDATEELAPSEDTIME:
+      if (peer->update_time == 0)
+       return SNMP_INTEGER (0);
+      else
+       return SNMP_INTEGER (time (NULL) - peer->update_time);
+      break;
+    default:
+      return NULL;
+      break;
+    }  
+  return NULL;
+}
+
+u_char *
+bgpIdentifier (struct variable *v, oid name[], size_t *length,
+              int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct bgp *bgp;
+
+  if (smux_header_generic(v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  bgp = bgp_get_default ();
+  if (!bgp)
+    return NULL;
+
+  return SNMP_IPADDRESS (bgp->router_id);
+}
+
+u_char *
+bgpRcvdPathAttrTable (struct variable *v, oid name[], size_t *length,
+                     int exact, size_t *var_len, WriteMethod **write_method)
+{
+  /* Received Path Attribute Table.  This table contains, one entry
+     per path to a network, path attributes received from all peers
+     running BGP version 3 or less.  This table is obsolete, having
+     been replaced in functionality with the bgp4PathAttrTable.  */
+  return NULL;
+}
+
+struct bgp_info *
+bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length,
+                   struct bgp *bgp, struct prefix_ipv4 *addr, int exact)
+{
+  oid *offset;
+  int offsetlen;
+  struct bgp_info *binfo;
+  struct bgp_info *min;
+  struct bgp_node *rn;
+  union sockunion su;
+  int len;
+  struct in_addr paddr;
+
+#define BGP_PATHATTR_ENTRY_OFFSET \
+          (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE)
+
+  if (exact)
+    {
+      if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET)
+       return NULL;
+
+      /* Set OID offset for prefix. */
+      offset = name + v->namelen;
+      oid2in_addr (offset, IN_ADDR_SIZE, &addr->prefix);
+      offset += IN_ADDR_SIZE;
+
+      /* Prefix length. */
+      addr->prefixlen = *offset;
+      offset++;
+
+      /* Peer address. */
+      su.sin.sin_family = AF_INET;
+      oid2in_addr (offset, IN_ADDR_SIZE, &su.sin.sin_addr);
+
+      /* Lookup node. */
+      rn = bgp_node_lookup (bgp->rib[AFI_IP][SAFI_UNICAST], 
+                             (struct prefix *) addr);
+      if (rn)
+       {
+         bgp_unlock_node (rn);
+
+         for (binfo = rn->info; binfo; binfo = binfo->next)
+           if (sockunion_same (&binfo->peer->su, &su))
+             return binfo;
+       }
+    }
+  else
+    {
+      offset = name + v->namelen;
+      offsetlen = *length - v->namelen;
+      len = offsetlen;
+
+      if (offsetlen == 0)
+       rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]);
+      else
+       {
+         if (len > IN_ADDR_SIZE)
+           len = IN_ADDR_SIZE;
+      
+         oid2in_addr (offset, len, &addr->prefix);
+
+         offset += IN_ADDR_SIZE;
+         offsetlen -= IN_ADDR_SIZE;
+
+         if (offsetlen > 0)
+           addr->prefixlen = *offset;
+         else
+           addr->prefixlen = len * 8;
+
+         rn = bgp_node_get (bgp->rib[AFI_IP][SAFI_UNICAST],
+                              (struct prefix *) addr);
+
+         offset++;
+         offsetlen--;
+       }
+
+      if (offsetlen > 0)
+       {
+         len = offsetlen;
+         if (len > IN_ADDR_SIZE)
+           len = IN_ADDR_SIZE;
+
+         oid2in_addr (offset, len, &paddr);
+       }
+      else
+       paddr.s_addr = 0;
+
+      if (! rn)
+       return NULL;
+
+      do
+       {
+         min = NULL;
+
+         for (binfo = rn->info; binfo; binfo = binfo->next)
+           {
+             if (binfo->peer->su.sin.sin_family == AF_INET
+                 && ntohl (paddr.s_addr) 
+                 < ntohl (binfo->peer->su.sin.sin_addr.s_addr))
+               {
+                 if (min)
+                   {
+                     if (ntohl (binfo->peer->su.sin.sin_addr.s_addr) 
+                         < ntohl (min->peer->su.sin.sin_addr.s_addr))
+                       min = binfo;
+                   }
+                 else
+                   min = binfo;
+               }
+           }
+
+         if (min)
+           {
+             *length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET;
+
+             offset = name + v->namelen;
+             oid_copy_addr (offset, &rn->p.u.prefix4, IN_ADDR_SIZE);
+             offset += IN_ADDR_SIZE;
+             *offset = rn->p.prefixlen;
+             offset++;
+             oid_copy_addr (offset, &min->peer->su.sin.sin_addr, 
+                            IN_ADDR_SIZE);
+             addr->prefix = rn->p.u.prefix4;
+             addr->prefixlen = rn->p.prefixlen;
+
+             bgp_unlock_node (rn);
+
+             return min;
+           }
+
+         paddr.s_addr = 0;
+       }
+      while ((rn = bgp_route_next (rn)) != NULL);
+    }
+  return NULL;
+}
+
+u_char *
+bgp4PathAttrTable (struct variable *v, oid name[], size_t *length,
+                  int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct bgp *bgp;
+  struct bgp_info *binfo;
+  struct prefix_ipv4 addr;
+  
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return NULL;
+
+  memset (&addr, 0, sizeof (struct prefix_ipv4));
+
+  binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact);
+  if (! binfo)
+    return NULL;
+
+  switch (v->magic)
+    {
+    case BGP4PATHATTRPEER:     /* 1 */
+      return SNMP_IPADDRESS (binfo->peer->su.sin.sin_addr);
+      break;
+    case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */
+      return SNMP_INTEGER (addr.prefixlen);
+      break;
+    case BGP4PATHATTRIPADDRPREFIX: /* 3 */
+      return SNMP_IPADDRESS (addr.prefix);
+      break;
+    case BGP4PATHATTRORIGIN:   /* 4 */
+      return SNMP_INTEGER (binfo->attr->origin);
+      break;
+    case BGP4PATHATTRASPATHSEGMENT: /* 5 */
+      *var_len = binfo->attr->aspath->length;
+      return (u_char *) binfo->attr->aspath->data;
+      break;
+    case BGP4PATHATTRNEXTHOP:  /* 6 */
+      return SNMP_IPADDRESS (binfo->attr->nexthop);
+      break;
+    case BGP4PATHATTRMULTIEXITDISC: /* 7 */
+      return SNMP_INTEGER (binfo->attr->med);
+      break;
+    case BGP4PATHATTRLOCALPREF:        /* 8 */
+      return SNMP_INTEGER (binfo->attr->local_pref);
+      break;
+    case BGP4PATHATTRATOMICAGGREGATE: /* 9 */
+      return SNMP_INTEGER (1);
+      break;
+    case BGP4PATHATTRAGGREGATORAS: /* 10 */
+      return SNMP_INTEGER (binfo->attr->aggregator_as);
+      break;
+    case BGP4PATHATTRAGGREGATORADDR: /* 11 */
+      return SNMP_IPADDRESS (binfo->attr->aggregator_addr);
+      break;
+    case BGP4PATHATTRCALCLOCALPREF: /* 12 */
+      return SNMP_INTEGER (-1);
+      break;
+    case BGP4PATHATTRBEST:     /* 13 */
+#define BGP4_PathAttrBest_false 1
+#define BGP4_PathAttrBest_true  2
+      if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+       return SNMP_INTEGER (BGP4_PathAttrBest_true);
+      else
+       return SNMP_INTEGER (BGP4_PathAttrBest_false);
+      break;
+    case BGP4PATHATTRUNKNOWN:  /* 14 */
+      *var_len = 0;
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+/* BGP Traps. */
+struct trap_object bgpTrapList[] =
+{
+  {bgpPeerTable, 3, {3, 1, BGPPEERREMOTEADDR}},
+  {bgpPeerTable, 3, {3, 1, BGPPEERLASTERROR}},
+  {bgpPeerTable, 3, {3, 1, BGPPEERSTATE}}
+};
+
+void
+bgpTrapEstablished (struct peer *peer)
+{
+  int ret;
+  struct in_addr addr;
+  oid index[sizeof (oid) * IN_ADDR_SIZE];
+
+  ret = inet_aton (peer->host, &addr);
+  if (ret == 0)
+    return;
+
+  oid_copy_addr (index, &addr, IN_ADDR_SIZE);
+
+  smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid),
+            index, IN_ADDR_SIZE,
+            bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object),
+            bm->start_time - time (NULL));
+}
+
+void
+bgpTrapBackwardTransition (struct peer *peer)
+{
+  int ret;
+  struct in_addr addr;
+  oid index[sizeof (oid) * IN_ADDR_SIZE];
+
+  ret = inet_aton (peer->host, &addr);
+  if (ret == 0)
+    return;
+
+  oid_copy_addr (index, &addr, IN_ADDR_SIZE);
+
+  smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid),
+            index, IN_ADDR_SIZE,
+            bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object),
+            bm->start_time - time (NULL));
+}
+
+void
+bgp_snmp_init ()
+{
+  smux_init (bgpd_oid, sizeof bgpd_oid / sizeof (oid));
+  REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid);
+  smux_start ();
+}
+#endif /* HAVE_SNMP */
diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h
new file mode 100644 (file)
index 0000000..a8af032
--- /dev/null
@@ -0,0 +1,23 @@
+/* BGP4 SNMP support
+   Copyright (C) 1999, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+void bgp_snmp_init ();
+void bgpTrapEstablished (struct peer *);
+void bgpTrapBackwardTransition (struct peer *);
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
new file mode 100644 (file)
index 0000000..a2a3c97
--- /dev/null
@@ -0,0 +1,489 @@
+/* BGP routing table
+   Copyright (C) 1998, 2001 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "vty.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+
+void bgp_node_delete (struct bgp_node *);
+void bgp_table_free (struct bgp_table *);
+\f
+struct bgp_table *
+bgp_table_init (void)
+{
+  struct bgp_table *rt;
+
+  rt = XMALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table));
+  memset (rt, 0, sizeof (struct bgp_table));
+  return rt;
+}
+
+void
+bgp_table_finish (struct bgp_table *rt)
+{
+  bgp_table_free (rt);
+}
+
+struct bgp_node *
+bgp_node_create ()
+{
+  struct bgp_node *rn;
+
+  rn = (struct bgp_node *) XMALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node));
+  memset (rn, 0, sizeof (struct bgp_node));
+  return rn;
+}
+
+/* Allocate new route node with prefix set. */
+struct bgp_node *
+bgp_node_set (struct bgp_table *table, struct prefix *prefix)
+{
+  struct bgp_node *node;
+  
+  node = bgp_node_create ();
+
+  prefix_copy (&node->p, prefix);
+  node->table = table;
+
+  return node;
+}
+
+/* Free route node. */
+void
+bgp_node_free (struct bgp_node *node)
+{
+  XFREE (MTYPE_BGP_NODE, node);
+}
+
+/* Free route table. */
+void
+bgp_table_free (struct bgp_table *rt)
+{
+  struct bgp_node *tmp_node;
+  struct bgp_node *node;
+  if (rt == NULL)
+    return;
+
+  node = rt->top;
+
+  while (node)
+    {
+      if (node->l_left)
+       {
+         node = node->l_left;
+         continue;
+       }
+
+      if (node->l_right)
+       {
+         node = node->l_right;
+         continue;
+       }
+
+      tmp_node = node;
+      node = node->parent;
+
+      if (node != NULL)
+       {
+         if (node->l_left == tmp_node)
+           node->l_left = NULL;
+         else
+           node->l_right = NULL;
+
+         bgp_node_free (tmp_node);
+       }
+      else
+       {
+         bgp_node_free (tmp_node);
+         break;
+       }
+    }
+  XFREE (MTYPE_BGP_TABLE, rt);
+  return;
+}
+
+/* Utility mask array. */
+static u_char maskbit[] = 
+{
+  0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+};
+
+/* Common prefix route genaration. */
+static void
+route_common (struct prefix *n, struct prefix *p, struct prefix *new)
+{
+  int i;
+  u_char diff;
+  u_char mask;
+
+  u_char *np = (u_char *)&n->u.prefix;
+  u_char *pp = (u_char *)&p->u.prefix;
+  u_char *newp = (u_char *)&new->u.prefix;
+
+  for (i = 0; i < p->prefixlen / 8; i++)
+    {
+      if (np[i] == pp[i])
+       newp[i] = np[i];
+      else
+       break;
+    }
+
+  new->prefixlen = i * 8;
+
+  if (new->prefixlen != p->prefixlen)
+    {
+      diff = np[i] ^ pp[i];
+      mask = 0x80;
+      while (new->prefixlen < p->prefixlen && !(mask & diff))
+       {
+         mask >>= 1;
+         new->prefixlen++;
+       }
+      newp[i] = np[i] & maskbit[new->prefixlen % 8];
+    }
+}
+
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
+
+/* Check bit of the prefix. */
+static int
+check_bit (u_char *prefix, u_char prefixlen)
+{
+  int offset;
+  int shift;
+  u_char *p = (u_char *)prefix;
+
+  assert (prefixlen <= 128);
+
+  offset = prefixlen / 8;
+  shift = 7 - (prefixlen % 8);
+  
+  return (p[offset] >> shift & 1);
+}
+
+/* Macro version of set_link (). */
+#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\
+                      (Y)->parent = (X)
+
+static void
+set_link (struct bgp_node *node, struct bgp_node *new)
+{
+  int bit;
+    
+  bit = check_bit (&new->p.u.prefix, node->p.prefixlen);
+
+  assert (bit == 0 || bit == 1);
+
+  node->link[bit] = new;
+  new->parent = node;
+}
+
+/* Lock node. */
+struct bgp_node *
+bgp_lock_node (struct bgp_node *node)
+{
+  node->lock++;
+  return node;
+}
+
+/* Unlock node. */
+void
+bgp_unlock_node (struct bgp_node *node)
+{
+  node->lock--;
+
+  if (node->lock == 0)
+    bgp_node_delete (node);
+}
+
+/* Find matched prefix. */
+struct bgp_node *
+bgp_node_match (struct bgp_table *table, struct prefix *p)
+{
+  struct bgp_node *node;
+  struct bgp_node *matched;
+
+  matched = NULL;
+  node = table->top;
+
+  /* Walk down tree.  If there is matched route then store it to
+     matched. */
+  while (node && node->p.prefixlen <= p->prefixlen && 
+        prefix_match (&node->p, p))
+    {
+      if (node->info)
+       matched = node;
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  /* If matched route found, return it. */
+  if (matched)
+    return bgp_lock_node (matched);
+
+  return NULL;
+}
+
+struct bgp_node *
+bgp_node_match_ipv4 (struct bgp_table *table, struct in_addr *addr)
+{
+  struct prefix_ipv4 p;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *addr;
+
+  return bgp_node_match (table, (struct prefix *) &p);
+}
+
+#ifdef HAVE_IPV6
+struct bgp_node *
+bgp_node_match_ipv6 (struct bgp_table *table, struct in6_addr *addr)
+{
+  struct prefix_ipv6 p;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  p.prefix = *addr;
+
+  return bgp_node_match (table, (struct prefix *) &p);
+}
+#endif /* HAVE_IPV6 */
+
+/* Lookup same prefix node.  Return NULL when we can't find route. */
+struct bgp_node *
+bgp_node_lookup (struct bgp_table *table, struct prefix *p)
+{
+  struct bgp_node *node;
+
+  node = table->top;
+
+  while (node && node->p.prefixlen <= p->prefixlen && 
+        prefix_match (&node->p, p))
+    {
+      if (node->p.prefixlen == p->prefixlen && node->info)
+       return bgp_lock_node (node);
+
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  return NULL;
+}
+
+/* Add node to routing table. */
+struct bgp_node *
+bgp_node_get (struct bgp_table *table, struct prefix *p)
+{
+  struct bgp_node *new;
+  struct bgp_node *node;
+  struct bgp_node *match;
+
+  match = NULL;
+  node = table->top;
+  while (node && node->p.prefixlen <= p->prefixlen && 
+        prefix_match (&node->p, p))
+    {
+      if (node->p.prefixlen == p->prefixlen)
+       {
+         bgp_lock_node (node);
+         return node;
+       }
+      match = node;
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  if (node == NULL)
+    {
+      new = bgp_node_set (table, p);
+      if (match)
+       set_link (match, new);
+      else
+       table->top = new;
+    }
+  else
+    {
+      new = bgp_node_create ();
+      route_common (&node->p, p, &new->p);
+      new->p.family = p->family;
+      new->table = table;
+      set_link (new, node);
+
+      if (match)
+       set_link (match, new);
+      else
+       table->top = new;
+
+      if (new->p.prefixlen != p->prefixlen)
+       {
+         match = new;
+         new = bgp_node_set (table, p);
+         set_link (match, new);
+       }
+    }
+  bgp_lock_node (new);
+  
+  return new;
+}
+
+/* Delete node from the routing table. */
+void
+bgp_node_delete (struct bgp_node *node)
+{
+  struct bgp_node *child;
+  struct bgp_node *parent;
+
+  assert (node->lock == 0);
+  assert (node->info == NULL);
+
+  if (node->l_left && node->l_right)
+    return;
+
+  if (node->l_left)
+    child = node->l_left;
+  else
+    child = node->l_right;
+
+  parent = node->parent;
+
+  if (child)
+    child->parent = parent;
+
+  if (parent)
+    {
+      if (parent->l_left == node)
+       parent->l_left = child;
+      else
+       parent->l_right = child;
+    }
+  else
+    node->table->top = child;
+
+  bgp_node_free (node);
+
+  /* If parent node is stub then delete it also. */
+  if (parent && parent->lock == 0)
+    bgp_node_delete (parent);
+}
+
+/* Get fist node and lock it.  This function is useful when one want
+   to lookup all the node exist in the routing table. */
+struct bgp_node *
+bgp_table_top (struct bgp_table *table)
+{
+  /* If there is no node in the routing table return NULL. */
+  if (table->top == NULL)
+    return NULL;
+
+  /* Lock the top node and return it. */
+  bgp_lock_node (table->top);
+  return table->top;
+}
+
+/* Unlock current node and lock next node then return it. */
+struct bgp_node *
+bgp_route_next (struct bgp_node *node)
+{
+  struct bgp_node *next;
+  struct bgp_node *start;
+
+  /* Node may be deleted from bgp_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
+    {
+      next = node->l_left;
+      bgp_lock_node (next);
+      bgp_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      bgp_lock_node (next);
+      bgp_unlock_node (node);
+      return next;
+    }
+
+  start = node;
+  while (node->parent)
+    {
+      if (node->parent->l_left == node && node->parent->l_right)
+       {
+         next = node->parent->l_right;
+         bgp_lock_node (next);
+         bgp_unlock_node (start);
+         return next;
+       }
+      node = node->parent;
+    }
+  bgp_unlock_node (start);
+  return NULL;
+}
+
+/* Unlock current node and lock next node until limit. */
+struct bgp_node *
+bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit)
+{
+  struct bgp_node *next;
+  struct bgp_node *start;
+
+  /* Node may be deleted from bgp_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
+    {
+      next = node->l_left;
+      bgp_lock_node (next);
+      bgp_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      bgp_lock_node (next);
+      bgp_unlock_node (node);
+      return next;
+    }
+
+  start = node;
+  while (node->parent && node != limit)
+    {
+      if (node->parent->l_left == node && node->parent->l_right)
+       {
+         next = node->parent->l_right;
+         bgp_lock_node (next);
+         bgp_unlock_node (start);
+         return next;
+       }
+      node = node->parent;
+    }
+  bgp_unlock_node (start);
+  return NULL;
+}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
new file mode 100644 (file)
index 0000000..52eb6a4
--- /dev/null
@@ -0,0 +1,65 @@
+/* BGP routing table
+   Copyright (C) 1998, 2001 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+struct bgp_table
+{
+  struct bgp_node *top;
+};
+
+struct bgp_node
+{
+  struct prefix p;
+
+  struct bgp_table *table;
+  struct bgp_node *parent;
+  struct bgp_node *link[2];
+#define l_left   link[0]
+#define l_right  link[1]
+
+  unsigned int lock;
+
+  void *info;
+
+  struct bgp_adj_out *adj_out;
+
+  struct bgp_adj_in *adj_in;
+
+  void *aggregate;
+
+  struct bgp_node *prn;
+};
+
+struct bgp_table *bgp_table_init (void);
+void bgp_table_finish (struct bgp_table *);
+void bgp_unlock_node (struct bgp_node *node);
+void bgp_node_delete (struct bgp_node *node);
+struct bgp_node *bgp_table_top (struct bgp_table *);
+struct bgp_node *bgp_route_next (struct bgp_node *);
+struct bgp_node *bgp_route_next_until (struct bgp_node *, struct bgp_node *);
+struct bgp_node *bgp_node_get (struct bgp_table *, struct prefix *);
+struct bgp_node *bgp_node_lookup (struct bgp_table *, struct prefix *);
+struct bgp_node *bgp_lock_node (struct bgp_node *node);
+struct bgp_node *bgp_node_match (struct bgp_table *, struct prefix *);
+struct bgp_node *bgp_node_match_ipv4 (struct bgp_table *,
+                                         struct in_addr *);
+#ifdef HAVE_IPV6
+struct bgp_node *bgp_node_match_ipv6 (struct bgp_table *,
+                                         struct in6_addr *);
+#endif /* HAVE_IPV6 */
diff --git a/bgpd/bgp_view.c b/bgpd/bgp_view.c
new file mode 100644 (file)
index 0000000..795d155
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * $Id: bgp_view.c,v 1.1 2002/12/13 20:15:29 paul Exp $
+ *
+ * Multiple view function for route server.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "zebra/zebra.h"
+#include "table.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_aspath.h"
+
+/* Static configuration of BGP annoucement. */
+struct route_table *bgp_static_ipv4;
+#ifdef HAVE_IPV6
+struct route_table *bgp_static_ipv6;
+#endif /* HAVE_IPV6 */
+
+/* Static annoucement peer. */
+struct peer *static_peer;
+
+/* Default value setting flag */
+#define VAL_LOCAL_PREF 0x01
+#define VAL_MED        0x02
+#define VAL_NEXT_HOP   0x04
+
+DEFUN (default_attr_localpref,
+       default_attr_localpref_cmd,
+       "default-attr local-pref NUMBER",
+       "Set default local preference value\n"
+       "Set default local preference value\n"
+       "Value\n")
+{
+  struct bgp *bgp;
+  long lpref;
+
+  bgp = (struct bgp *) vty->index;
+
+  lpref = strtol (argv[0], NULL, 10);
+
+  bgp->def |= VAL_LOCAL_PREF;
+  bgp->localpref = lpref;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_default_attr_localpref,
+       no_default_attr_localpref_cmd,
+       "no default-attr local-pref NUMBER",
+       NO_STR
+       "Unset default local preference value\n"
+       "Unset default local preference value\n"
+       "Value\n")
+{
+  struct bgp *bgp;
+
+  bgp = (struct bgp *) vty->index;
+
+  bgp->def &= ~DEFAULT_LOCAL_PREF;
+  bgp->localpref = 0;
+
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Network configuration for IPv6. */
+int
+bgp_network_config_ipv6 (struct vty *vty, char *address_str)
+{
+  int ret;
+  struct prefix p;
+  struct route_node *node;
+  struct bgp_info *bgp_info;
+
+  ret = str2prefix_ipv6 (address_str, (struct prefix_ipv6 *) &p);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify valid address\r\n");
+      return CMD_WARNING;
+    }
+
+  apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
+  
+  node = route_node_get (bgp_static_ipv6, &p);
+  if (node->info)
+    {
+      vty_out (vty, "There is already same static announcement.\r\n");
+      route_unlock_node (node);
+      return CMD_WARNING;
+    }
+
+  bgp_info = bgp_info_new ();
+  bgp_info->type = ZEBRA_ROUTE_STATIC;
+  bgp_info->peer = static_peer;
+  bgp_info->attr = bgp_attr_make_default ();
+  node->info = bgp_info;
+
+  nlri_process (&p, bgp_info);
+
+  return CMD_SUCCESS;
+}
+#endif
+
+/* Configure static BGP network. */
+DEFUN (bgp_network,
+       bgp_network_cmd,
+       "network PREFIX",
+       "Announce network setup\n"
+       "Static network for bgp announcement\n")
+{
+  int ret;
+  struct bgp *bgp;
+  struct prefix p;
+  struct route_node *node;
+  struct bgp_info *bgp_info;
+
+  bgp = (struct bgp *) vty->index;
+
+  ret = str2prefix_ipv4 (argv[0], (struct prefix_ipv4 *) &p);
+  if (!ret)
+    {
+#ifdef HAVE_IPV6
+      return bgp_network_config_ipv6 (vty, argv[0]);
+#endif /* HAVE_IPV6 */
+
+      vty_out (vty, "Please specify address by a.b.c.d/mask\r\n");
+      return CMD_WARNING;
+    }
+
+  /* Make sure mask is applied. */
+  apply_mask ((struct prefix_ipv4 *) &p);
+
+  node = route_node_get (bgp_static_ipv4, &p);
+  if (node->info)
+    {
+      vty_out (vty, "There is already same static announcement.\r\n");
+      route_unlock_node (node);
+      return CMD_WARNING;
+    }
+
+  bgp_info = bgp_info_new ();
+  bgp_info->type = ZEBRA_ROUTE_STATIC;
+  bgp_info->peer = static_peer;
+  bgp_info->attr = bgp_attr_make_default ();
+  node->info = bgp_info;
+
+  nlri_process (&p, bgp_info);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_network,
+       no_bgp_network_cmd,
+       "no network PREFIX",
+       NO_STR
+       "Announce network setup\n"
+       "Delete static network for bgp announcement\n")
+{
+  int ret;
+  struct bgp *bgp;
+  struct route_node *np;
+  struct prefix_ipv4 p;
+
+  bgp = (struct bgp *) vty->index;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify address by a.b.c.d/mask\r\n");
+      return CMD_WARNING;
+    }
+
+  apply_mask (&p);
+
+  np = route_node_get (bgp_static_ipv4, (struct prefix *) &p);
+  if (!np->info)
+    {
+      vty_out (vty, "Can't find specified static route configuration.\r\n");
+      route_unlock_node (np);
+      return CMD_WARNING;
+    }
+  nlri_delete (static_peer, (struct prefix *) &p);
+
+  /* bgp_attr_free (np->info); */
+  np->info = NULL;
+
+  route_unlock_node (np);
+
+  return CMD_SUCCESS;
+}
+
+int
+config_write_network (struct vty *vty, struct bgp *bgp)
+{
+  struct route_node *node;
+  struct bgp_route *route;
+  char buf[BUFSIZ];
+  
+  for (node = route_top (bgp_static_ipv4); node; node = route_next (node)) 
+    for (route = node->info; route; route = route->next)
+      vty_out (vty, " network %s/%d%s", 
+              inet_ntoa (node->p.u.prefix4), node->p.prefixlen, VTY_NEWLINE);
+#ifdef HAVE_IPV6
+  for (node = route_top (bgp_static_ipv6); node; node = route_next (node)) 
+    for (route = node->info; route; route = route->next)
+      vty_out (vty, " network %s/%d%s", 
+              inet_ntop (AF_INET6, &node->p.u.prefix6, buf, BUFSIZ),
+              node->p.prefixlen, VTY_NEWLINE);
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+void
+view_init ()
+{
+  bgp_static_ipv4 = route_table_init ();
+#ifdef HAVE_IPV6
+  bgp_static_ipv6 = route_table_init ();
+#endif /* HAVE_IPV6 */
+
+  static_peer = peer_new ();
+  static_peer->host = "Static annucement";
+
+  install_element (BGP_NODE, &bgp_network_cmd);
+  install_element (BGP_NODE, &no_bgp_network_cmd);
+  install_element (BGP_NODE, &default_attr_localpref_cmd);
+  install_element (BGP_NODE, &no_default_attr_localpref_cmd);
+}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
new file mode 100644 (file)
index 0000000..c1bae93
--- /dev/null
@@ -0,0 +1,9416 @@
+/* BGP VTY interface.
+   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "plist.h"
+#include "buffer.h"
+#include "linklist.h"
+#include "stream.h"
+#include "thread.h"
+#include "log.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_zebra.h"
+
+/* Utility function to get address family from current node.  */
+afi_t
+bgp_node_afi (struct vty *vty)
+{
+  if (vty->node == BGP_IPV6_NODE)
+    return AFI_IP6;
+  return AFI_IP;
+}
+
+/* Utility function to get subsequent address family from current
+   node.  */
+safi_t
+bgp_node_safi (struct vty *vty)
+{
+  if (vty->node == BGP_VPNV4_NODE)
+    return SAFI_MPLS_VPN;
+  if (vty->node == BGP_IPV4M_NODE)
+    return SAFI_MULTICAST;
+  return SAFI_UNICAST;
+}
+
+int
+peer_address_self_check (union sockunion *su)
+{
+  struct interface *ifp = NULL;
+
+  if (su->sa.sa_family == AF_INET)
+    ifp = if_lookup_by_ipv4_exact (&su->sin.sin_addr);
+#ifdef HAVE_IPV6
+  else if (su->sa.sa_family == AF_INET6)
+    ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr);
+#endif /* HAVE IPV6 */
+
+  if (ifp)
+    return 1;
+
+  return 0;
+}
+
+/* Utility function for looking up peer from VTY.  */
+struct peer *
+peer_lookup_vty (struct vty *vty, char *ip_str)
+{
+  int ret;
+  struct bgp *bgp;
+  union sockunion su;
+  struct peer *peer;
+
+  bgp = vty->index;
+
+  ret = str2sockunion (ip_str, &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE);
+      return NULL;
+    }
+
+  peer = peer_lookup (bgp, &su);
+  if (! peer)
+    {
+      vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE);
+      return NULL;
+    }
+  return peer;
+}
+
+/* Utility function for looking up peer or peer group.  */
+struct peer *
+peer_and_group_lookup_vty (struct vty *vty, char *peer_str)
+{
+  int ret;
+  struct bgp *bgp;
+  union sockunion su;
+  struct peer *peer;
+  struct peer_group *group;
+
+  bgp = vty->index;
+
+  ret = str2sockunion (peer_str, &su);
+  if (ret == 0)
+    {
+      peer = peer_lookup (bgp, &su);
+      if (peer)
+       return peer;
+    }
+  else
+    {
+      group = peer_group_lookup (bgp, peer_str);
+      if (group)
+       return group->conf;
+    }
+
+  vty_out (vty, "%% Specify remote-as or peer-group commands first%s",
+          VTY_NEWLINE);
+
+  return NULL;
+}
+
+int
+bgp_vty_return (struct vty *vty, int ret)
+{
+  char *str = NULL;
+
+  switch (ret)
+    {
+    case BGP_ERR_INVALID_VALUE:
+      str = "Invalid value";
+      break;
+    case BGP_ERR_INVALID_FLAG:
+      str = "Invalid flag";
+      break;
+    case BGP_ERR_PEER_INACTIVE:
+      str = "Activate the neighbor for the address family first";
+      break;
+    case BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER:
+      str = "Invalid command for a peer-group member";
+      break;
+    case BGP_ERR_PEER_GROUP_SHUTDOWN:
+      str = "Peer-group has been shutdown. Activate the peer-group first";
+      break;
+    case BGP_ERR_PEER_GROUP_HAS_THE_FLAG:
+      str = "This peer is a peer-group member.  Please change peer-group configuration";
+      break;
+    case BGP_ERR_PEER_FLAG_CONFLICT:
+      str = "Can't set override-capability and strict-capability-match at the same time";
+      break;
+    case BGP_ERR_PEER_GROUP_MEMBER_EXISTS:
+      str = "No activate for peergroup can be given only if peer-group has no members";
+      break;
+    case BGP_ERR_PEER_BELONGS_TO_GROUP:
+      str = "No activate for an individual peer-group member is invalid";
+      break;
+    case BGP_ERR_PEER_GROUP_AF_UNCONFIGURED:
+      str = "Activate the peer-group for the address family first";
+      break;
+    case BGP_ERR_PEER_GROUP_NO_REMOTE_AS:
+      str = "Specify remote-as or peer-group remote AS first";
+      break;
+    case BGP_ERR_PEER_GROUP_CANT_CHANGE:
+      str = "Cannot change the peer-group. Deconfigure first";
+      break;
+    case BGP_ERR_PEER_GROUP_MISMATCH:
+      str = "Cannot have different peer-group for the neighbor";
+      break;
+    case BGP_ERR_PEER_FILTER_CONFLICT:
+      str = "Prefix/distribute list can not co-exist";
+      break;
+    case BGP_ERR_NOT_INTERNAL_PEER:
+      str = "Invalid command. Not an internal neighbor";
+      break;
+    case BGP_ERR_REMOVE_PRIVATE_AS:
+      str = "Private AS cannot be removed for IBGP peers";
+      break;
+    case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP:
+      str = "Local-AS allowed only for EBGP peers";
+      break;
+    case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS:
+      str = "Cannot have local-as same as BGP AS number";
+      break;
+    }
+  if (str)
+    {
+      vty_out (vty, "%% %s%s", str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+/* BGP global configuration.  */
+
+DEFUN (bgp_multiple_instance_func,
+       bgp_multiple_instance_cmd,
+       "bgp multiple-instance",
+       BGP_STR
+       "Enable bgp multiple instance\n")
+{
+  bgp_option_set (BGP_OPT_MULTIPLE_INSTANCE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_multiple_instance,
+       no_bgp_multiple_instance_cmd,
+       "no bgp multiple-instance",
+       NO_STR
+       BGP_STR
+       "BGP multiple instance\n")
+{
+  int ret;
+
+  ret = bgp_option_unset (BGP_OPT_MULTIPLE_INSTANCE);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% There are more than two BGP instances%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (bgp_config_type,
+       bgp_config_type_cmd,
+       "bgp config-type (cisco|zebra)",
+       BGP_STR
+       "Configuration type\n"
+       "cisco\n"
+       "zebra\n")
+{
+  if (strncmp (argv[0], "c", 1) == 0)
+    bgp_option_set (BGP_OPT_CONFIG_CISCO);
+  else
+    bgp_option_unset (BGP_OPT_CONFIG_CISCO);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_config_type,
+       no_bgp_config_type_cmd,
+       "no bgp config-type",
+       NO_STR
+       BGP_STR
+       "Display configuration type\n")
+{
+  bgp_option_unset (BGP_OPT_CONFIG_CISCO);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_synchronization,
+       no_synchronization_cmd,
+       "no synchronization",
+       NO_STR
+       "Perform IGP synchronization\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_auto_summary,
+       no_auto_summary_cmd,
+       "no auto-summary",
+       NO_STR
+       "Enable automatic network number summarization\n")
+{
+  return CMD_SUCCESS;
+}
+\f
+/* "router bgp" commands. */
+DEFUN (router_bgp, 
+       router_bgp_cmd, 
+       "router bgp <1-65535>",
+       ROUTER_STR
+       BGP_STR
+       AS_STR)
+{
+  int ret;
+  as_t as;
+  struct bgp *bgp;
+  char *name = NULL;
+
+  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535);
+
+  if (argc == 2)
+    name = argv[1];
+
+  ret = bgp_get (&bgp, &as, name);
+  switch (ret)
+    {
+    case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
+      vty_out (vty, "Please specify 'bgp multiple-instance' first%s", 
+              VTY_NEWLINE);
+      return CMD_WARNING;
+      break;
+    case BGP_ERR_AS_MISMATCH:
+      vty_out (vty, "BGP is already running; AS is %d%s", as, VTY_NEWLINE);
+      return CMD_WARNING;
+      break;
+    case BGP_ERR_INSTANCE_MISMATCH:
+      vty_out (vty, "BGP view name and AS number mismatch%s", VTY_NEWLINE);
+      vty_out (vty, "BGP instance is already running; AS is %d%s",
+              as, VTY_NEWLINE);
+      return CMD_WARNING;
+      break;
+    }
+
+  vty->node = BGP_NODE;
+  vty->index = bgp;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (router_bgp,
+       router_bgp_view_cmd,
+       "router bgp <1-65535> view WORD",
+       ROUTER_STR
+       BGP_STR
+       AS_STR
+       "BGP view\n"
+       "view name\n")
+\f
+/* "no router bgp" commands. */
+DEFUN (no_router_bgp,
+       no_router_bgp_cmd,
+       "no router bgp <1-65535>",
+       NO_STR
+       ROUTER_STR
+       BGP_STR
+       AS_STR)
+{
+  as_t as;
+  struct bgp *bgp;
+  char *name = NULL;
+
+  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535);
+
+  if (argc == 2)
+    name = argv[1];
+
+  /* Lookup bgp structure. */
+  bgp = bgp_lookup (as, name);
+  if (! bgp)
+    {
+      vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_delete (bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_router_bgp,
+       no_router_bgp_view_cmd,
+       "no router bgp <1-65535> view WORD",
+       NO_STR
+       ROUTER_STR
+       BGP_STR
+       AS_STR
+       "BGP view\n"
+       "view name\n")
+\f
+/* BGP router-id.  */
+
+DEFUN (bgp_router_id,
+       bgp_router_id_cmd,
+       "bgp router-id A.B.C.D",
+       BGP_STR
+       "Override configured router identifier\n"
+       "Manually configured router identifier\n")
+{
+  int ret;
+  struct in_addr id;
+  struct bgp *bgp;
+
+  bgp = vty->index;
+
+  ret = inet_aton (argv[0], &id);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed bgp router identifier%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_router_id_set (bgp, &id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_router_id,
+       no_bgp_router_id_cmd,
+       "no bgp router-id",
+       NO_STR
+       BGP_STR
+       "Override configured router identifier\n")
+{
+  int ret;
+  struct in_addr id;
+  struct bgp *bgp;
+
+  bgp = vty->index;
+
+  if (argc == 1)
+    {
+      ret = inet_aton (argv[0], &id);
+      if (! ret)
+       {
+         vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      if (! IPV4_ADDR_SAME (&bgp->router_id, &id))
+       {
+         vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+
+  bgp_router_id_unset (bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_router_id,
+       no_bgp_router_id_val_cmd,
+       "no bgp router-id A.B.C.D",
+       NO_STR
+       BGP_STR
+       "Override configured router identifier\n"
+       "Manually configured router identifier\n")
+\f
+/* BGP Cluster ID.  */
+
+DEFUN (bgp_cluster_id,
+       bgp_cluster_id_cmd,
+       "bgp cluster-id A.B.C.D",
+       BGP_STR
+       "Configure Route-Reflector Cluster-id\n"
+       "Route-Reflector Cluster-id in IP address format\n")
+{
+  int ret;
+  struct bgp *bgp;
+  struct in_addr cluster;
+
+  bgp = vty->index;
+
+  ret = inet_aton (argv[0], &cluster);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_cluster_id_set (bgp, &cluster);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (bgp_cluster_id,
+       bgp_cluster_id32_cmd,
+       "bgp cluster-id <1-4294967295>",
+       BGP_STR
+       "Configure Route-Reflector Cluster-id\n"
+       "Route-Reflector Cluster-id as 32 bit quantity\n")
+
+DEFUN (no_bgp_cluster_id,
+       no_bgp_cluster_id_cmd,
+       "no bgp cluster-id",
+       NO_STR
+       BGP_STR
+       "Configure Route-Reflector Cluster-id\n")
+{
+  int ret;
+  struct bgp *bgp;
+  struct in_addr cluster;
+
+  bgp = vty->index;
+
+  if (argc == 1)
+    {
+      ret = inet_aton (argv[0], &cluster);
+      if (! ret)
+       {
+         vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+
+  bgp_cluster_id_unset (bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_cluster_id,
+       no_bgp_cluster_id_arg_cmd,
+       "no bgp cluster-id A.B.C.D",
+       NO_STR
+       BGP_STR
+       "Configure Route-Reflector Cluster-id\n"
+       "Route-Reflector Cluster-id in IP address format\n")
+\f
+DEFUN (bgp_confederation_identifier,
+       bgp_confederation_identifier_cmd,
+       "bgp confederation identifier <1-65535>",
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "AS number\n"
+       "Set routing domain confederation AS\n")
+{
+  struct bgp *bgp;
+  as_t as;
+
+  bgp = vty->index;
+
+  VTY_GET_INTEGER ("AS", as, argv[0]);
+
+  bgp_confederation_id_set (bgp, as);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_confederation_identifier,
+       no_bgp_confederation_identifier_cmd,
+       "no bgp confederation identifier",
+       NO_STR
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "AS number\n")
+{
+  struct bgp *bgp;
+  as_t as;
+
+  bgp = vty->index;
+
+  if (argc == 1)
+    VTY_GET_INTEGER ("AS", as, argv[0]);
+
+  bgp_confederation_id_unset (bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_confederation_identifier,
+       no_bgp_confederation_identifier_arg_cmd,
+       "no bgp confederation identifier <1-65535>",
+       NO_STR
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "AS number\n"
+       "Set routing domain confederation AS\n")
+\f
+DEFUN (bgp_confederation_peers,
+       bgp_confederation_peers_cmd,
+       "bgp confederation peers .<1-65535>",
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "Peer ASs in BGP confederation\n"
+       AS_STR)
+{
+  struct bgp *bgp;
+  as_t as;
+  int i;
+
+  bgp = vty->index;
+
+  for (i = 0; i < argc; i++)
+    {
+      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535);
+
+      if (bgp->as == as)
+       {
+         vty_out (vty, "%% Local member-AS not allowed in confed peer list%s",
+                  VTY_NEWLINE);
+         continue;
+       }
+
+      bgp_confederation_peers_add (bgp, as);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_confederation_peers,
+       no_bgp_confederation_peers_cmd,
+       "no bgp confederation peers .<1-65535>",
+       NO_STR
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "Peer ASs in BGP confederation\n"
+       AS_STR)
+{
+  struct bgp *bgp;
+  as_t as;
+  int i;
+
+  bgp = vty->index;
+
+  for (i = 0; i < argc; i++)
+    {
+      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535);
+      
+      bgp_confederation_peers_remove (bgp, as);
+    }
+  return CMD_SUCCESS;
+}
+\f
+/* BGP timers.  */
+
+DEFUN (bgp_timers,
+       bgp_timers_cmd,
+       "timers bgp <0-65535> <0-65535>",
+       "Adjust routing timers\n"
+       "BGP timers\n"
+       "Keepalive interval\n"
+       "Holdtime\n")
+{
+  struct bgp *bgp;
+  unsigned long keepalive = 0;
+  unsigned long holdtime = 0;
+
+  bgp = vty->index;
+
+  VTY_GET_INTEGER ("keepalive", keepalive, argv[0]);
+  VTY_GET_INTEGER ("holdtime", holdtime, argv[1]);
+
+  /* Holdtime value check. */
+  if (holdtime < 3 && holdtime != 0)
+    {
+      vty_out (vty, "%% hold time value must be either 0 or greater than 3%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_timers_set (bgp, keepalive, holdtime);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_timers,
+       no_bgp_timers_cmd,
+       "no timers bgp",
+       NO_STR
+       "Adjust routing timers\n"
+       "BGP timers\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_timers_unset (bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_timers,
+       no_bgp_timers_arg_cmd,
+       "no timers bgp <0-65535> <0-65535>",
+       NO_STR
+       "Adjust routing timers\n"
+       "BGP timers\n"
+       "Keepalive interval\n"
+       "Holdtime\n")
+\f
+DEFUN (bgp_client_to_client_reflection,
+       bgp_client_to_client_reflection_cmd,
+       "bgp client-to-client reflection",
+       "BGP specific commands\n"
+       "Configure client to client route reflection\n"
+       "reflection of routes allowed\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_client_to_client_reflection,
+       no_bgp_client_to_client_reflection_cmd,
+       "no bgp client-to-client reflection",
+       NO_STR
+       "BGP specific commands\n"
+       "Configure client to client route reflection\n"
+       "reflection of routes allowed\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT);
+  return CMD_SUCCESS;
+}
+
+/* "bgp always-compare-med" configuration. */
+DEFUN (bgp_always_compare_med,
+       bgp_always_compare_med_cmd,
+       "bgp always-compare-med",
+       "BGP specific commands\n"
+       "Allow comparing MED from different neighbors\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_ALWAYS_COMPARE_MED);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_always_compare_med,
+       no_bgp_always_compare_med_cmd,
+       "no bgp always-compare-med",
+       NO_STR
+       "BGP specific commands\n"
+       "Allow comparing MED from different neighbors\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp deterministic-med" configuration. */
+DEFUN (bgp_deterministic_med,
+       bgp_deterministic_med_cmd,
+       "bgp deterministic-med",
+       "BGP specific commands\n"
+       "Pick the best-MED path among paths advertised from the neighboring AS\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_deterministic_med,
+       no_bgp_deterministic_med_cmd,
+       "no bgp deterministic-med",
+       NO_STR
+       "BGP specific commands\n"
+       "Pick the best-MED path among paths advertised from the neighboring AS\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp fast-external-failover" configuration. */
+DEFUN (bgp_fast_external_failover,
+       bgp_fast_external_failover_cmd,
+       "bgp fast-external-failover",
+       BGP_STR
+       "Immediately reset session if a link to a directly connected external peer goes down\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_fast_external_failover,
+       no_bgp_fast_external_failover_cmd,
+       "no bgp fast-external-failover",
+       NO_STR
+       BGP_STR
+       "Immediately reset session if a link to a directly connected external peer goes down\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp enforce-first-as" configuration. */
+DEFUN (bgp_enforce_first_as,
+       bgp_enforce_first_as_cmd,
+       "bgp enforce-first-as",
+       BGP_STR
+       "Enforce the first AS for EBGP routes\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_ENFORCE_FIRST_AS);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_enforce_first_as,
+       no_bgp_enforce_first_as_cmd,
+       "no bgp enforce-first-as",
+       NO_STR
+       BGP_STR
+       "Enforce the first AS for EBGP routes\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp bestpath compare-routerid" configuration.  */
+DEFUN (bgp_bestpath_compare_router_id,
+       bgp_bestpath_compare_router_id_cmd,
+       "bgp bestpath compare-routerid",
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "Compare router-id for identical EBGP paths\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_COMPARE_ROUTER_ID);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_bestpath_compare_router_id,
+       no_bgp_bestpath_compare_router_id_cmd,
+       "no bgp bestpath compare-routerid",
+       NO_STR
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "Compare router-id for identical EBGP paths\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp bestpath as-path ignore" configuration.  */
+DEFUN (bgp_bestpath_aspath_ignore,
+       bgp_bestpath_aspath_ignore_cmd,
+       "bgp bestpath as-path ignore",
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "AS-path attribute\n"
+       "Ignore as-path length in selecting a route\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_ASPATH_IGNORE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_bestpath_aspath_ignore,
+       no_bgp_bestpath_aspath_ignore_cmd,
+       "no bgp bestpath as-path ignore",
+       NO_STR
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "AS-path attribute\n"
+       "Ignore as-path length in selecting a route\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp bestpath med" configuration. */
+DEFUN (bgp_bestpath_med,
+       bgp_bestpath_med_cmd,
+       "bgp bestpath med (confed|missing-as-worst)",
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+{
+  struct bgp *bgp;
+  
+  bgp = vty->index;
+
+  if (strncmp (argv[0], "confed", 1) == 0)
+    bgp_flag_set (bgp, BGP_FLAG_MED_CONFED);
+  else
+    bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (bgp_bestpath_med2,
+       bgp_bestpath_med2_cmd,
+       "bgp bestpath med confed missing-as-worst",
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+{
+  struct bgp *bgp;
+  
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_MED_CONFED);
+  bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST);
+  return CMD_SUCCESS;
+}
+
+ALIAS (bgp_bestpath_med2,
+       bgp_bestpath_med3_cmd,
+       "bgp bestpath med missing-as-worst confed",
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Treat missing MED as the least preferred one\n"
+       "Compare MED among confederation paths\n")
+
+DEFUN (no_bgp_bestpath_med,
+       no_bgp_bestpath_med_cmd,
+       "no bgp bestpath med (confed|missing-as-worst)",
+       NO_STR
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  
+  if (strncmp (argv[0], "confed", 1) == 0)
+    bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED);
+  else
+    bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_bestpath_med2,
+       no_bgp_bestpath_med2_cmd,
+       "no bgp bestpath med confed missing-as-worst",
+       NO_STR
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+{
+  struct bgp *bgp;
+  
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED);
+  bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_bestpath_med2,
+       no_bgp_bestpath_med3_cmd,
+       "no bgp bestpath med missing-as-worst confed",
+       NO_STR
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Treat missing MED as the least preferred one\n"
+       "Compare MED among confederation paths\n")
+\f
+/* "no bgp default ipv4-unicast". */
+DEFUN (no_bgp_default_ipv4_unicast,
+       no_bgp_default_ipv4_unicast_cmd,
+       "no bgp default ipv4-unicast",
+       NO_STR
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "Activate ipv4-unicast for a peer by default\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_NO_DEFAULT_IPV4);
+  return CMD_SUCCESS;
+}
+
+DEFUN (bgp_default_ipv4_unicast,
+       bgp_default_ipv4_unicast_cmd,
+       "bgp default ipv4-unicast",
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "Activate ipv4-unicast for a peer by default\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4);
+  return CMD_SUCCESS;
+}
+\f
+/* "bgp import-check" configuration.  */
+DEFUN (bgp_network_import_check,
+       bgp_network_import_check_cmd,
+       "bgp network import-check",
+       "BGP specific commands\n"
+       "BGP network command\n"
+       "Check BGP network route exists in IGP\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_network_import_check,
+       no_bgp_network_import_check_cmd,
+       "no bgp network import-check",
+       NO_STR
+       "BGP specific commands\n"
+       "BGP network command\n"
+       "Check BGP network route exists in IGP\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK);
+  return CMD_SUCCESS;
+}
+\f
+DEFUN (bgp_default_local_preference,
+       bgp_default_local_preference_cmd,
+       "bgp default local-preference <0-4294967295>",
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "local preference (higher=more preferred)\n"
+       "Configure default local preference value\n")
+{
+  struct bgp *bgp;
+  u_int32_t local_pref;
+
+  bgp = vty->index;
+
+  VTY_GET_INTEGER ("local preference", local_pref, argv[0]);
+
+  bgp_default_local_preference_set (bgp, local_pref);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_default_local_preference,
+       no_bgp_default_local_preference_cmd,
+       "no bgp default local-preference",
+       NO_STR
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "local preference (higher=more preferred)\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_default_local_preference_unset (bgp);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_default_local_preference,
+       no_bgp_default_local_preference_val_cmd,
+       "no bgp default local-preference <0-4294967295>",
+       NO_STR
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "local preference (higher=more preferred)\n"
+       "Configure default local preference value\n")
+\f
+static int
+peer_remote_as_vty (struct vty *vty, char *peer_str, char *as_str, afi_t afi,
+                   safi_t safi)
+{
+  int ret;
+  struct bgp *bgp;
+  as_t as;
+  union sockunion su;
+
+  bgp = vty->index;
+
+  /* Get AS number.  */
+  VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, 65535);
+
+  /* If peer is peer group, call proper function.  */
+  ret = str2sockunion (peer_str, &su);
+  if (ret < 0)
+    {
+      ret = peer_group_remote_as (bgp, peer_str, &as);
+      if (ret < 0)
+       {
+         vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      return CMD_SUCCESS;
+    }
+
+  if (peer_address_self_check (&su))
+    {
+      vty_out (vty, "%% Can not configure the local system as neighbor%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = peer_remote_as (bgp, &su, &as, afi, safi);
+
+  /* This peer belongs to peer group.  */
+  switch (ret)
+    {
+    case BGP_ERR_PEER_GROUP_MEMBER:
+      vty_out (vty, "%% Peer-group AS %d. Cannot configure remote-as for member%s", as, VTY_NEWLINE);
+      return CMD_WARNING;
+      break;
+    case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT:
+      vty_out (vty, "%% The AS# can not be changed from %d to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE);
+      return CMD_WARNING;
+      break;
+    }
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_remote_as,
+       neighbor_remote_as_cmd,
+       NEIGHBOR_CMD2 "remote-as <1-65535>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a BGP neighbor\n"
+       AS_STR)
+{
+  return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST);
+}
+\f
+DEFUN (neighbor_peer_group,
+       neighbor_peer_group_cmd,
+       "neighbor WORD peer-group",
+       NEIGHBOR_STR
+       "Neighbor tag\n"
+       "Configure peer-group\n")
+{
+  struct bgp *bgp;
+  struct peer_group *group;
+
+  bgp = vty->index;
+
+  group = peer_group_get (bgp, argv[0]);
+  if (! group)
+    return CMD_WARNING;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_neighbor,
+       no_neighbor_cmd,
+       NO_NEIGHBOR_CMD2,
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2)
+{
+  int ret;
+  union sockunion su;
+  struct peer_group *group;
+  struct peer *peer;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      group = peer_group_lookup (vty->index, argv[0]);
+      if (group)
+       peer_group_delete (group);
+      else
+       {
+         vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+  else
+    {
+      peer = peer_lookup (vty->index, &su);
+      if (peer)
+       peer_delete (peer);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_neighbor,
+       no_neighbor_remote_as_cmd,
+       NO_NEIGHBOR_CMD "remote-as <1-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Specify a BGP neighbor\n"
+       AS_STR)
+
+DEFUN (no_neighbor_peer_group,
+       no_neighbor_peer_group_cmd,
+       "no neighbor WORD peer-group",
+       NO_STR
+       NEIGHBOR_STR
+       "Neighbor tag\n"
+       "Configure peer-group\n")
+{
+  struct peer_group *group;
+
+  group = peer_group_lookup (vty->index, argv[0]);
+  if (group)
+    peer_group_delete (group);
+  else
+    {
+      vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_neighbor_peer_group_remote_as,
+       no_neighbor_peer_group_remote_as_cmd,
+       "no neighbor WORD remote-as <1-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       "Neighbor tag\n"
+       "Specify a BGP neighbor\n"
+       AS_STR)
+{
+  struct peer_group *group;
+
+  group = peer_group_lookup (vty->index, argv[0]);
+  if (group)
+    peer_group_remote_as_delete (group);
+  else
+    {
+      vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+\f
+DEFUN (neighbor_local_as,
+       neighbor_local_as_cmd,
+       NEIGHBOR_CMD2 "local-as <1-65535>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n"
+       "AS number used as local AS\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_local_as_set (peer, atoi (argv[1]), 0);
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_local_as_no_prepend,
+       neighbor_local_as_no_prepend_cmd,
+       NEIGHBOR_CMD2 "local-as <1-65535> no-prepend",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n"
+       "AS number used as local AS\n"
+       "Do not prepend local-as to updates from ebgp peers\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_local_as_set (peer, atoi (argv[1]), 1);
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (no_neighbor_local_as,
+       no_neighbor_local_as_cmd,
+       NO_NEIGHBOR_CMD2 "local-as",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_local_as_unset (peer);
+  return bgp_vty_return (vty, ret);
+}
+
+ALIAS (no_neighbor_local_as,
+       no_neighbor_local_as_val_cmd,
+       NO_NEIGHBOR_CMD2 "local-as <1-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n"
+       "AS number used as local AS\n")
+
+ALIAS (no_neighbor_local_as,
+       no_neighbor_local_as_val2_cmd,
+       NO_NEIGHBOR_CMD2 "local-as <1-65535> no-prepend",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n"
+       "AS number used as local AS\n"
+       "Do not prepend local-as to updates from ebgp peers\n")
+\f
+DEFUN (neighbor_activate,
+       neighbor_activate_cmd,
+       NEIGHBOR_CMD2 "activate",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Enable the Address Family for this Neighbor\n")
+{
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  peer_activate (peer, bgp_node_afi (vty), bgp_node_safi (vty));
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_neighbor_activate,
+       no_neighbor_activate_cmd,
+       NO_NEIGHBOR_CMD2 "activate",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Enable the Address Family for this Neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+
+  /* Lookup peer. */
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_deactivate (peer, bgp_node_afi (vty), bgp_node_safi (vty));
+
+  return bgp_vty_return (vty, ret);
+}
+\f
+DEFUN (neighbor_set_peer_group,
+       neighbor_set_peer_group_cmd,
+       NEIGHBOR_CMD "peer-group WORD",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Member of the peer-group\n"
+       "peer-group name\n")
+{
+  int ret;
+  as_t as;
+  union sockunion su;
+  struct bgp *bgp;
+  struct peer_group *group;
+
+  bgp = vty->index;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  group = peer_group_lookup (bgp, argv[1]);
+  if (! group)
+    {
+      vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (peer_address_self_check (&su))
+    {
+      vty_out (vty, "%% Can not configure the local system as neighbor%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty), 
+                        bgp_node_safi (vty), &as);
+
+  if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT)
+    {
+      vty_out (vty, "%% Peer with AS %d cannot be in this peer-group, members must be all internal or all external%s", as, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (no_neighbor_set_peer_group,
+       no_neighbor_set_peer_group_cmd,
+       NO_NEIGHBOR_CMD "peer-group WORD",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Member of the peer-group\n"
+       "peer-group name\n")
+{
+  int ret;
+  struct bgp *bgp;
+  struct peer *peer;
+  struct peer_group *group;
+
+  bgp = vty->index;
+
+  peer = peer_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  group = peer_group_lookup (bgp, argv[1]);
+  if (! group)
+    {
+      vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = peer_group_unbind (bgp, peer, group, bgp_node_afi (vty),
+                          bgp_node_safi (vty));
+
+  return bgp_vty_return (vty, ret);
+}
+\f
+int
+peer_flag_modify_vty (struct vty *vty, char *ip_str, u_int16_t flag, int set)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (set)
+    ret = peer_flag_set (peer, flag);
+  else
+    ret = peer_flag_unset (peer, flag);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_flag_set_vty (struct vty *vty, char *ip_str, u_int16_t flag)
+{
+  return peer_flag_modify_vty (vty, ip_str, flag, 1);
+}
+
+int
+peer_flag_unset_vty (struct vty *vty, char *ip_str, u_int16_t flag)
+{
+  return peer_flag_modify_vty (vty, ip_str, flag, 0);
+}
+
+/* neighbor passive. */
+DEFUN (neighbor_passive,
+       neighbor_passive_cmd,
+       NEIGHBOR_CMD2 "passive",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Don't send open messages to this neighbor\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_PASSIVE);
+}
+
+DEFUN (no_neighbor_passive,
+       no_neighbor_passive_cmd,
+       NO_NEIGHBOR_CMD2 "passive",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Don't send open messages to this neighbor\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE);
+}
+\f
+/* neighbor shutdown. */
+DEFUN (neighbor_shutdown,
+       neighbor_shutdown_cmd,
+       NEIGHBOR_CMD2 "shutdown",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Administratively shut down this neighbor\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_SHUTDOWN);
+}
+
+DEFUN (no_neighbor_shutdown,
+       no_neighbor_shutdown_cmd,
+       NO_NEIGHBOR_CMD2 "shutdown",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Administratively shut down this neighbor\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN);
+}
+\f
+/* neighbor capability route-refresh. */
+DEFUN (neighbor_capability_route_refresh,
+       neighbor_capability_route_refresh_cmd,
+       NEIGHBOR_CMD2 "capability route-refresh",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise route-refresh capability to this neighbor\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_NO_ROUTE_REFRESH_CAP);
+}
+
+DEFUN (no_neighbor_capability_route_refresh,
+       no_neighbor_capability_route_refresh_cmd,
+       NO_NEIGHBOR_CMD2 "capability route-refresh",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise route-refresh capability to this neighbor\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_NO_ROUTE_REFRESH_CAP);
+}
+\f
+/* neighbor capability dynamic. */
+DEFUN (neighbor_capability_dynamic,
+       neighbor_capability_dynamic_cmd,
+       NEIGHBOR_CMD2 "capability dynamic",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise dynamic capability to this neighbor\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY);
+}
+
+DEFUN (no_neighbor_capability_dynamic,
+       no_neighbor_capability_dynamic_cmd,
+       NO_NEIGHBOR_CMD2 "capability dynamic",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise dynamic capability to this neighbor\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY);
+}
+\f
+/* neighbor dont-capability-negotiate */
+DEFUN (neighbor_dont_capability_negotiate,
+       neighbor_dont_capability_negotiate_cmd,
+       NEIGHBOR_CMD2 "dont-capability-negotiate",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Do not perform capability negotiation\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY);
+}
+
+DEFUN (no_neighbor_dont_capability_negotiate,
+       no_neighbor_dont_capability_negotiate_cmd,
+       NO_NEIGHBOR_CMD2 "dont-capability-negotiate",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Do not perform capability negotiation\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY);
+}
+\f
+int
+peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi,
+                        safi_t safi, u_int16_t flag, int set)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, peer_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (set)
+    ret = peer_af_flag_set (peer, afi, safi, flag);
+  else
+    ret = peer_af_flag_unset (peer, afi, safi, flag);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_af_flag_set_vty (struct vty *vty, char *peer_str, afi_t afi,
+                     safi_t safi, u_int16_t flag)
+{
+  return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1);
+}
+
+int
+peer_af_flag_unset_vty (struct vty *vty, char *peer_str, afi_t afi,
+                       safi_t safi, u_int16_t flag)
+{
+  return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0);
+}
+\f
+/* neighbor capability orf prefix-list. */
+DEFUN (neighbor_capability_orf_prefix,
+       neighbor_capability_orf_prefix_cmd,
+       NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise ORF capability to the peer\n"
+       "Advertise prefixlist ORF capability to this neighbor\n"
+       "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+       "Capability to RECEIVE the ORF from this neighbor\n"
+       "Capability to SEND the ORF to this neighbor\n")
+{
+  u_int16_t flag = 0;
+
+  if (strncmp (argv[1], "s", 1) == 0)
+    flag = PEER_FLAG_ORF_PREFIX_SM;
+  else if (strncmp (argv[1], "r", 1) == 0)
+    flag = PEER_FLAG_ORF_PREFIX_RM;
+  else if (strncmp (argv[1], "b", 1) == 0)
+    flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM;
+  else
+    return CMD_WARNING;
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flag);
+}
+
+DEFUN (no_neighbor_capability_orf_prefix,
+       no_neighbor_capability_orf_prefix_cmd,
+       NO_NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Advertise capability to the peer\n"
+       "Advertise ORF capability to the peer\n"
+       "Advertise prefixlist ORF capability to this neighbor\n"
+       "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+       "Capability to RECEIVE the ORF from this neighbor\n"
+       "Capability to SEND the ORF to this neighbor\n")
+{
+  u_int16_t flag = 0;
+
+  if (strncmp (argv[1], "s", 1) == 0)
+    flag = PEER_FLAG_ORF_PREFIX_SM;
+  else if (strncmp (argv[1], "r", 1) == 0)
+    flag = PEER_FLAG_ORF_PREFIX_RM;
+  else if (strncmp (argv[1], "b", 1) == 0)
+    flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM;
+  else
+    return CMD_WARNING;
+
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty), flag);
+}
+\f
+/* neighbor next-hop-self. */
+DEFUN (neighbor_nexthop_self,
+       neighbor_nexthop_self_cmd,
+       NEIGHBOR_CMD2 "next-hop-self",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Disable the next hop calculation for this neighbor\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
+}
+
+DEFUN (no_neighbor_nexthop_self,
+       no_neighbor_nexthop_self_cmd,
+       NO_NEIGHBOR_CMD2 "next-hop-self",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Disable the next hop calculation for this neighbor\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
+}
+\f
+/* neighbor remove-private-AS. */
+DEFUN (neighbor_remove_private_as,
+       neighbor_remove_private_as_cmd,
+       NEIGHBOR_CMD2 "remove-private-AS",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Remove private AS number from outbound updates\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_REMOVE_PRIVATE_AS);
+}
+
+DEFUN (no_neighbor_remove_private_as,
+       no_neighbor_remove_private_as_cmd,
+       NO_NEIGHBOR_CMD2 "remove-private-AS",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Remove private AS number from outbound updates\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_REMOVE_PRIVATE_AS);
+}
+\f
+/* neighbor send-community. */
+DEFUN (neighbor_send_community,
+       neighbor_send_community_cmd,
+       NEIGHBOR_CMD2 "send-community",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Send Community attribute to this neighbor\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_SEND_COMMUNITY);
+}
+
+DEFUN (no_neighbor_send_community,
+       no_neighbor_send_community_cmd,
+       NO_NEIGHBOR_CMD2 "send-community",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Send Community attribute to this neighbor\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_SEND_COMMUNITY);
+}
+\f
+/* neighbor send-community extended. */
+DEFUN (neighbor_send_community_type,
+       neighbor_send_community_type_cmd,
+       NEIGHBOR_CMD2 "send-community (both|extended|standard)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Send Community attribute to this neighbor\n"
+       "Send Standard and Extended Community attributes\n"
+       "Send Extended Community attributes\n"
+       "Send Standard Community attributes\n")
+{
+  if (strncmp (argv[1], "s", 1) == 0)
+    return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_SEND_COMMUNITY);
+  if (strncmp (argv[1], "e", 1) == 0)
+    return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_SEND_EXT_COMMUNITY);
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              (PEER_FLAG_SEND_COMMUNITY|
+                               PEER_FLAG_SEND_EXT_COMMUNITY));
+}
+
+DEFUN (no_neighbor_send_community_type,
+       no_neighbor_send_community_type_cmd,
+       NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Send Community attribute to this neighbor\n"
+       "Send Standard and Extended Community attributes\n"
+       "Send Extended Community attributes\n"
+       "Send Standard Community attributes\n")
+{
+  if (strncmp (argv[1], "s", 1) == 0)
+    return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                  bgp_node_safi (vty),
+                                  PEER_FLAG_SEND_COMMUNITY);
+  if (strncmp (argv[1], "e", 1) == 0)
+    return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                  bgp_node_safi (vty),
+                                  PEER_FLAG_SEND_EXT_COMMUNITY);
+
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                (PEER_FLAG_SEND_COMMUNITY |
+                                 PEER_FLAG_SEND_EXT_COMMUNITY));
+}
+\f
+/* neighbor soft-reconfig. */
+DEFUN (neighbor_soft_reconfiguration,
+       neighbor_soft_reconfiguration_cmd,
+       NEIGHBOR_CMD2 "soft-reconfiguration inbound",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Per neighbor soft reconfiguration\n"
+       "Allow inbound soft reconfiguration for this neighbor\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0],
+                              bgp_node_afi (vty), bgp_node_safi (vty),
+                              PEER_FLAG_SOFT_RECONFIG);
+}
+
+DEFUN (no_neighbor_soft_reconfiguration,
+       no_neighbor_soft_reconfiguration_cmd,
+       NO_NEIGHBOR_CMD2 "soft-reconfiguration inbound",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Per neighbor soft reconfiguration\n"
+       "Allow inbound soft reconfiguration for this neighbor\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0],
+                                bgp_node_afi (vty), bgp_node_safi (vty),
+                                PEER_FLAG_SOFT_RECONFIG);
+}
+\f
+DEFUN (neighbor_route_reflector_client,
+       neighbor_route_reflector_client_cmd,
+       NEIGHBOR_CMD2 "route-reflector-client",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Configure a neighbor as Route Reflector client\n")
+{
+  struct peer *peer;
+
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_REFLECTOR_CLIENT);
+}
+
+DEFUN (no_neighbor_route_reflector_client,
+       no_neighbor_route_reflector_client_cmd,
+       NO_NEIGHBOR_CMD2 "route-reflector-client",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Configure a neighbor as Route Reflector client\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_REFLECTOR_CLIENT);
+}
+\f
+/* neighbor route-server-client. */
+DEFUN (neighbor_route_server_client,
+       neighbor_route_server_client_cmd,
+       NEIGHBOR_CMD2 "route-server-client",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Configure a neighbor as Route Server client\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_RSERVER_CLIENT);
+}
+
+DEFUN (no_neighbor_route_server_client,
+       no_neighbor_route_server_client_cmd,
+       NO_NEIGHBOR_CMD2 "route-server-client",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Configure a neighbor as Route Server client\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_RSERVER_CLIENT);
+}
+\f
+DEFUN (neighbor_attr_unchanged,
+       neighbor_attr_unchanged_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              (PEER_FLAG_AS_PATH_UNCHANGED |
+                               PEER_FLAG_NEXTHOP_UNCHANGED |
+                               PEER_FLAG_MED_UNCHANGED));
+}
+
+DEFUN (neighbor_attr_unchanged1,
+       neighbor_attr_unchanged1_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+{
+  u_int16_t flags = 0;
+
+  if (strncmp (argv[1], "as-path", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED);
+  else if (strncmp (argv[1], "next-hop", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED);
+  else if (strncmp (argv[1], "med", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED);
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flags);
+}
+
+DEFUN (neighbor_attr_unchanged2,
+       neighbor_attr_unchanged2_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+{
+  u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED;
+
+  if (strncmp (argv[1], "next-hop", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED);
+  else if (strncmp (argv[1], "med", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED);
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flags);
+
+}
+
+DEFUN (neighbor_attr_unchanged3,
+       neighbor_attr_unchanged3_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+{
+  u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED;
+
+  if (strncmp (argv[1], "as-path", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED);
+  else if (strncmp (argv[1], "med", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED);
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flags);
+}
+
+DEFUN (neighbor_attr_unchanged4,
+       neighbor_attr_unchanged4_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+{
+  u_int16_t flags = PEER_FLAG_MED_UNCHANGED;
+
+  if (strncmp (argv[1], "as-path", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED);
+  else if (strncmp (argv[1], "next-hop", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED);
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flags);
+}
+
+ALIAS (neighbor_attr_unchanged,
+       neighbor_attr_unchanged5_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+ALIAS (neighbor_attr_unchanged,
+       neighbor_attr_unchanged6_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Med attribute\n"
+       "Nexthop attribute\n")
+
+ALIAS (neighbor_attr_unchanged,
+       neighbor_attr_unchanged7_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "Med attribute\n"
+       "As-path attribute\n")
+
+ALIAS (neighbor_attr_unchanged,
+       neighbor_attr_unchanged8_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+
+ALIAS (neighbor_attr_unchanged,
+       neighbor_attr_unchanged9_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n")
+
+ALIAS (neighbor_attr_unchanged,
+       neighbor_attr_unchanged10_cmd,
+       NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+
+DEFUN (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged",
+       NO_STR   
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                (PEER_FLAG_AS_PATH_UNCHANGED |
+                                 PEER_FLAG_NEXTHOP_UNCHANGED |
+                                 PEER_FLAG_MED_UNCHANGED));
+}
+
+DEFUN (no_neighbor_attr_unchanged1,
+       no_neighbor_attr_unchanged1_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+{
+  u_int16_t flags = 0;
+
+  if (strncmp (argv[1], "as-path", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED);
+  else if (strncmp (argv[1], "next-hop", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED);
+  else if (strncmp (argv[1], "med", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED);
+
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty), flags);
+}
+
+DEFUN (no_neighbor_attr_unchanged2,
+       no_neighbor_attr_unchanged2_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+{
+  u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED;
+
+  if (strncmp (argv[1], "next-hop", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED);
+  else if (strncmp (argv[1], "med", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED);
+
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flags);
+}
+
+DEFUN (no_neighbor_attr_unchanged3,
+       no_neighbor_attr_unchanged3_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+{
+  u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED;
+
+  if (strncmp (argv[1], "as-path", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED);
+  else if (strncmp (argv[1], "med", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED);
+
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty), flags);
+}
+
+DEFUN (no_neighbor_attr_unchanged4,
+       no_neighbor_attr_unchanged4_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+{
+  u_int16_t flags = PEER_FLAG_MED_UNCHANGED;
+
+  if (strncmp (argv[1], "as-path", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED);
+  else if (strncmp (argv[1], "next-hop", 1) == 0)
+    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED);
+
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty), flags);
+}
+
+ALIAS (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged5_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+ALIAS (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged6_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Med attribute\n"
+       "Nexthop attribute\n")
+
+ALIAS (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged7_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "Med attribute\n"
+       "As-path attribute\n")
+
+ALIAS (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged8_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+
+ALIAS (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged9_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n")
+
+ALIAS (no_neighbor_attr_unchanged,
+       no_neighbor_attr_unchanged10_cmd,
+       NO_NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+
+/* For old version Zebra compatibility.  */
+DEFUN (neighbor_transparent_as,
+       neighbor_transparent_as_cmd,
+       NEIGHBOR_CMD "transparent-as",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Do not append my AS number even peer is EBGP peer\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_AS_PATH_UNCHANGED);
+}
+
+DEFUN (neighbor_transparent_nexthop,
+       neighbor_transparent_nexthop_cmd,
+       NEIGHBOR_CMD "transparent-nexthop",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Do not change nexthop even peer is EBGP peer\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_NEXTHOP_UNCHANGED);
+}
+\f
+/* EBGP multihop configuration. */
+int
+peer_ebgp_multihop_set_vty (struct vty *vty, char *ip_str, char *ttl_str)
+{
+  struct peer *peer;
+  int ttl;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! ttl_str)
+    ttl = TTL_MAX;
+  else
+    VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255);
+
+  peer_ebgp_multihop_set (peer, ttl);
+
+  return CMD_SUCCESS;
+}
+
+int
+peer_ebgp_multihop_unset_vty (struct vty *vty, char *ip_str) 
+{
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  peer_ebgp_multihop_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+/* neighbor ebgp-multihop. */
+DEFUN (neighbor_ebgp_multihop,
+       neighbor_ebgp_multihop_cmd,
+       NEIGHBOR_CMD2 "ebgp-multihop",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Allow EBGP neighbors not on directly connected networks\n")
+{
+  return peer_ebgp_multihop_set_vty (vty, argv[0], NULL);
+}
+
+DEFUN (neighbor_ebgp_multihop_ttl,
+       neighbor_ebgp_multihop_ttl_cmd,
+       NEIGHBOR_CMD2 "ebgp-multihop <1-255>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Allow EBGP neighbors not on directly connected networks\n"
+       "maximum hop count\n")
+{
+  return peer_ebgp_multihop_set_vty (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_neighbor_ebgp_multihop,
+       no_neighbor_ebgp_multihop_cmd,
+       NO_NEIGHBOR_CMD2 "ebgp-multihop",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Allow EBGP neighbors not on directly connected networks\n")
+{
+  return peer_ebgp_multihop_unset_vty (vty, argv[0]);
+}
+
+ALIAS (no_neighbor_ebgp_multihop,
+       no_neighbor_ebgp_multihop_ttl_cmd,
+       NO_NEIGHBOR_CMD2 "ebgp-multihop <1-255>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Allow EBGP neighbors not on directly connected networks\n"
+       "maximum hop count\n")
+\f
+/* Enforce multihop.  */
+DEFUN (neighbor_enforce_multihop,
+       neighbor_enforce_multihop_cmd,
+       NEIGHBOR_CMD2 "enforce-multihop",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Enforce EBGP neighbors perform multihop\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_ENFORCE_MULTIHOP);
+}
+
+DEFUN (no_neighbor_enforce_multihop,
+       no_neighbor_enforce_multihop_cmd,
+       NO_NEIGHBOR_CMD2 "enforce-multihop",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Enforce EBGP neighbors perform multihop\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_ENFORCE_MULTIHOP);
+}
+\f
+DEFUN (neighbor_description,
+       neighbor_description_cmd,
+       NEIGHBOR_CMD2 "description .LINE",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Neighbor specific description\n"
+       "Up to 80 characters describing this neighbor\n")
+{
+  struct peer *peer;
+  struct buffer *b;
+  char *str;
+  int i;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (argc == 1)
+    return CMD_SUCCESS;
+
+  /* Make string from buffer.  This function should be provided by
+     buffer.c. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+  str = buffer_getstr (b);
+  buffer_free (b);
+
+  peer_description_set (peer, str);
+
+  free (str);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_neighbor_description,
+       no_neighbor_description_cmd,
+       NO_NEIGHBOR_CMD2 "description",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Neighbor specific description\n")
+{
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  peer_description_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_neighbor_description,
+       no_neighbor_description_val_cmd,
+       NO_NEIGHBOR_CMD2 "description .LINE",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Neighbor specific description\n"
+       "Up to 80 characters describing this neighbor\n")
+\f
+/* Neighbor update-source. */
+int
+peer_update_source_vty (struct vty *vty, char *peer_str, char *source_str)
+{
+  struct peer *peer;
+  union sockunion *su;
+
+  peer = peer_and_group_lookup_vty (vty, peer_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (source_str)
+    {
+      su = sockunion_str2su (source_str);
+      if (su)
+       {
+         peer_update_source_addr_set (peer, su);
+         sockunion_free (su);
+       }
+      else
+       peer_update_source_if_set (peer, source_str);
+    }
+  else
+    peer_update_source_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (neighbor_update_source,
+       neighbor_update_source_cmd,
+       NEIGHBOR_CMD2 "update-source WORD",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Source of routing updates\n"
+       "Interface name\n")
+{
+  return peer_update_source_vty (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_neighbor_update_source,
+       no_neighbor_update_source_cmd,
+       NO_NEIGHBOR_CMD2 "update-source",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Source of routing updates\n"
+       "Interface name\n")
+{
+  return peer_update_source_vty (vty, argv[0], NULL);
+}
+\f
+int
+peer_default_originate_set_vty (struct vty *vty, char *peer_str, afi_t afi,
+                               safi_t safi, char *rmap, int set)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, peer_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (set)
+    ret = peer_default_originate_set (peer, afi, safi, rmap);
+  else
+    ret = peer_default_originate_unset (peer, afi, safi);
+
+  return bgp_vty_return (vty, ret);
+}
+
+/* neighbor default-originate. */
+DEFUN (neighbor_default_originate,
+       neighbor_default_originate_cmd,
+       NEIGHBOR_CMD2 "default-originate",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Originate default route to this neighbor\n")
+{
+  return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                        bgp_node_safi (vty), NULL, 1);
+}
+
+DEFUN (neighbor_default_originate_rmap,
+       neighbor_default_originate_rmap_cmd,
+       NEIGHBOR_CMD2 "default-originate route-map WORD",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Originate default route to this neighbor\n"
+       "Route-map to specify criteria to originate default\n"
+       "route-map name\n")
+{
+  return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                        bgp_node_safi (vty), argv[1], 1);
+}
+
+DEFUN (no_neighbor_default_originate,
+       no_neighbor_default_originate_cmd,
+       NO_NEIGHBOR_CMD2 "default-originate",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Originate default route to this neighbor\n")
+{
+  return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                        bgp_node_safi (vty), NULL, 0);
+}
+
+ALIAS (no_neighbor_default_originate,
+       no_neighbor_default_originate_rmap_cmd,
+       NO_NEIGHBOR_CMD2 "default-originate route-map WORD",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Originate default route to this neighbor\n"
+       "Route-map to specify criteria to originate default\n"
+       "route-map name\n")
+\f
+/* Set neighbor's BGP port.  */
+int
+peer_port_vty (struct vty *vty, char *ip_str, int afi, char *port_str)
+{
+  struct peer *peer;
+  u_int16_t port;
+  struct servent *sp;
+
+  peer = peer_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! port_str)
+    { 
+      sp = getservbyname ("bgp", "tcp");
+      port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port);
+    }
+  else
+    {
+      VTY_GET_INTEGER("port", port, port_str);
+    }
+
+  peer_port_set (peer, port);
+
+  return CMD_SUCCESS;
+}
+
+/* Set specified peer's BGP version.  */
+DEFUN (neighbor_port,
+       neighbor_port_cmd,
+       NEIGHBOR_CMD "port <0-65535>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Neighbor's BGP port\n"
+       "TCP port number\n")
+{
+  return peer_port_vty (vty, argv[0], AFI_IP, argv[1]);
+}
+
+DEFUN (no_neighbor_port,
+       no_neighbor_port_cmd,
+       NO_NEIGHBOR_CMD "port",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Neighbor's BGP port\n")
+{
+  return peer_port_vty (vty, argv[0], AFI_IP, NULL);
+}
+
+ALIAS (no_neighbor_port,
+       no_neighbor_port_val_cmd,
+       NO_NEIGHBOR_CMD "port <0-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Neighbor's BGP port\n"
+       "TCP port number\n")
+\f
+/* neighbor weight. */
+int
+peer_weight_set_vty (struct vty *vty, char *ip_str, char *weight_str)
+{
+  int ret;
+  struct peer *peer;
+  unsigned long weight;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  VTY_GET_INTEGER_RANGE("weight", weight, weight_str, 0, 65535);
+
+  ret = peer_weight_set (peer, weight);
+
+  return CMD_SUCCESS;
+}
+
+int
+peer_weight_unset_vty (struct vty *vty, char *ip_str)
+{
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  peer_weight_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (neighbor_weight,
+       neighbor_weight_cmd,
+       NEIGHBOR_CMD2 "weight <0-65535>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Set default weight for routes from this neighbor\n"
+       "default weight\n")
+{
+  return peer_weight_set_vty (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_neighbor_weight,
+       no_neighbor_weight_cmd,
+       NO_NEIGHBOR_CMD2 "weight",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Set default weight for routes from this neighbor\n")
+{
+  return peer_weight_unset_vty (vty, argv[0]);
+}
+
+ALIAS (no_neighbor_weight,
+       no_neighbor_weight_val_cmd,
+       NO_NEIGHBOR_CMD2 "weight <0-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Set default weight for routes from this neighbor\n"
+       "default weight\n")
+\f
+/* Override capability negotiation. */
+DEFUN (neighbor_override_capability,
+       neighbor_override_capability_cmd,
+       NEIGHBOR_CMD2 "override-capability",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Override capability negotiation result\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY);
+}
+
+DEFUN (no_neighbor_override_capability,
+       no_neighbor_override_capability_cmd,
+       NO_NEIGHBOR_CMD2 "override-capability",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Override capability negotiation result\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY);
+}
+\f
+DEFUN (neighbor_strict_capability,
+       neighbor_strict_capability_cmd,
+       NEIGHBOR_CMD "strict-capability-match",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Strict capability negotiation match\n")
+{
+  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH);
+}
+
+DEFUN (no_neighbor_strict_capability,
+       no_neighbor_strict_capability_cmd,
+       NO_NEIGHBOR_CMD "strict-capability-match",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Strict capability negotiation match\n")
+{
+  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH);
+}
+\f
+int
+peer_timers_set_vty (struct vty *vty, char *ip_str, char *keep_str,
+                    char *hold_str)
+{
+  int ret;
+  struct peer *peer;
+  u_int32_t keepalive;
+  u_int32_t holdtime;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  VTY_GET_INTEGER_RANGE ("Keepalive", keepalive, keep_str, 0, 65535);
+  VTY_GET_INTEGER_RANGE ("Holdtime", holdtime, hold_str, 0, 65535);
+
+  ret = peer_timers_set (peer, keepalive, holdtime);
+
+  return bgp_vty_return (vty, ret);
+}
+\f
+int
+peer_timers_unset_vty (struct vty *vty, char *ip_str)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_timers_unset (peer);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_timers,
+       neighbor_timers_cmd,
+       NEIGHBOR_CMD2 "timers <0-65535> <0-65535>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP per neighbor timers\n"
+       "Keepalive interval\n"
+       "Holdtime\n")
+{
+  return peer_timers_set_vty (vty, argv[0], argv[1], argv[2]);
+}
+
+DEFUN (no_neighbor_timers,
+       no_neighbor_timers_cmd,
+       NO_NEIGHBOR_CMD2 "timers",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP per neighbor timers\n")
+{
+  return peer_timers_unset_vty (vty, argv[0]);
+}
+\f
+int
+peer_timers_connect_set_vty (struct vty *vty, char *ip_str, char *time_str)
+{
+  int ret;
+  struct peer *peer;
+  u_int32_t connect;
+
+  peer = peer_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  VTY_GET_INTEGER_RANGE ("Connect time", connect, time_str, 0, 65535);
+
+  ret = peer_timers_connect_set (peer, connect);
+
+  return CMD_SUCCESS;
+}
+
+int
+peer_timers_connect_unset_vty (struct vty *vty, char *ip_str)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_timers_connect_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (neighbor_timers_connect,
+       neighbor_timers_connect_cmd,
+       NEIGHBOR_CMD "timers connect <0-65535>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "BGP per neighbor timers\n"
+       "BGP connect timer\n"
+       "Connect timer\n")
+{
+  return peer_timers_connect_set_vty (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_neighbor_timers_connect,
+       no_neighbor_timers_connect_cmd,
+       NO_NEIGHBOR_CMD "timers connect",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "BGP per neighbor timers\n"
+       "BGP connect timer\n")
+{
+  return peer_timers_connect_unset_vty (vty, argv[0]);
+}
+
+ALIAS (no_neighbor_timers_connect,
+       no_neighbor_timers_connect_val_cmd,
+       NO_NEIGHBOR_CMD "timers connect <0-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "BGP per neighbor timers\n"
+       "BGP connect timer\n"
+       "Connect timer\n")
+\f
+int
+peer_advertise_interval_vty (struct vty *vty, char *ip_str, char *time_str,
+                            int set)  
+{
+  int ret;
+  struct peer *peer;
+  u_int32_t routeadv = 0;
+
+  peer = peer_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (time_str)
+    VTY_GET_INTEGER_RANGE ("advertise interval", routeadv, time_str, 0, 600);
+
+  if (set)
+    ret = peer_advertise_interval_set (peer, routeadv);
+  else
+    ret = peer_advertise_interval_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (neighbor_advertise_interval,
+       neighbor_advertise_interval_cmd,
+       NEIGHBOR_CMD "advertisement-interval <0-600>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Minimum interval between sending BGP routing updates\n"
+       "time in seconds\n")
+{
+  return peer_advertise_interval_vty (vty, argv[0], argv[1], 1);
+}
+
+DEFUN (no_neighbor_advertise_interval,
+       no_neighbor_advertise_interval_cmd,
+       NO_NEIGHBOR_CMD "advertisement-interval",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Minimum interval between sending BGP routing updates\n")
+{
+  return peer_advertise_interval_vty (vty, argv[0], NULL, 0);
+}
+
+ALIAS (no_neighbor_advertise_interval,
+       no_neighbor_advertise_interval_val_cmd,
+       NO_NEIGHBOR_CMD "advertisement-interval <0-600>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Minimum interval between sending BGP routing updates\n"
+       "time in seconds\n")
+\f
+int
+peer_version_vty (struct vty *vty, char *ip_str, char *str)
+{
+  int ret;
+  struct peer *peer;
+  int version = BGP_VERSION_4;
+
+  peer = peer_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* BGP version string check. */
+  if (str)
+    {
+      if (strcmp (str, "4") == 0)
+       version = BGP_VERSION_4;
+      else if (strcmp (str, "4-") == 0)
+       version = BGP_VERSION_MP_4_DRAFT_00;
+
+      ret = peer_version_set (peer, version);
+    }
+  else
+    ret = peer_version_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (neighbor_version,
+       neighbor_version_cmd,
+       NEIGHBOR_CMD "version (4|4-)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Neighbor's BGP version\n"
+       "Border Gateway Protocol 4\n"
+       "Multiprotocol Extensions for BGP-4(Old Draft)\n")
+{
+  return peer_version_vty (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_neighbor_version,
+       no_neighbor_version_cmd,
+       NO_NEIGHBOR_CMD "version",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Neighbor's BGP version\n")
+{
+  return peer_version_vty (vty, argv[0], NULL);
+}
+\f
+/* neighbor interface */
+int
+peer_interface_vty (struct vty *vty, char *ip_str, char *str)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (str)
+    ret = peer_interface_set (peer, str);
+  else
+    ret = peer_interface_unset (peer);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (neighbor_interface,
+       neighbor_interface_cmd,
+       NEIGHBOR_CMD "interface WORD",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Interface\n"
+       "Interface name\n")
+{
+  return peer_interface_vty (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_neighbor_interface,
+       no_neighbor_interface_cmd,
+       NO_NEIGHBOR_CMD "interface WORD",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR
+       "Interface\n"
+       "Interface name\n")
+{
+  return peer_interface_vty (vty, argv[0], NULL);
+}
+\f
+/* Set distribute list to the peer. */
+int
+peer_distribute_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi,
+                        char *name_str, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_distribute_set (peer, afi, safi, direct, name_str);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_distribute_unset_vty (struct vty *vty, char *ip_str, afi_t afi,
+                          safi_t safi, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_distribute_unset (peer, afi, safi, direct);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_distribute_list,
+       neighbor_distribute_list_cmd,
+       NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Filter updates to/from this neighbor\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+{
+  return peer_distribute_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                 bgp_node_safi (vty), argv[1], argv[2]);
+}
+
+DEFUN (no_neighbor_distribute_list,
+       no_neighbor_distribute_list_cmd,
+       NO_NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Filter updates to/from this neighbor\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+{
+  return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                   bgp_node_safi (vty), argv[2]);
+}
+\f
+/* Set prefix list to the peer. */
+int
+peer_prefix_list_set_vty (struct vty *vty, char *ip_str, afi_t afi,
+                         safi_t safi, char *name_str, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_prefix_list_set (peer, afi, safi, direct, name_str);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_prefix_list_unset_vty (struct vty *vty, char *ip_str, afi_t afi,
+                           safi_t safi, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+  
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_prefix_list_unset (peer, afi, safi, direct);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_prefix_list,
+       neighbor_prefix_list_cmd,
+       NEIGHBOR_CMD2 "prefix-list WORD (in|out)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Filter updates to/from this neighbor\n"
+       "Name of a prefix list\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+{
+  return peer_prefix_list_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                  bgp_node_safi (vty), argv[1], argv[2]);
+}
+
+DEFUN (no_neighbor_prefix_list,
+       no_neighbor_prefix_list_cmd,
+       NO_NEIGHBOR_CMD2 "prefix-list WORD (in|out)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Filter updates to/from this neighbor\n"
+       "Name of a prefix list\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+{
+  return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                    bgp_node_safi (vty), argv[2]);
+}
+\f
+int
+peer_aslist_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi,
+                    char *name_str, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_aslist_set (peer, afi, safi, direct, name_str);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_aslist_unset_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi,
+                      char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_aslist_unset (peer, afi, safi, direct);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_filter_list,
+       neighbor_filter_list_cmd,
+       NEIGHBOR_CMD2 "filter-list WORD (in|out)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Establish BGP filters\n"
+       "AS path access-list name\n"
+       "Filter incoming routes\n"
+       "Filter outgoing routes\n")
+{
+  return peer_aslist_set_vty (vty, argv[0], bgp_node_afi (vty),
+                             bgp_node_safi (vty), argv[1], argv[2]);
+}
+
+DEFUN (no_neighbor_filter_list,
+       no_neighbor_filter_list_cmd,
+       NO_NEIGHBOR_CMD2 "filter-list WORD (in|out)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Establish BGP filters\n"
+       "AS path access-list name\n"
+       "Filter incoming routes\n"
+       "Filter outgoing routes\n")
+{
+  return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                               bgp_node_safi (vty), argv[2]);
+}
+\f
+/* Set route-map to the peer. */
+int
+peer_route_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi,
+                       char *name_str, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = FILTER_OUT;
+
+  ret = peer_route_map_set (peer, afi, safi, direct, name_str);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi,
+                         safi_t safi, char *direct_str)
+{
+  int ret;
+  struct peer *peer;
+  int direct = FILTER_IN;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  /* Check filter direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = FILTER_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+
+    direct = FILTER_OUT;
+
+  ret = peer_route_map_unset (peer, afi, safi, direct);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_route_map,
+       neighbor_route_map_cmd,
+       NEIGHBOR_CMD2 "route-map WORD (in|out)",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Apply route map to neighbor\n"
+       "Name of route map\n"
+       "Apply map to incoming routes\n"
+       "Apply map to outbound routes\n")
+{
+  return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty), argv[1], argv[2]);
+}
+
+DEFUN (no_neighbor_route_map,
+       no_neighbor_route_map_cmd,
+       NO_NEIGHBOR_CMD2 "route-map WORD (in|out)",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Apply route map to neighbor\n"
+       "Name of route map\n"
+       "Apply map to incoming routes\n"
+       "Apply map to outbound routes\n")
+{
+  return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                  bgp_node_safi (vty), argv[2]);
+}
+\f
+/* Set unsuppress-map to the peer. */
+int
+peer_unsuppress_map_set_vty (struct vty *vty, char *ip_str, afi_t afi,
+                            safi_t safi, char *name_str)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_unsuppress_map_set (peer, afi, safi, name_str);
+
+  return bgp_vty_return (vty, ret);
+}
+
+/* Unset route-map from the peer. */
+int
+peer_unsuppress_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi,
+                              safi_t safi)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_unsuppress_map_unset (peer, afi, safi);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (neighbor_unsuppress_map,
+       neighbor_unsuppress_map_cmd,
+       NEIGHBOR_CMD2 "unsuppress-map WORD",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Route-map to selectively unsuppress suppressed routes\n"
+       "Name of route map\n")
+{
+  return peer_unsuppress_map_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                     bgp_node_safi (vty), argv[1]);
+}
+
+DEFUN (no_neighbor_unsuppress_map,
+       no_neighbor_unsuppress_map_cmd,
+       NO_NEIGHBOR_CMD2 "unsuppress-map WORD",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Route-map to selectively unsuppress suppressed routes\n"
+       "Name of route map\n")
+{
+  return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                       bgp_node_safi (vty));
+}
+\f
+int
+peer_maximum_prefix_set_vty (struct vty *vty, char *ip_str, afi_t afi,
+                            safi_t safi, char *num_str, int warning)
+{
+  int ret;
+  struct peer *peer;
+  u_int32_t max;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  VTY_GET_INTEGER ("maxmum number", max, num_str);
+
+  ret = peer_maximum_prefix_set (peer, afi, safi, max, warning);
+
+  return bgp_vty_return (vty, ret);
+}
+
+int
+peer_maximum_prefix_unset_vty (struct vty *vty, char *ip_str, afi_t afi,
+                              safi_t safi)
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, ip_str);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_maximum_prefix_unset (peer, afi, safi);
+
+  return bgp_vty_return (vty, ret);
+}
+
+/* Maximum number of prefix configuration.  prefix count is different
+   for each peer configuration.  So this configuration can be set for
+   each peer configuration. */
+DEFUN (neighbor_maximum_prefix,
+       neighbor_maximum_prefix_cmd,
+       NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n")
+{
+  return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                     bgp_node_safi (vty), argv[1], 0);
+}
+
+DEFUN (neighbor_maximum_prefix_warning,
+       neighbor_maximum_prefix_warning_cmd,
+       NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n"
+       "Only give warning message when limit is exceeded\n")
+{
+  return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty),
+                                     bgp_node_safi (vty), argv[1], 1);
+}
+
+DEFUN (no_neighbor_maximum_prefix,
+       no_neighbor_maximum_prefix_cmd,
+       NO_NEIGHBOR_CMD2 "maximum-prefix",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Maximum number of prefix accept from this peer\n")
+{
+  return peer_maximum_prefix_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                       bgp_node_safi (vty));
+}
+ALIAS (no_neighbor_maximum_prefix,
+       no_neighbor_maximum_prefix_val_cmd,
+       NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n")
+
+ALIAS (no_neighbor_maximum_prefix,
+       no_neighbor_maximum_prefix_val2_cmd,
+       NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n"
+       "Only give warning message when limit is exceeded\n")
+\f
+/* "neighbor allowas-in" */
+DEFUN (neighbor_allowas_in,
+       neighbor_allowas_in_cmd,
+       NEIGHBOR_CMD2 "allowas-in",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Accept as-path with my AS present in it\n")
+{
+  int ret;
+  struct peer *peer;
+  int allow_num;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (argc == 1)
+    allow_num = 3;
+  else
+    VTY_GET_INTEGER_RANGE ("AS number", allow_num, argv[1], 1, 10);
+
+  ret = peer_allowas_in_set (peer, bgp_node_afi (vty), bgp_node_safi (vty),
+                            allow_num);
+
+  return bgp_vty_return (vty, ret);
+}
+
+ALIAS (neighbor_allowas_in,
+       neighbor_allowas_in_arg_cmd,
+       NEIGHBOR_CMD2 "allowas-in <1-10>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Accept as-path with my AS present in it\n"
+       "Number of occurances of AS number\n")
+
+DEFUN (no_neighbor_allowas_in,
+       no_neighbor_allowas_in_cmd,
+       NO_NEIGHBOR_CMD2 "allowas-in",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "allow local ASN appears in aspath attribute\n")
+{
+  int ret;
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_allowas_in_unset (peer, bgp_node_afi (vty), bgp_node_safi (vty));
+
+  return bgp_vty_return (vty, ret);
+}
+\f
+/* Address family configuration.  */
+DEFUN (address_family_ipv4,
+       address_family_ipv4_cmd,
+       "address-family ipv4",
+       "Enter Address Family command mode\n"
+       "Address family\n")
+{
+  vty->node = BGP_IPV4_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUN (address_family_ipv4_safi,
+       address_family_ipv4_safi_cmd,
+       "address-family ipv4 (unicast|multicast)",
+       "Enter Address Family command mode\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    vty->node = BGP_IPV4M_NODE;
+  else
+    vty->node = BGP_IPV4_NODE;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (address_family_ipv6_unicast,
+       address_family_ipv6_unicast_cmd,
+       "address-family ipv6 unicast",
+       "Enter Address Family command mode\n"
+       "Address family\n"
+       "unicast\n")
+{
+  vty->node = BGP_IPV6_NODE;
+  return CMD_SUCCESS;
+}
+
+ALIAS (address_family_ipv6_unicast,
+       address_family_ipv6_cmd,
+       "address-family ipv6",
+       "Enter Address Family command mode\n"
+       "Address family\n")
+
+DEFUN (address_family_vpnv4,
+       address_family_vpnv4_cmd,
+       "address-family vpnv4",
+       "Enter Address Family command mode\n"
+       "Address family\n")
+{
+  vty->node = BGP_VPNV4_NODE;
+  return CMD_SUCCESS;
+}
+
+ALIAS (address_family_vpnv4,
+       address_family_vpnv4_unicast_cmd,
+       "address-family vpnv4 unicast",
+       "Enter Address Family command mode\n"
+       "Address family\n"
+       "Address Family Modifier\n")
+
+DEFUN (exit_address_family,
+       exit_address_family_cmd,
+       "exit-address-family",
+       "Exit from Address Family configuration mode\n")
+{
+  if (vty->node == BGP_IPV4M_NODE
+      || vty->node == BGP_VPNV4_NODE
+      || vty->node == BGP_IPV6_NODE)
+    vty->node = BGP_NODE;
+  return CMD_SUCCESS;
+}
+\f
+/* BGP clear sort. */
+enum clear_sort
+{
+  clear_all,
+  clear_peer,
+  clear_group,
+  clear_external,
+  clear_as
+};
+
+void
+bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi,
+                    safi_t safi, int error)
+{
+  switch (error)
+    {
+    case BGP_ERR_AF_UNCONFIGURED:
+      vty_out (vty,
+              "%%BGP: Enable %s %s address family for the neighbor %s%s",
+              afi == AFI_IP6 ? "IPv6" : safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4",
+              safi == SAFI_MULTICAST ? "Multicast" : "Unicast",
+              peer->host, VTY_NEWLINE);
+      break;
+    case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
+      vty_out (vty, "%%BGP: Inbound soft reconfig for %s not possible as it%s      has neither refresh capability, nor inbound soft reconfig%s", peer->host, VTY_NEWLINE, VTY_NEWLINE);
+      break;
+    default:
+      break;
+    }
+}
+
+/* `clear ip bgp' functions. */
+int
+bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,
+           enum clear_sort sort,enum bgp_clear_type stype, char *arg)
+{
+  int ret;
+  struct peer *peer;
+  struct listnode *nn;
+
+  /* Clear all neighbors. */
+  if (sort == clear_all)
+    {
+      LIST_LOOP (bgp->peer, peer, nn)
+       {
+         if (stype == BGP_CLEAR_SOFT_NONE)
+           ret = peer_clear (peer);
+         else
+           ret = peer_clear_soft (peer, afi, safi, stype);
+
+         if (ret < 0)
+           bgp_clear_vty_error (vty, peer, afi, safi, ret);
+       }
+      return 0;
+    }
+
+  /* Clear specified neighbors. */
+  if (sort == clear_peer)
+    {
+      union sockunion su;
+      int ret;
+
+      /* Make sockunion for lookup. */
+      ret = str2sockunion (arg, &su);
+      if (ret < 0)
+       {
+         vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE);
+         return -1;
+       }
+      peer = peer_lookup (bgp, &su);
+      if (! peer)
+       {
+         vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE);
+         return -1;
+       }
+
+      if (stype == BGP_CLEAR_SOFT_NONE)
+       ret = peer_clear (peer);
+      else
+       ret = peer_clear_soft (peer, afi, safi, stype);
+
+      if (ret < 0)
+       bgp_clear_vty_error (vty, peer, afi, safi, ret);
+
+      return 0;
+    }
+
+  /* Clear all peer-group members. */
+  if (sort == clear_group)
+    {
+      struct peer_group *group;
+
+      group = peer_group_lookup (bgp, arg);
+      if (! group)
+       {
+         vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE);
+         return -1; 
+       }
+
+      LIST_LOOP (group->peer, peer, nn)
+       {
+         if (stype == BGP_CLEAR_SOFT_NONE)
+           {
+             ret = peer_clear (peer);
+             continue;
+           }
+
+         if (! peer->af_group[afi][safi])
+           continue;
+
+         ret = peer_clear_soft (peer, afi, safi, stype);
+
+         if (ret < 0)
+           bgp_clear_vty_error (vty, peer, afi, safi, ret);
+       }
+      return 0;
+    }
+
+  if (sort == clear_external)
+    {
+      LIST_LOOP (bgp->peer, peer, nn)
+       {
+         if (peer_sort (peer) == BGP_PEER_IBGP) 
+           continue;
+
+         if (stype == BGP_CLEAR_SOFT_NONE)
+           ret = peer_clear (peer);
+         else
+           ret = peer_clear_soft (peer, afi, safi, stype);
+
+         if (ret < 0)
+           bgp_clear_vty_error (vty, peer, afi, safi, ret);
+       }
+      return 0;
+    }
+
+  if (sort == clear_as)
+    {
+      as_t as;
+      unsigned long as_ul;
+      char *endptr = NULL;
+      int find = 0;
+
+      as_ul = strtoul(arg, &endptr, 10);
+
+      if ((as_ul == ULONG_MAX) || (*endptr != '\0') || (as_ul > USHRT_MAX))
+       {
+         vty_out (vty, "Invalid AS number%s", VTY_NEWLINE); 
+         return -1;
+       }
+      as = (as_t) as_ul;
+
+      LIST_LOOP (bgp->peer, peer, nn)
+       {
+         if (peer->as != as) 
+           continue;
+
+         find = 1;
+         if (stype == BGP_CLEAR_SOFT_NONE)
+           ret = peer_clear (peer);
+         else
+           ret = peer_clear_soft (peer, afi, safi, stype);
+
+         if (ret < 0)
+           bgp_clear_vty_error (vty, peer, afi, safi, ret);
+       }
+      if (! find)
+       vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg,
+                VTY_NEWLINE);
+      return 0;
+    }
+
+  return 0;
+}
+
+int
+bgp_clear_vty (struct vty *vty, char *name, afi_t afi, safi_t safi,
+               enum clear_sort sort, enum bgp_clear_type stype, char *arg)  
+{
+  int ret;
+  struct bgp *bgp;
+
+  /* BGP structure lookup. */
+  if (name)
+    {
+      bgp = bgp_lookup_by_name (name);
+      if (bgp == NULL)
+        {
+          vty_out (vty, "Can't find BGP view %s%s", name, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+        {
+          vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+
+  ret =  bgp_clear (vty, bgp, afi, safi, sort, stype, arg);
+  if (ret < 0)
+    return CMD_WARNING;
+
+  return CMD_SUCCESS;
+}
+  
+DEFUN (clear_ip_bgp_all,
+       clear_ip_bgp_all_cmd,
+       "clear ip bgp *",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL);    
+
+  return bgp_clear_vty (vty, NULL, 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL);
+}
+
+ALIAS (clear_ip_bgp_all,
+       clear_bgp_all_cmd,
+       "clear bgp *",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n")
+
+ALIAS (clear_ip_bgp_all,
+       clear_bgp_ipv6_all_cmd,
+       "clear bgp ipv6 *",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n")
+
+ALIAS (clear_ip_bgp_all,
+       clear_ip_bgp_instance_all_cmd,
+       "clear ip bgp view WORD *",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n")
+
+ALIAS (clear_ip_bgp_all,
+       clear_bgp_instance_all_cmd,
+       "clear bgp view WORD *",
+       CLEAR_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n")
+
+DEFUN (clear_ip_bgp_peer,
+       clear_ip_bgp_peer_cmd, 
+       "clear ip bgp (A.B.C.D|X:X::X:X)",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor IP address to clear\n"
+       "BGP IPv6 neighbor to clear\n")
+{
+  return bgp_clear_vty (vty, NULL, 0, 0, clear_peer, BGP_CLEAR_SOFT_NONE, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer,
+       clear_bgp_peer_cmd, 
+       "clear bgp (A.B.C.D|X:X::X:X)",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n")
+
+ALIAS (clear_ip_bgp_peer,
+       clear_bgp_ipv6_peer_cmd, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X)",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n")
+
+DEFUN (clear_ip_bgp_peer_group,
+       clear_ip_bgp_peer_group_cmd, 
+       "clear ip bgp peer-group WORD",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n")
+{
+  return bgp_clear_vty (vty, NULL, 0, 0, clear_group, BGP_CLEAR_SOFT_NONE, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_group,
+       clear_bgp_peer_group_cmd, 
+       "clear bgp peer-group WORD",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n")
+
+ALIAS (clear_ip_bgp_peer_group,
+       clear_bgp_ipv6_peer_group_cmd, 
+       "clear bgp ipv6 peer-group WORD",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n")
+
+DEFUN (clear_ip_bgp_external,
+       clear_ip_bgp_external_cmd,
+       "clear ip bgp external",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n")
+{
+  return bgp_clear_vty (vty, NULL, 0, 0, clear_external, BGP_CLEAR_SOFT_NONE, NULL);
+}
+
+ALIAS (clear_ip_bgp_external,
+       clear_bgp_external_cmd, 
+       "clear bgp external",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n")
+
+ALIAS (clear_ip_bgp_external,
+       clear_bgp_ipv6_external_cmd, 
+       "clear bgp ipv6 external",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n")
+
+DEFUN (clear_ip_bgp_as,
+       clear_ip_bgp_as_cmd,
+       "clear ip bgp <1-65535>",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n")
+{
+  return bgp_clear_vty (vty, NULL, 0, 0, clear_as, BGP_CLEAR_SOFT_NONE, argv[0]);
+}       
+
+ALIAS (clear_ip_bgp_as,
+       clear_bgp_as_cmd,
+       "clear bgp <1-65535>",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n")
+
+ALIAS (clear_ip_bgp_as,
+       clear_bgp_ipv6_as_cmd,
+       "clear bgp ipv6 <1-65535>",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n")
+\f
+/* Outbound soft-reconfiguration */
+DEFUN (clear_ip_bgp_all_soft_out,
+       clear_ip_bgp_all_soft_out_cmd,
+       "clear ip bgp * soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                          BGP_CLEAR_SOFT_OUT, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_soft_out,
+       clear_ip_bgp_all_out_cmd,
+       "clear ip bgp * out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_ip_bgp_all_soft_out,
+       clear_ip_bgp_instance_all_soft_out_cmd,
+       "clear ip bgp view WORD * soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_all_ipv4_soft_out,
+       clear_ip_bgp_all_ipv4_soft_out_cmd,
+       "clear ip bgp * ipv4 (unicast|multicast) soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
+                         BGP_CLEAR_SOFT_OUT, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_ipv4_soft_out,
+       clear_ip_bgp_all_ipv4_out_cmd,
+       "clear ip bgp * ipv4 (unicast|multicast) out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out,
+       clear_ip_bgp_instance_all_ipv4_soft_out_cmd,
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all,
+                          BGP_CLEAR_SOFT_OUT, NULL);
+
+  return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+DEFUN (clear_ip_bgp_all_vpnv4_soft_out,
+       clear_ip_bgp_all_vpnv4_soft_out_cmd,
+       "clear ip bgp * vpnv4 unicast soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_vpnv4_soft_out,
+       clear_ip_bgp_all_vpnv4_out_cmd,
+       "clear ip bgp * vpnv4 unicast out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_bgp_all_soft_out,
+       clear_bgp_all_soft_out_cmd,
+       "clear bgp * soft out",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
+                          BGP_CLEAR_SOFT_OUT, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_bgp_all_soft_out,
+       clear_bgp_instance_all_soft_out_cmd,
+       "clear bgp view WORD * soft out",
+       CLEAR_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_all_soft_out,
+       clear_bgp_all_out_cmd,
+       "clear bgp * out",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_all_soft_out,
+       clear_bgp_ipv6_all_soft_out_cmd,
+       "clear bgp ipv6 * soft out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_all_soft_out,
+       clear_bgp_ipv6_all_out_cmd,
+       "clear bgp ipv6 * out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_peer_soft_out,
+       clear_ip_bgp_peer_soft_out_cmd,
+       "clear ip bgp A.B.C.D soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_soft_out,
+       clear_ip_bgp_peer_out_cmd,
+       "clear ip bgp A.B.C.D out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_peer_ipv4_soft_out,
+       clear_ip_bgp_peer_ipv4_soft_out_cmd,
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
+                         BGP_CLEAR_SOFT_OUT, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_ipv4_soft_out,
+       clear_ip_bgp_peer_ipv4_out_cmd,
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_peer_vpnv4_soft_out,
+       clear_ip_bgp_peer_vpnv4_soft_out_cmd,
+       "clear ip bgp A.B.C.D vpnv4 unicast soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_vpnv4_soft_out,
+       clear_ip_bgp_peer_vpnv4_out_cmd,
+       "clear ip bgp A.B.C.D vpnv4 unicast out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_bgp_peer_soft_out,
+       clear_bgp_peer_soft_out_cmd,
+       "clear bgp (A.B.C.D|X:X::X:X) soft out",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_soft_out,
+       clear_bgp_ipv6_peer_soft_out_cmd,
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_peer_soft_out,
+       clear_bgp_peer_out_cmd,
+       "clear bgp (A.B.C.D|X:X::X:X) out",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_peer_soft_out,
+       clear_bgp_ipv6_peer_out_cmd,
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_peer_group_soft_out,
+       clear_ip_bgp_peer_group_soft_out_cmd, 
+       "clear ip bgp peer-group WORD soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_group_soft_out,
+       clear_ip_bgp_peer_group_out_cmd, 
+       "clear ip bgp peer-group WORD out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out,
+       clear_ip_bgp_peer_group_ipv4_soft_out_cmd,
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
+                         BGP_CLEAR_SOFT_OUT, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out,
+       clear_ip_bgp_peer_group_ipv4_out_cmd,
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_bgp_peer_group_soft_out,
+       clear_bgp_peer_group_soft_out_cmd,
+       "clear bgp peer-group WORD soft out",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_group_soft_out,
+       clear_bgp_ipv6_peer_group_soft_out_cmd,
+       "clear bgp ipv6 peer-group WORD soft out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_peer_group_soft_out,
+       clear_bgp_peer_group_out_cmd,
+       "clear bgp peer-group WORD out",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_peer_group_soft_out,
+       clear_bgp_ipv6_peer_group_out_cmd,
+       "clear bgp ipv6 peer-group WORD out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_external_soft_out,
+       clear_ip_bgp_external_soft_out_cmd, 
+       "clear ip bgp external soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_ip_bgp_external_soft_out,
+       clear_ip_bgp_external_out_cmd, 
+       "clear ip bgp external out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_external_ipv4_soft_out,
+       clear_ip_bgp_external_ipv4_soft_out_cmd,
+       "clear ip bgp external ipv4 (unicast|multicast) soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
+                         BGP_CLEAR_SOFT_OUT, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_ip_bgp_external_ipv4_soft_out,
+       clear_ip_bgp_external_ipv4_out_cmd,
+       "clear ip bgp external ipv4 (unicast|multicast) out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_bgp_external_soft_out,
+       clear_bgp_external_soft_out_cmd,
+       "clear bgp external soft out",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_bgp_external_soft_out,
+       clear_bgp_ipv6_external_soft_out_cmd,
+       "clear bgp ipv6 external soft out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_external_soft_out,
+       clear_bgp_external_out_cmd,
+       "clear bgp external out",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_external_soft_out,
+       clear_bgp_ipv6_external_out_cmd,
+       "clear bgp ipv6 external WORD out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_as_soft_out,
+       clear_ip_bgp_as_soft_out_cmd,
+       "clear ip bgp <1-65535> soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_soft_out,
+       clear_ip_bgp_as_out_cmd,
+       "clear ip bgp <1-65535> out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_as_ipv4_soft_out,
+       clear_ip_bgp_as_ipv4_soft_out_cmd,
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
+                         BGP_CLEAR_SOFT_OUT, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_ipv4_soft_out,
+       clear_ip_bgp_as_ipv4_out_cmd,
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
+       clear_ip_bgp_as_vpnv4_soft_out_cmd,
+       "clear ip bgp <1-65535> vpnv4 unicast soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_vpnv4_soft_out,
+       clear_ip_bgp_as_vpnv4_out_cmd,
+       "clear ip bgp <1-65535> vpnv4 unicast out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFUN (clear_bgp_as_soft_out,
+       clear_bgp_as_soft_out_cmd,
+       "clear bgp <1-65535> soft out",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_bgp_as_soft_out,
+       clear_bgp_ipv6_as_soft_out_cmd,
+       "clear bgp ipv6 <1-65535> soft out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_as_soft_out,
+       clear_bgp_as_out_cmd,
+       "clear bgp <1-65535> out",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig outbound update\n")
+
+ALIAS (clear_bgp_as_soft_out,
+       clear_bgp_ipv6_as_out_cmd,
+       "clear bgp ipv6 <1-65535> out",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig outbound update\n")
+\f
+/* Inbound soft-reconfiguration */
+DEFUN (clear_ip_bgp_all_soft_in,
+       clear_ip_bgp_all_soft_in_cmd,
+       "clear ip bgp * soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                          BGP_CLEAR_SOFT_IN, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_soft_in,
+       clear_ip_bgp_instance_all_soft_in_cmd,
+       "clear ip bgp view WORD * soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_ip_bgp_all_soft_in,
+       clear_ip_bgp_all_in_cmd,
+       "clear ip bgp * in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_all_in_prefix_filter,
+       clear_ip_bgp_all_in_prefix_filter_cmd,
+       "clear ip bgp * in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  if (argc== 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                          BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_in_prefix_filter,
+       clear_ip_bgp_instance_all_in_prefix_filter_cmd,
+       "clear ip bgp view WORD * in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+
+DEFUN (clear_ip_bgp_all_ipv4_soft_in,
+       clear_ip_bgp_all_ipv4_soft_in_cmd,
+       "clear ip bgp * ipv4 (unicast|multicast) soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
+                         BGP_CLEAR_SOFT_IN, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_ipv4_soft_in,
+       clear_ip_bgp_all_ipv4_in_cmd,
+       "clear ip bgp * ipv4 (unicast|multicast) in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in,
+       clear_ip_bgp_instance_all_ipv4_soft_in_cmd,
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all,
+                          BGP_CLEAR_SOFT_IN, NULL);
+
+  return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_IN, NULL);
+}
+
+DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter,
+       clear_ip_bgp_all_ipv4_in_prefix_filter_cmd,
+       "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
+                         BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter,
+       clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd,
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all,
+                          BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+
+  return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+DEFUN (clear_ip_bgp_all_vpnv4_soft_in,
+       clear_ip_bgp_all_vpnv4_soft_in_cmd,
+       "clear ip bgp * vpnv4 unicast soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_vpnv4_soft_in,
+       clear_ip_bgp_all_vpnv4_in_cmd,
+       "clear ip bgp * vpnv4 unicast in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_all_soft_in,
+       clear_bgp_all_soft_in_cmd,
+       "clear bgp * soft in",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_IN, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_bgp_all_soft_in,
+       clear_bgp_instance_all_soft_in_cmd,
+       "clear bgp view WORD * soft in",
+       CLEAR_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_all_soft_in,
+       clear_bgp_ipv6_all_soft_in_cmd,
+       "clear bgp ipv6 * soft in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_all_soft_in,
+       clear_bgp_all_in_cmd,
+       "clear bgp * in",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_all_soft_in,
+       clear_bgp_ipv6_all_in_cmd,
+       "clear bgp ipv6 * in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_all_in_prefix_filter,
+       clear_bgp_all_in_prefix_filter_cmd,
+       "clear bgp * in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+ALIAS (clear_bgp_all_in_prefix_filter,
+       clear_bgp_ipv6_all_in_prefix_filter_cmd,
+       "clear bgp ipv6 * in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFUN (clear_ip_bgp_peer_soft_in,
+       clear_ip_bgp_peer_soft_in_cmd,
+       "clear ip bgp A.B.C.D soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_soft_in,
+       clear_ip_bgp_peer_in_cmd,
+       "clear ip bgp A.B.C.D in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Soft reconfig inbound update\n")
+       
+DEFUN (clear_ip_bgp_peer_in_prefix_filter,
+       clear_ip_bgp_peer_in_prefix_filter_cmd,
+       "clear ip bgp A.B.C.D in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_peer_ipv4_soft_in,
+       clear_ip_bgp_peer_ipv4_soft_in_cmd,
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
+                         BGP_CLEAR_SOFT_IN, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_ipv4_soft_in,
+       clear_ip_bgp_peer_ipv4_in_cmd,
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter,
+       clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd,
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
+                         BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_peer_vpnv4_soft_in,
+       clear_ip_bgp_peer_vpnv4_soft_in_cmd,
+       "clear ip bgp A.B.C.D vpnv4 unicast soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_vpnv4_soft_in,
+       clear_ip_bgp_peer_vpnv4_in_cmd,
+       "clear ip bgp A.B.C.D vpnv4 unicast in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_peer_soft_in,
+       clear_bgp_peer_soft_in_cmd,
+       "clear bgp (A.B.C.D|X:X::X:X) soft in",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_soft_in,
+       clear_bgp_ipv6_peer_soft_in_cmd,
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_peer_soft_in,
+       clear_bgp_peer_in_cmd,
+       "clear bgp (A.B.C.D|X:X::X:X) in",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_peer_soft_in,
+       clear_bgp_ipv6_peer_in_cmd,
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_peer_in_prefix_filter,
+       clear_bgp_peer_in_prefix_filter_cmd,
+       "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_in_prefix_filter,
+       clear_bgp_ipv6_peer_in_prefix_filter_cmd,
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+
+DEFUN (clear_ip_bgp_peer_group_soft_in,
+       clear_ip_bgp_peer_group_soft_in_cmd,
+       "clear ip bgp peer-group WORD soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_group_soft_in,
+       clear_ip_bgp_peer_group_in_cmd,
+       "clear ip bgp peer-group WORD in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_peer_group_in_prefix_filter,
+       clear_ip_bgp_peer_group_in_prefix_filter_cmd,
+       "clear ip bgp peer-group WORD in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in,
+       clear_ip_bgp_peer_group_ipv4_soft_in_cmd,
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
+                         BGP_CLEAR_SOFT_IN, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in,
+       clear_ip_bgp_peer_group_ipv4_in_cmd,
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter,
+       clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd,
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
+                         BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+DEFUN (clear_bgp_peer_group_soft_in,
+       clear_bgp_peer_group_soft_in_cmd,
+       "clear bgp peer-group WORD soft in",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_group_soft_in,
+       clear_bgp_ipv6_peer_group_soft_in_cmd,
+       "clear bgp ipv6 peer-group WORD soft in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_peer_group_soft_in,
+       clear_bgp_peer_group_in_cmd,
+       "clear bgp peer-group WORD in",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_peer_group_soft_in,
+       clear_bgp_ipv6_peer_group_in_cmd,
+       "clear bgp ipv6 peer-group WORD in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_peer_group_in_prefix_filter,
+       clear_bgp_peer_group_in_prefix_filter_cmd,
+       "clear bgp peer-group WORD in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_group_in_prefix_filter,
+       clear_bgp_ipv6_peer_group_in_prefix_filter_cmd,
+       "clear bgp ipv6 peer-group WORD in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFUN (clear_ip_bgp_external_soft_in,
+       clear_ip_bgp_external_soft_in_cmd,
+       "clear ip bgp external soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_ip_bgp_external_soft_in,
+       clear_ip_bgp_external_in_cmd,
+       "clear ip bgp external in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_external_in_prefix_filter,
+       clear_ip_bgp_external_in_prefix_filter_cmd,
+       "clear ip bgp external in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+DEFUN (clear_ip_bgp_external_ipv4_soft_in,
+       clear_ip_bgp_external_ipv4_soft_in_cmd,
+       "clear ip bgp external ipv4 (unicast|multicast) soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
+                         BGP_CLEAR_SOFT_IN, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_ip_bgp_external_ipv4_soft_in,
+       clear_ip_bgp_external_ipv4_in_cmd,
+       "clear ip bgp external ipv4 (unicast|multicast) in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter,
+       clear_ip_bgp_external_ipv4_in_prefix_filter_cmd,
+       "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
+                         BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+DEFUN (clear_bgp_external_soft_in,
+       clear_bgp_external_soft_in_cmd,
+       "clear bgp external soft in",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_bgp_external_soft_in,
+       clear_bgp_ipv6_external_soft_in_cmd,
+       "clear bgp ipv6 external soft in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_external_soft_in,
+       clear_bgp_external_in_cmd,
+       "clear bgp external in",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_external_soft_in,
+       clear_bgp_ipv6_external_in_cmd,
+       "clear bgp ipv6 external WORD in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_external_in_prefix_filter,
+       clear_bgp_external_in_prefix_filter_cmd,
+       "clear bgp external in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL);
+}
+
+ALIAS (clear_bgp_external_in_prefix_filter,
+       clear_bgp_ipv6_external_in_prefix_filter_cmd,
+       "clear bgp ipv6 external in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFUN (clear_ip_bgp_as_soft_in,
+       clear_ip_bgp_as_soft_in_cmd,
+       "clear ip bgp <1-65535> soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_soft_in,
+       clear_ip_bgp_as_in_cmd,
+       "clear ip bgp <1-65535> in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_as_in_prefix_filter,
+       clear_ip_bgp_as_in_prefix_filter_cmd,
+       "clear ip bgp <1-65535> in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_as_ipv4_soft_in,
+       clear_ip_bgp_as_ipv4_soft_in_cmd,
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
+                         BGP_CLEAR_SOFT_IN, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_ipv4_soft_in,
+       clear_ip_bgp_as_ipv4_in_cmd,
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
+       clear_ip_bgp_as_ipv4_in_prefix_filter_cmd,
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
+                         BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_as_vpnv4_soft_in,
+       clear_ip_bgp_as_vpnv4_soft_in_cmd,
+       "clear ip bgp <1-65535> vpnv4 unicast soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_vpnv4_soft_in,
+       clear_ip_bgp_as_vpnv4_in_cmd,
+       "clear ip bgp <1-65535> vpnv4 unicast in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_as_soft_in,
+       clear_bgp_as_soft_in_cmd,
+       "clear bgp <1-65535> soft in",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_bgp_as_soft_in,
+       clear_bgp_ipv6_as_soft_in_cmd,
+       "clear bgp ipv6 <1-65535> soft in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_as_soft_in,
+       clear_bgp_as_in_cmd,
+       "clear bgp <1-65535> in",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n")
+
+ALIAS (clear_bgp_as_soft_in,
+       clear_bgp_ipv6_as_in_cmd,
+       "clear bgp ipv6 <1-65535> in",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n")
+
+DEFUN (clear_bgp_as_in_prefix_filter,
+       clear_bgp_as_in_prefix_filter_cmd,
+       "clear bgp <1-65535> in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]);
+}
+
+ALIAS (clear_bgp_as_in_prefix_filter,
+       clear_bgp_ipv6_as_in_prefix_filter_cmd,
+       "clear bgp ipv6 <1-65535> in prefix-filter",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+\f
+/* Both soft-reconfiguration */
+DEFUN (clear_ip_bgp_all_soft,
+       clear_ip_bgp_all_soft_cmd,
+       "clear ip bgp * soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_BOTH, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_BOTH, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_soft,
+       clear_ip_bgp_instance_all_soft_cmd,
+       "clear ip bgp view WORD * soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+
+DEFUN (clear_ip_bgp_all_ipv4_soft,
+       clear_ip_bgp_all_ipv4_soft_cmd,
+       "clear ip bgp * ipv4 (unicast|multicast) soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
+                         BGP_CLEAR_SOFT_BOTH, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_BOTH, NULL);
+}
+
+DEFUN (clear_ip_bgp_instance_all_ipv4_soft,
+       clear_ip_bgp_instance_all_ipv4_soft_cmd,
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
+                          BGP_CLEAR_SOFT_BOTH, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_BOTH, NULL);
+}
+
+DEFUN (clear_ip_bgp_all_vpnv4_soft,
+       clear_ip_bgp_all_vpnv4_soft_cmd,
+       "clear ip bgp * vpnv4 unicast soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_bgp_all_soft,
+       clear_bgp_all_soft_cmd,
+       "clear bgp * soft",
+       CLEAR_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Soft reconfig\n")
+{
+  if (argc == 1)
+    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
+                        BGP_CLEAR_SOFT_BOTH, argv[0]);
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+ALIAS (clear_bgp_all_soft,
+       clear_bgp_instance_all_soft_cmd,
+       "clear bgp view WORD * soft",
+       CLEAR_STR
+       BGP_STR
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+ALIAS (clear_bgp_all_soft,
+       clear_bgp_ipv6_all_soft_cmd,
+       "clear bgp ipv6 * soft",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+DEFUN (clear_ip_bgp_peer_soft,
+       clear_ip_bgp_peer_soft_cmd,
+       "clear ip bgp A.B.C.D soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_peer_ipv4_soft,
+       clear_ip_bgp_peer_ipv4_soft_cmd,
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
+                         BGP_CLEAR_SOFT_BOTH, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_peer_vpnv4_soft,
+       clear_ip_bgp_peer_vpnv4_soft_cmd,
+       "clear ip bgp A.B.C.D vpnv4 unicast soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_bgp_peer_soft,
+       clear_bgp_peer_soft_cmd,
+       "clear bgp (A.B.C.D|X:X::X:X) soft",
+       CLEAR_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_soft,
+       clear_bgp_ipv6_peer_soft_cmd,
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n")
+
+DEFUN (clear_ip_bgp_peer_group_soft,
+       clear_ip_bgp_peer_group_soft_cmd,
+       "clear ip bgp peer-group WORD soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_peer_group_ipv4_soft,
+       clear_ip_bgp_peer_group_ipv4_soft_cmd,
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
+                         BGP_CLEAR_SOFT_BOTH, argv[0]);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_bgp_peer_group_soft,
+       clear_bgp_peer_group_soft_cmd,
+       "clear bgp peer-group WORD soft",
+       CLEAR_STR
+       BGP_STR
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+ALIAS (clear_bgp_peer_group_soft,
+       clear_bgp_ipv6_peer_group_soft_cmd,
+       "clear bgp ipv6 peer-group WORD soft",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n")
+
+DEFUN (clear_ip_bgp_external_soft,
+       clear_ip_bgp_external_soft_cmd,
+       "clear ip bgp external soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_BOTH, NULL);
+}
+
+DEFUN (clear_ip_bgp_external_ipv4_soft,
+       clear_ip_bgp_external_ipv4_soft_cmd,
+       "clear ip bgp external ipv4 (unicast|multicast) soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
+                         BGP_CLEAR_SOFT_BOTH, NULL);
+
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_BOTH, NULL);
+}
+
+DEFUN (clear_bgp_external_soft,
+       clear_bgp_external_soft_cmd,
+       "clear bgp external soft",
+       CLEAR_STR
+       BGP_STR
+       "Clear all external peers\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
+                       BGP_CLEAR_SOFT_BOTH, NULL);
+}
+
+ALIAS (clear_bgp_external_soft,
+       clear_bgp_ipv6_external_soft_cmd,
+       "clear bgp ipv6 external soft",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n")
+
+DEFUN (clear_ip_bgp_as_soft,
+       clear_ip_bgp_as_soft_cmd,
+       "clear ip bgp <1-65535> soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_as_ipv4_soft,
+       clear_ip_bgp_as_ipv4_soft_cmd,
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
+                         BGP_CLEAR_SOFT_BOTH, argv[0]);
+
+  return bgp_clear_vty (vty, NULL,AFI_IP, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_ip_bgp_as_vpnv4_soft,
+       clear_ip_bgp_as_vpnv4_soft_cmd,
+       "clear ip bgp <1-65535> vpnv4 unicast soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+DEFUN (clear_bgp_as_soft,
+       clear_bgp_as_soft_cmd,
+       "clear bgp <1-65535> soft",
+       CLEAR_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
+                       BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
+ALIAS (clear_bgp_as_soft,
+       clear_bgp_ipv6_as_soft_cmd,
+       "clear bgp ipv6 <1-65535> soft",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n")
+\f
+/* Show BGP peer's summary information. */
+int
+bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
+{
+  struct peer *peer;
+  struct listnode *nn;
+  int count = 0;
+  char timebuf[BGP_UPTIME_LEN];
+  int len;
+
+  /* Header string for each address family. */
+  static char header[] = "Neighbor        V    AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd";
+
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer->afc[afi][safi])
+       {
+         if (! count)
+           {
+             vty_out (vty,
+                      "BGP router identifier %s, local AS number %d%s",
+                      inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE);
+             vty_out (vty, 
+                      "%ld BGP AS-PATH entries%s", aspath_count (),
+                      VTY_NEWLINE);
+             vty_out (vty, 
+                      "%ld BGP community entries%s", community_count (),
+                      VTY_NEWLINE);
+
+             if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
+               vty_out (vty, "Dampening enabled.%s", VTY_NEWLINE);
+             vty_out (vty, "%s", VTY_NEWLINE);
+             vty_out (vty, "%s%s", header, VTY_NEWLINE);
+           }
+         count++;
+
+         len = vty_out (vty, "%s", peer->host);
+         len = 16 - len;
+         if (len < 1)
+           vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " ");
+         else
+           vty_out (vty, "%*s", len, " ");
+
+         switch (peer->version) 
+           {
+           case BGP_VERSION_4:
+             vty_out (vty, "4 ");
+             break;
+           case BGP_VERSION_MP_4_DRAFT_00:
+             vty_out (vty, "4-");
+             break;
+           }
+
+         vty_out (vty, "%5d %7d %7d %8d %4d %4ld ",
+                  peer->as,
+                  peer->open_in + peer->update_in + peer->keepalive_in
+                  + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in,
+                  peer->open_out + peer->update_out + peer->keepalive_out
+                  + peer->notify_out + peer->refresh_out
+                  + peer->dynamic_cap_out,
+                  0, 0, peer->obuf->count);
+
+         vty_out (vty, "%8s", 
+                  peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
+
+         if (peer->status == Established)
+           {
+             vty_out (vty, " %8ld", peer->pcount[afi][safi]);
+           }
+         else
+           {
+             if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
+               vty_out (vty, " Idle (Admin)");
+             else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+               vty_out (vty, " Idle (PfxCt)");
+             else
+               vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, peer->status));
+           }
+
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+    }
+
+  if (count)
+    vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE,
+            count, VTY_NEWLINE);
+  else
+    vty_out (vty, "No %s neighbor is configured%s",
+            afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+int 
+bgp_show_summary_vty (struct vty *vty, char *name, afi_t afi, safi_t safi)
+{
+  struct bgp *bgp;
+
+  if (name)
+    {
+      bgp = bgp_lookup_by_name (name);
+      
+      if (! bgp)
+       {
+         vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); 
+         return CMD_WARNING;
+       }
+
+      bgp_show_summary (vty, bgp, afi, safi);
+      return CMD_SUCCESS;
+    }
+  
+  bgp = bgp_get_default ();
+
+  if (bgp)
+    bgp_show_summary (vty, bgp, afi, safi);    
+  return CMD_SUCCESS;
+}
+
+/* `show ip bgp summary' commands. */
+DEFUN (show_ip_bgp_summary, 
+       show_ip_bgp_summary_cmd,
+       "show ip bgp summary",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_instance_summary,
+       show_ip_bgp_instance_summary_cmd,
+       "show ip bgp view WORD summary",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);  
+}
+
+DEFUN (show_ip_bgp_ipv4_summary, 
+       show_ip_bgp_ipv4_summary_cmd,
+       "show ip bgp ipv4 (unicast|multicast) summary",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST);
+
+  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_instance_ipv4_summary,
+       show_ip_bgp_instance_ipv4_summary_cmd,
+       "show ip bgp view WORD ipv4 (unicast|multicast) summary",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST);
+  else
+    return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_vpnv4_all_summary,
+       show_ip_bgp_vpnv4_all_summary_cmd,
+       "show ip bgp vpnv4 all summary",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN);
+}
+
+DEFUN (show_ip_bgp_vpnv4_rd_summary,
+       show_ip_bgp_vpnv4_rd_summary_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Summary of BGP neighbor status\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_summary, 
+       show_bgp_summary_cmd,
+       "show bgp summary",
+       SHOW_STR
+       BGP_STR
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_instance_summary,
+       show_bgp_instance_summary_cmd,
+       "show bgp view WORD summary",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_summary, 
+       show_bgp_ipv6_summary_cmd,
+       "show bgp ipv6 summary",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Summary of BGP neighbor status\n")
+
+ALIAS (show_bgp_instance_summary,
+       show_bgp_instance_ipv6_summary_cmd,
+       "show bgp view WORD ipv6 summary",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Summary of BGP neighbor status\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_summary, 
+       show_ipv6_bgp_summary_cmd,
+       "show ipv6 bgp summary",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_summary, 
+       show_ipv6_mbgp_summary_cmd,
+       "show ipv6 mbgp summary",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Summary of BGP neighbor status\n")
+{
+  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST);
+}
+#endif /* HAVE_IPV6 */
+\f
+/* Show BGP peer's information. */
+enum show_type
+{
+  show_all,
+  show_peer
+};
+
+void
+bgp_show_peer_afi_orf_cap (struct vty *vty, struct peer *p,
+                          afi_t afi, safi_t safi,
+                          u_int16_t adv_smcap, u_int16_t adv_rmcap,
+                          u_int16_t rcv_smcap, u_int16_t rcv_rmcap)
+{
+  /* Send-Mode */
+  if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap)
+      || CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap))
+    {
+      vty_out (vty, "      Send-mode: ");
+      if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap))
+       vty_out (vty, "advertised");
+      if (CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap))
+       vty_out (vty, "%sreceived",
+                CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) ?
+                ", " : "");
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  /* Receive-Mode */
+  if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap)
+      || CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap))
+    {
+      vty_out (vty, "      Receive-mode: ");
+      if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap))
+       vty_out (vty, "advertised");
+      if (CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap))
+       vty_out (vty, "%sreceived",
+                CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) ?
+                ", " : "");
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+void
+bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+  char orf_pfx_name[BUFSIZ];
+  int orf_pfx_count;
+
+  filter = &p->filter[afi][safi];
+
+  vty_out (vty, " For address family: %s %s%s",
+          afi == AFI_IP6 ? "IPv6" :
+          safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4",
+          safi == SAFI_MULTICAST ? "Multicast" : "Unicast",
+          VTY_NEWLINE);
+  if (p->af_group[afi][safi])
+    vty_out (vty, "  %s peer-group member%s", p->group->name, VTY_NEWLINE);
+
+  if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
+    vty_out (vty, "  AF-dependant capabilities:%s", VTY_NEWLINE);
+
+  if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
+    {
+      vty_out (vty, "    Outbound Route Filter (ORF) type (%d) Prefix-list:%s",
+              ORF_TYPE_PREFIX, VTY_NEWLINE);
+      bgp_show_peer_afi_orf_cap (vty, p, afi, safi,
+                                PEER_CAP_ORF_PREFIX_SM_ADV,
+                                PEER_CAP_ORF_PREFIX_RM_ADV,
+                                PEER_CAP_ORF_PREFIX_SM_RCV,
+                                PEER_CAP_ORF_PREFIX_RM_RCV);
+    }
+  if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)
+      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
+    {
+      vty_out (vty, "    Outbound Route Filter (ORF) type (%d) Prefix-list:%s",
+              ORF_TYPE_PREFIX_OLD, VTY_NEWLINE);
+      bgp_show_peer_afi_orf_cap (vty, p, afi, safi,
+                                PEER_CAP_ORF_PREFIX_SM_ADV,
+                                PEER_CAP_ORF_PREFIX_RM_ADV,
+                                PEER_CAP_ORF_PREFIX_SM_OLD_RCV,
+                                PEER_CAP_ORF_PREFIX_RM_OLD_RCV);
+    }
+
+  sprintf (orf_pfx_name, "%s.%d.%d", p->host, afi, safi);
+  orf_pfx_count =  prefix_bgp_show_prefix_list (NULL, afi, orf_pfx_name);
+
+  if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)
+      || orf_pfx_count)
+    {
+      vty_out (vty, "  Outbound Route Filter (ORF):");
+      if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND))
+         vty_out (vty, " sent;");
+      if (orf_pfx_count)
+       vty_out (vty, " received (%d entries)", orf_pfx_count);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
+      vty_out (vty, "  First update is deferred until ORF or ROUTE-REFRESH is received%s", VTY_NEWLINE);
+
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+    vty_out (vty, "  Route-Reflector Client%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
+    vty_out (vty, "  Route-Server Client%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+    vty_out (vty, "  Inbound soft reconfiguration allowed%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS))
+    vty_out (vty, "  Private AS number removed from updates to this neighbor%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF))
+    vty_out (vty, "  NEXT_HOP is always this router%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED))
+    vty_out (vty, "  AS_PATH is propagated unchanged to this neighbor%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))
+    vty_out (vty, "  NEXT_HOP is propagated unchanged to this neighbor%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
+    vty_out (vty, "  MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
+      || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
+    {
+      vty_out (vty, "  Community attribute sent to this neighbor");
+      if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
+       && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
+       vty_out (vty, " (both)%s", VTY_NEWLINE);
+      else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
+       vty_out (vty, " (extended)%s", VTY_NEWLINE);
+      else 
+       vty_out (vty, " (standard)%s", VTY_NEWLINE);
+    }
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
+    {
+      vty_out (vty, "  Default information originate,");
+
+      if (p->default_rmap[afi][safi].name)
+       vty_out (vty, " default route-map %s%s,",
+                p->default_rmap[afi][safi].map ? "*" : "",
+                p->default_rmap[afi][safi].name);
+      if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
+       vty_out (vty, " default sent%s", VTY_NEWLINE);
+      else
+       vty_out (vty, " default not sent%s", VTY_NEWLINE);
+    }
+
+  if (filter->plist[FILTER_IN].name
+      || filter->dlist[FILTER_IN].name
+      || filter->aslist[FILTER_IN].name
+      || filter->map[FILTER_IN].name)
+    vty_out (vty, "  Inbound path policy configured%s", VTY_NEWLINE);
+  if (filter->plist[FILTER_OUT].name
+      || filter->dlist[FILTER_OUT].name
+      || filter->aslist[FILTER_OUT].name
+      || filter->map[FILTER_OUT].name
+      || filter->usmap.name)
+    vty_out (vty, "  Outbound path policy configured%s", VTY_NEWLINE);
+
+  /* prefix-list */
+  if (filter->plist[FILTER_IN].name)
+    vty_out (vty, "  Incoming update prefix filter list is %s%s%s",
+            filter->plist[FILTER_IN].plist ? "*" : "",
+            filter->plist[FILTER_IN].name,
+            VTY_NEWLINE);
+  if (filter->plist[FILTER_OUT].name)
+    vty_out (vty, "  Outgoing update prefix filter list is %s%s%s",
+            filter->plist[FILTER_OUT].plist ? "*" : "",
+            filter->plist[FILTER_OUT].name,
+            VTY_NEWLINE);
+
+  /* distribute-list */
+  if (filter->dlist[FILTER_IN].name)
+    vty_out (vty, "  Incoming update network filter list is %s%s%s",
+            filter->dlist[FILTER_IN].alist ? "*" : "",
+            filter->dlist[FILTER_IN].name,
+            VTY_NEWLINE);
+  if (filter->dlist[FILTER_OUT].name)
+    vty_out (vty, "  Outgoing update network filter list is %s%s%s",
+            filter->dlist[FILTER_OUT].alist ? "*" : "",
+            filter->dlist[FILTER_OUT].name,
+            VTY_NEWLINE);
+
+  /* filter-list. */
+  if (filter->aslist[FILTER_IN].name)
+    vty_out (vty, "  Incoming update AS path filter list is %s%s%s",
+            filter->aslist[FILTER_IN].aslist ? "*" : "",
+            filter->aslist[FILTER_IN].name,
+            VTY_NEWLINE);
+  if (filter->aslist[FILTER_OUT].name)
+    vty_out (vty, "  Outgoing update AS path filter list is %s%s%s",
+            filter->aslist[FILTER_OUT].aslist ? "*" : "",
+            filter->aslist[FILTER_OUT].name,
+            VTY_NEWLINE);
+
+  /* route-map. */
+  if (filter->map[FILTER_IN].name)
+    vty_out (vty, "  Route map for incoming advertisements is %s%s%s",
+            filter->map[FILTER_IN].map ? "*" : "",
+            filter->map[FILTER_IN].name,
+            VTY_NEWLINE);
+  if (filter->map[FILTER_OUT].name)
+    vty_out (vty, "  Route map for outgoing advertisements is %s%s%s",
+            filter->map[FILTER_OUT].map ? "*" : "",
+            filter->map[FILTER_OUT].name,
+            VTY_NEWLINE);
+
+  /* unsuppress-map */
+  if (filter->usmap.name)
+    vty_out (vty, "  Route map for selective unsuppress is %s%s%s",
+            filter->usmap.map ? "*" : "",
+            filter->usmap.name, VTY_NEWLINE);
+
+  /* Receive prefix count */
+  vty_out (vty, "  %ld accepted prefixes",
+          p->pcount[afi][safi]);
+  /* Maximum prefix */
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
+    {
+      vty_out (vty, ", maximum limit %ld%s",
+              p->pmax[afi][safi],
+              CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)
+              ? " (warning-only)" : "");
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+bgp_show_peer (struct vty *vty, struct peer *p)
+{
+  struct bgp *bgp;
+  char buf1[BUFSIZ];
+  char timebuf[BGP_UPTIME_LEN];
+
+  bgp = p->bgp;
+
+  /* Configured IP address. */
+  vty_out (vty, "BGP neighbor is %s, ", p->host);
+  vty_out (vty, "remote AS %d, ", p->as);
+  vty_out (vty, "local AS %d%s, ",
+          p->change_local_as ? p->change_local_as : p->local_as,
+          CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
+          " no-prepend" : "");
+  vty_out (vty, "%s link%s",
+          p->as == p->local_as ? "internal" : "external",
+          VTY_NEWLINE);
+
+  /* Description. */
+  if (p->desc)
+    vty_out (vty, " Description: %s%s", p->desc, VTY_NEWLINE);
+  
+  /* Peer-group */
+  if (p->group)
+    vty_out (vty, " Member of peer-group %s for session parameters%s",
+            p->group->name, VTY_NEWLINE);
+
+  /* Administrative shutdown. */
+  if (CHECK_FLAG (p->flags, PEER_FLAG_SHUTDOWN))
+    vty_out (vty, " Administratively shut down%s", VTY_NEWLINE);
+
+  /* BGP Version. */
+  vty_out (vty, "  BGP version 4");
+  if (p->version == BGP_VERSION_MP_4_DRAFT_00)
+    vty_out (vty, "(with draft-00 verion of multiporotocol extension)");
+  vty_out (vty, ", remote router ID %s%s", 
+          inet_ntop (AF_INET, &p->remote_id, buf1, BUFSIZ),
+          VTY_NEWLINE);
+
+  /* Confederation */
+  if (bgp_confederation_peers_check (bgp, p->as)) 
+    vty_out (vty, "  Neighbor under common administration%s", VTY_NEWLINE);
+  
+  /* Status. */
+  vty_out (vty, "  BGP state = %s",  
+          LOOKUP (bgp_status_msg, p->status));
+  if (p->status == Established) 
+    vty_out (vty, ", up for %8s", 
+            peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN));
+  vty_out (vty, "%s", VTY_NEWLINE);
+  
+  /* read timer */
+  vty_out (vty, "  Last read %s", peer_uptime (p->readtime, timebuf, BGP_UPTIME_LEN));
+
+  /* Configured timer values. */
+  vty_out (vty, ", hold time is %d, keepalive interval is %d seconds%s",
+          p->v_holdtime, p->v_keepalive, VTY_NEWLINE);
+  if (CHECK_FLAG (p->config, PEER_CONFIG_TIMER))
+    {
+      vty_out (vty, "  Configured hold time is %d", p->holdtime);
+      vty_out (vty, ", keepalive interval is %d seconds%s",
+              p->keepalive, VTY_NEWLINE);
+    }
+  
+  /* Capability. */
+  if (p->status == Established) 
+    {
+      if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)
+         || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)
+         || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)
+         || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)
+         || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)
+         || p->afc_adv[AFI_IP][SAFI_UNICAST]
+         || p->afc_recv[AFI_IP][SAFI_UNICAST]
+         || p->afc_adv[AFI_IP][SAFI_MULTICAST]
+         || p->afc_recv[AFI_IP][SAFI_MULTICAST]
+#ifdef HAVE_IPV6
+         || p->afc_adv[AFI_IP6][SAFI_UNICAST]
+         || p->afc_recv[AFI_IP6][SAFI_UNICAST]
+         || p->afc_adv[AFI_IP6][SAFI_MULTICAST]
+         || p->afc_recv[AFI_IP6][SAFI_MULTICAST]
+#endif /* HAVE_IPV6 */
+         || p->afc_adv[AFI_IP][SAFI_MPLS_VPN]
+         || p->afc_recv[AFI_IP][SAFI_MPLS_VPN])
+       {
+         vty_out (vty, "  Neighbor capabilities:%s", VTY_NEWLINE);
+
+         /* Dynamic */
+         if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)
+             || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV))
+           {
+             vty_out (vty, "    Dynamic:");
+             if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV))
+               vty_out (vty, " advertised");
+             if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV))
+               {
+                 if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV))
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+
+         /* Route Refresh */
+         if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)
+             || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)
+             || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV))
+           {
+             vty_out (vty, "    Route refresh:");
+             if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV))
+               vty_out (vty, " advertised");
+             if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)
+                 || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV))
+               {
+                 if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV))
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+                 if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)
+                     && CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV))
+                   vty_out (vty, " (old and new)");
+                 else if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV))
+                   vty_out (vty, " (old)");
+                 else 
+                   vty_out (vty, " (new)");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+
+         /* IPv4 */
+         if (p->afc_adv[AFI_IP][SAFI_UNICAST]
+             || p->afc_recv[AFI_IP][SAFI_UNICAST]) 
+           {
+             vty_out (vty, "    Address family IPv4 Unicast:");
+             if (p->afc_adv[AFI_IP][SAFI_UNICAST]) 
+               vty_out (vty, " advertised");
+             if (p->afc_recv[AFI_IP][SAFI_UNICAST])
+               {
+                 if (p->afc_adv[AFI_IP][SAFI_UNICAST])
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+         if (p->afc_adv[AFI_IP][SAFI_MULTICAST] || p->afc_recv[AFI_IP][SAFI_MULTICAST]) 
+           {
+             vty_out (vty, "    Address family IPv4 Multicast:");
+             if (p->afc_adv[AFI_IP][SAFI_MULTICAST]) 
+               vty_out (vty, " advertised");
+             if (p->afc_recv[AFI_IP][SAFI_MULTICAST])
+               {
+                 if (p->afc_adv[AFI_IP][SAFI_MULTICAST])
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+         if (p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) 
+           {
+             vty_out (vty, "    Address family VPNv4 Unicast:");
+             if (p->afc_adv[AFI_IP][SAFI_MPLS_VPN]) 
+               vty_out (vty, " advertised");
+             if (p->afc_recv[AFI_IP][SAFI_MPLS_VPN])
+               {
+                 if (p->afc_adv[AFI_IP][SAFI_MPLS_VPN])
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+         /* IPv6 */
+#ifdef HAVE_IPV6
+         if (p->afc_adv[AFI_IP6][SAFI_UNICAST] || p->afc_recv[AFI_IP6][SAFI_UNICAST]) 
+           {
+             vty_out (vty, "    Address family IPv6 Unicast:");
+             if (p->afc_adv[AFI_IP6][SAFI_UNICAST]) 
+               vty_out (vty, " advertised");
+             if (p->afc_recv[AFI_IP6][SAFI_UNICAST])
+               {
+                 if (p->afc_adv[AFI_IP6][SAFI_UNICAST])
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+         if (p->afc_adv[AFI_IP6][SAFI_MULTICAST] || p->afc_recv[AFI_IP6][SAFI_MULTICAST]) 
+           {
+             vty_out (vty, "    Address family IPv6 Multicast:");
+             if (p->afc_adv[AFI_IP6][SAFI_MULTICAST]) 
+               vty_out (vty, " advertised");
+             if (p->afc_recv[AFI_IP6][SAFI_MULTICAST])
+               {
+                 if (p->afc_adv[AFI_IP6][SAFI_MULTICAST])
+                   vty_out (vty, " and");
+                 vty_out (vty, " received");
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+#endif /* HAVE_IPV6 */
+       }
+    }
+
+  /* Packet counts. */
+  vty_out(vty, "  Received %d messages, %d notifications, %d in queue%s",
+         p->open_in + p->update_in + p->keepalive_in + p->refresh_in
+         + p->dynamic_cap_in, p->notify_in, 0, VTY_NEWLINE);
+  vty_out(vty, "  Sent %d messages, %d notifications, %ld in queue%s",
+         p->open_out + p->update_out + p->keepalive_out + p->refresh_out
+         + p->dynamic_cap_out, p->notify_out, p->obuf->count, VTY_NEWLINE);
+  vty_out(vty, "  Route refresh request: received %d, sent %d%s",
+         p->refresh_in, p->refresh_out, VTY_NEWLINE);
+
+  /* advertisement-interval */
+  vty_out (vty, "  Minimum time between advertisement runs is %d seconds%s",
+          p->v_routeadv, VTY_NEWLINE);
+
+  /* Update-source. */
+  if (p->update_if || p->update_source)
+    {
+      vty_out (vty, "  Update source is ");
+      if (p->update_if)
+       vty_out (vty, "%s", p->update_if);
+      else if (p->update_source)
+       vty_out (vty, "%s",
+                sockunion2str (p->update_source, buf1, SU_ADDRSTRLEN));
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  /* Default weight */
+  if (CHECK_FLAG (p->config, PEER_CONFIG_WEIGHT))
+    vty_out (vty, "  Default weight %d%s", p->weight,
+            VTY_NEWLINE);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  /* Address Family Information */
+  if (p->afc[AFI_IP][SAFI_UNICAST])
+    bgp_show_peer_afi (vty, p, AFI_IP, SAFI_UNICAST);
+  if (p->afc[AFI_IP][SAFI_MULTICAST])
+    bgp_show_peer_afi (vty, p, AFI_IP, SAFI_MULTICAST);
+  if (p->afc[AFI_IP][SAFI_MPLS_VPN])
+    bgp_show_peer_afi (vty, p, AFI_IP, SAFI_MPLS_VPN);
+#ifdef HAVE_IPV6
+  if (p->afc[AFI_IP6][SAFI_UNICAST])
+    bgp_show_peer_afi (vty, p, AFI_IP6, SAFI_UNICAST);
+  if (p->afc[AFI_IP6][SAFI_MULTICAST])
+    bgp_show_peer_afi (vty, p, AFI_IP6, SAFI_MULTICAST);
+#endif /* HAVE_IPV6 */
+
+  vty_out (vty, "  Connections established %d; dropped %d%s",
+          p->established, p->dropped,
+          VTY_NEWLINE);
+
+  if (CHECK_FLAG (p->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+    {
+      vty_out (vty, "  Peer had exceeded the max. no. of prefixes configured.%s", VTY_NEWLINE);
+      vty_out (vty, "  Reduce the no. of prefix and clear ip bgp %s to restore peering%s",
+              p->host, VTY_NEWLINE);
+    }
+
+  /* EBGP Multihop */
+  if (peer_sort (p) != BGP_PEER_IBGP && p->ttl > 1)
+    vty_out (vty, "  External BGP neighbor may be up to %d hops away.%s",
+            p->ttl, VTY_NEWLINE);
+
+  /* Local address. */
+  if (p->su_local)
+    {
+      vty_out (vty, "Local host: %s, Local port: %d%s%s",
+              sockunion2str (p->su_local, buf1, SU_ADDRSTRLEN),
+              ntohs (p->su_local->sin.sin_port),
+              CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE) ?
+              ", passive-mode" : "", 
+              VTY_NEWLINE);
+    }
+      
+  /* Remote address. */
+  if (p->su_remote)
+    {
+      vty_out (vty, "Foreign host: %s, Foreign port: %d%s",
+              sockunion2str (p->su_remote, buf1, SU_ADDRSTRLEN),
+              ntohs (p->su_remote->sin.sin_port),
+              VTY_NEWLINE);
+    }
+
+  /* Nexthop display. */
+  if (p->su_local)
+    {
+      vty_out (vty, "Nexthop: %s%s", 
+              inet_ntop (AF_INET, &p->nexthop.v4, buf1, BUFSIZ),
+              VTY_NEWLINE);
+#ifdef HAVE_IPV6
+      vty_out (vty, "Nexthop global: %s%s", 
+              inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ),
+              VTY_NEWLINE);
+      vty_out (vty, "Nexthop local: %s%s",
+              inet_ntop (AF_INET6, &p->nexthop.v6_local, buf1, BUFSIZ),
+              VTY_NEWLINE);
+      vty_out (vty, "BGP connection: %s%s",
+              p->shared_network ? "shared network" : "non shared network",
+              VTY_NEWLINE);
+#endif /* HAVE_IPV6 */
+    }
+
+  /* Timer information. */
+  if (p->t_start)
+    vty_out (vty, "Next start timer due in %ld seconds%s",
+            thread_timer_remain_second (p->t_start), VTY_NEWLINE);
+  if (p->t_connect)
+    vty_out (vty, "Next connect timer due in %ld seconds%s",
+            thread_timer_remain_second (p->t_connect), VTY_NEWLINE);
+  
+  vty_out (vty, "Read thread: %s  Write thread: %s%s", 
+          p->t_read ? "on" : "off",
+          p->t_write ? "on" : "off",
+          VTY_NEWLINE);
+
+  if (p->notify.code == BGP_NOTIFY_OPEN_ERR
+      && p->notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL)
+    bgp_capability_vty_out (vty, p);
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+bgp_show_neighbor (struct vty *vty, struct bgp *bgp,
+                  enum show_type type, union sockunion *su)
+{
+  struct listnode *nn;
+  struct peer *peer;
+  int find = 0;
+
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      switch (type)
+       {
+       case show_all:
+         bgp_show_peer (vty, peer);
+         break;
+       case show_peer:
+         if (sockunion_same (&peer->su, su))
+           {
+             find = 1;
+             bgp_show_peer (vty, peer);
+           }
+         break;
+       }
+    }
+
+  if (type == show_peer && ! find)
+    vty_out (vty, "%% No such neighbor%s", VTY_NEWLINE);
+  
+  return CMD_SUCCESS;
+}
+
+int 
+bgp_show_neighbor_vty (struct vty *vty, char *name, enum show_type type,
+                      char *ip_str)
+{
+  int ret;
+  struct bgp *bgp;
+  union sockunion su;
+
+  if (ip_str)
+    {
+      ret = str2sockunion (ip_str, &su);
+      if (ret < 0)
+        {
+          vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+
+  if (name)
+    {
+      bgp = bgp_lookup_by_name (name);
+      
+      if (! bgp)
+        {
+          vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); 
+          return CMD_WARNING;
+        }
+
+      bgp_show_neighbor (vty, bgp, type, &su);
+
+      return CMD_SUCCESS;
+    }
+
+  bgp = bgp_get_default ();
+
+  if (bgp)
+    bgp_show_neighbor (vty, bgp, type, &su);
+
+  return CMD_SUCCESS;
+}
+
+/* "show ip bgp neighbors" commands.  */
+DEFUN (show_ip_bgp_neighbors,
+       show_ip_bgp_neighbors_cmd,
+       "show ip bgp neighbors",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n")
+{
+  return bgp_show_neighbor_vty (vty, NULL, show_all, NULL);
+}
+
+ALIAS (show_ip_bgp_neighbors,
+       show_ip_bgp_ipv4_neighbors_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+ALIAS (show_ip_bgp_neighbors,
+       show_ip_bgp_vpnv4_all_neighbors_cmd,
+       "show ip bgp vpnv4 all neighbors",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+ALIAS (show_ip_bgp_neighbors,
+       show_ip_bgp_vpnv4_rd_neighbors_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+ALIAS (show_ip_bgp_neighbors,
+       show_bgp_neighbors_cmd,
+       "show bgp neighbors",
+       SHOW_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+ALIAS (show_ip_bgp_neighbors,
+       show_bgp_ipv6_neighbors_cmd,
+       "show bgp ipv6 neighbors",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFUN (show_ip_bgp_neighbors_peer,
+       show_ip_bgp_neighbors_peer_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+{
+  return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]);
+}
+
+ALIAS (show_ip_bgp_neighbors_peer,
+       show_ip_bgp_ipv4_neighbors_peer_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+ALIAS (show_ip_bgp_neighbors_peer,
+       show_ip_bgp_vpnv4_all_neighbors_peer_cmd,
+       "show ip bgp vpnv4 all neighbors A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n")
+
+ALIAS (show_ip_bgp_neighbors_peer,
+       show_ip_bgp_vpnv4_rd_neighbors_peer_cmd,
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n")
+
+ALIAS (show_ip_bgp_neighbors_peer,
+       show_bgp_neighbors_peer_cmd,
+       "show bgp neighbors (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+ALIAS (show_ip_bgp_neighbors_peer,
+       show_bgp_ipv6_neighbors_peer_cmd,
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+DEFUN (show_ip_bgp_instance_neighbors,
+       show_ip_bgp_instance_neighbors_cmd,
+       "show ip bgp view WORD neighbors",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+{
+  return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL);
+}
+
+DEFUN (show_ip_bgp_instance_neighbors_peer,
+       show_ip_bgp_instance_neighbors_peer_cmd,
+       "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+{
+  return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]);
+}
+\f
+/* Show BGP's AS paths internal data.  There are both `show ip bgp
+   paths' and `show ip mbgp paths'.  Those functions results are the
+   same.*/
+DEFUN (show_ip_bgp_paths, 
+       show_ip_bgp_paths_cmd,
+       "show ip bgp paths",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Path information\n")
+{
+  vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE);
+  aspath_print_all_vty (vty);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_ipv4_paths, 
+       show_ip_bgp_ipv4_paths_cmd,
+       "show ip bgp ipv4 (unicast|multicast) paths",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Path information\n")
+{
+  vty_out (vty, "Address Refcnt Path\r\n");
+  aspath_print_all_vty (vty);
+
+  return CMD_SUCCESS;
+}
+\f
+#include "hash.h"
+
+void
+community_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+{
+  struct community *com;
+
+  com = (struct community *) backet->data;
+  vty_out (vty, "[%p] (%ld) %s%s", backet, com->refcnt,
+          community_str (com), VTY_NEWLINE);
+}
+
+/* Show BGP's community internal data. */
+DEFUN (show_ip_bgp_community_info, 
+       show_ip_bgp_community_info_cmd,
+       "show ip bgp community-info",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "List all bgp community information\n")
+{
+  vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE);
+
+  hash_iterate (community_hash (), 
+               (void (*) (struct hash_backet *, void *))
+               community_show_all_iterator,
+               vty);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_attr_info, 
+       show_ip_bgp_attr_info_cmd,
+       "show ip bgp attribute-info",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "List all bgp attribute information\n")
+{
+  attr_show_all (vty);
+  return CMD_SUCCESS;
+}
+\f
+/* Redistribute VTY commands.  */
+
+/* Utility function to convert user input route type string to route
+   type.  */
+static int
+bgp_str2route_type (int afi, char *str)
+{
+  if (! str)
+    return 0;
+
+  if (afi == AFI_IP)
+    {
+      if (strncmp (str, "k", 1) == 0)
+       return ZEBRA_ROUTE_KERNEL;
+      else if (strncmp (str, "c", 1) == 0)
+       return ZEBRA_ROUTE_CONNECT;
+      else if (strncmp (str, "s", 1) == 0)
+       return ZEBRA_ROUTE_STATIC;
+      else if (strncmp (str, "r", 1) == 0)
+       return ZEBRA_ROUTE_RIP;
+      else if (strncmp (str, "o", 1) == 0)
+       return ZEBRA_ROUTE_OSPF;
+    }
+  if (afi == AFI_IP6)
+    {
+      if (strncmp (str, "k", 1) == 0)
+       return ZEBRA_ROUTE_KERNEL;
+      else if (strncmp (str, "c", 1) == 0)
+       return ZEBRA_ROUTE_CONNECT;
+      else if (strncmp (str, "s", 1) == 0)
+       return ZEBRA_ROUTE_STATIC;
+      else if (strncmp (str, "r", 1) == 0)
+       return ZEBRA_ROUTE_RIPNG;
+      else if (strncmp (str, "o", 1) == 0)
+       return ZEBRA_ROUTE_OSPF6;
+    }
+  return 0;
+}
+
+DEFUN (bgp_redistribute_ipv4,
+       bgp_redistribute_ipv4_cmd,
+       "redistribute (connected|kernel|ospf|rip|static)",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_redistribute_set (vty->index, AFI_IP, type);
+}
+
+DEFUN (bgp_redistribute_ipv4_rmap,
+       bgp_redistribute_ipv4_rmap_cmd,
+       "redistribute (connected|kernel|ospf|rip|static) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]);
+  return bgp_redistribute_set (vty->index, AFI_IP, type);
+}
+
+DEFUN (bgp_redistribute_ipv4_metric,
+       bgp_redistribute_ipv4_metric_cmd,
+       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+  u_int32_t metric;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  VTY_GET_INTEGER ("metric", metric, argv[1]);
+
+  bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric);
+  return bgp_redistribute_set (vty->index, AFI_IP, type);
+}
+
+DEFUN (bgp_redistribute_ipv4_rmap_metric,
+       bgp_redistribute_ipv4_rmap_metric_cmd,
+       "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+  u_int32_t metric;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  VTY_GET_INTEGER ("metric", metric, argv[2]);
+
+  bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]);
+  bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric);
+  return bgp_redistribute_set (vty->index, AFI_IP, type);
+}
+
+DEFUN (bgp_redistribute_ipv4_metric_rmap,
+       bgp_redistribute_ipv4_metric_rmap_cmd,
+       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type;
+  u_int32_t metric;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  VTY_GET_INTEGER ("metric", metric, argv[1]);
+
+  bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric);
+  bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[2]);
+  return bgp_redistribute_set (vty->index, AFI_IP, type);
+}
+
+DEFUN (no_bgp_redistribute_ipv4,
+       no_bgp_redistribute_ipv4_cmd,
+       "no redistribute (connected|kernel|ospf|rip|static)",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_redistribute_unset (vty->index, AFI_IP, type);
+}
+
+DEFUN (no_bgp_redistribute_ipv4_rmap,
+       no_bgp_redistribute_ipv4_rmap_cmd,
+       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_routemap_unset (vty->index, AFI_IP, type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_redistribute_ipv4_metric,
+       no_bgp_redistribute_ipv4_metric_cmd,
+       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_metric_unset (vty->index, AFI_IP, type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
+       no_bgp_redistribute_ipv4_rmap_metric_cmd,
+       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_metric_unset (vty->index, AFI_IP, type);
+  bgp_redistribute_routemap_unset (vty->index, AFI_IP, type);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
+       no_bgp_redistribute_ipv4_metric_rmap_cmd,
+       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+\f
+#ifdef HAVE_IPV6
+DEFUN (bgp_redistribute_ipv6,
+       bgp_redistribute_ipv6_cmd,
+       "redistribute (connected|kernel|ospf6|ripng|static)",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_redistribute_set (vty->index, AFI_IP6, type);
+}
+
+DEFUN (bgp_redistribute_ipv6_rmap,
+       bgp_redistribute_ipv6_rmap_cmd,
+       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]);
+  return bgp_redistribute_set (vty->index, AFI_IP6, type);
+}
+
+DEFUN (bgp_redistribute_ipv6_metric,
+       bgp_redistribute_ipv6_metric_cmd,
+       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+  u_int32_t metric;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  VTY_GET_INTEGER ("metric", metric, argv[1]);
+
+  bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric);
+  return bgp_redistribute_set (vty->index, AFI_IP6, type);
+}
+
+DEFUN (bgp_redistribute_ipv6_rmap_metric,
+       bgp_redistribute_ipv6_rmap_metric_cmd,
+       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+  u_int32_t metric;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  VTY_GET_INTEGER ("metric", metric, argv[2]);
+
+  bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]);
+  bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric);
+  return bgp_redistribute_set (vty->index, AFI_IP6, type);
+}
+
+DEFUN (bgp_redistribute_ipv6_metric_rmap,
+       bgp_redistribute_ipv6_metric_rmap_cmd,
+       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type;
+  u_int32_t metric;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  VTY_GET_INTEGER ("metric", metric, argv[1]);
+
+  bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric);
+  bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[2]);
+  return bgp_redistribute_set (vty->index, AFI_IP6, type);
+}
+
+DEFUN (no_bgp_redistribute_ipv6,
+       no_bgp_redistribute_ipv6_cmd,
+       "no redistribute (connected|kernel|ospf6|ripng|static)",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_redistribute_unset (vty->index, AFI_IP6, type);
+}
+
+DEFUN (no_bgp_redistribute_ipv6_rmap,
+       no_bgp_redistribute_ipv6_rmap_cmd,
+       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_redistribute_ipv6_metric,
+       no_bgp_redistribute_ipv6_metric_cmd,
+       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_metric_unset (vty->index, AFI_IP6, type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
+       no_bgp_redistribute_ipv6_rmap_metric_cmd,
+       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+{
+  int type;
+
+  type = bgp_str2route_type (AFI_IP6, argv[0]);
+  if (! type)
+    {
+      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  bgp_redistribute_metric_unset (vty->index, AFI_IP6, type);
+  bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_redistribute_ipv6_rmap_metric,
+       no_bgp_redistribute_ipv6_metric_rmap_cmd,
+       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+#endif /* HAVE_IPV6 */
+\f
+int
+bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
+                              safi_t safi, int *write)
+{
+  int i;
+  char *str[] = { "system", "kernel", "connected", "static", "rip",
+                 "ripng", "ospf", "ospf6", "bgp"};
+
+  /* Unicast redistribution only.  */
+  if (safi != SAFI_UNICAST)
+    return 0;
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      /* Redistribute BGP does not make sense.  */
+      if (bgp->redist[afi][i] && i != ZEBRA_ROUTE_BGP)
+       {
+         /* Display "address-family" when it is not yet diplayed.  */
+         bgp_config_write_family_header (vty, afi, safi, write);
+
+         /* "redistribute" configuration.  */
+         vty_out (vty, " redistribute %s", str[i]);
+
+         if (bgp->redist_metric_flag[afi][i])
+           vty_out (vty, " metric %d", bgp->redist_metric[afi][i]);
+
+         if (bgp->rmap[afi][i].name)
+           vty_out (vty, " route-map %s", bgp->rmap[afi][i].name);
+
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+    }
+  return *write;
+}
+\f
+/* BGP node structure. */
+struct cmd_node bgp_node =
+{
+  BGP_NODE,
+  "%s(config-router)# ",
+  1,
+};
+
+struct cmd_node bgp_ipv4_unicast_node =
+{
+  BGP_IPV4_NODE,
+  "%s(config-router-af)# ",
+  1,
+};
+
+struct cmd_node bgp_ipv4_multicast_node =
+{
+  BGP_IPV4M_NODE,
+  "%s(config-router-af)# ",
+  1,
+};
+
+struct cmd_node bgp_ipv6_unicast_node = 
+{
+  BGP_IPV6_NODE,
+  "%s(config-router-af)# ",
+  1,
+};
+
+struct cmd_node bgp_vpnv4_node =
+{
+  BGP_VPNV4_NODE,
+  "%s(config-router-af)# ",
+  1
+};
+\f
+void
+bgp_vty_init ()
+{
+  int bgp_config_write (struct vty *);
+  void community_list_vty ();
+
+  /* Install bgp top node. */
+  install_node (&bgp_node, bgp_config_write);
+  install_node (&bgp_ipv4_unicast_node, NULL);
+  install_node (&bgp_ipv4_multicast_node, NULL);
+  install_node (&bgp_ipv6_unicast_node, NULL);
+  install_node (&bgp_vpnv4_node, NULL);
+
+  /* Install default VTY commands to new nodes.  */
+  install_default (BGP_NODE);
+  install_default (BGP_IPV4_NODE);
+  install_default (BGP_IPV4M_NODE);
+  install_default (BGP_IPV6_NODE);
+  install_default (BGP_VPNV4_NODE);
+  
+  /* "bgp multiple-instance" commands. */
+  install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
+  install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
+
+  /* "bgp config-type" commands. */
+  install_element (CONFIG_NODE, &bgp_config_type_cmd);
+  install_element (CONFIG_NODE, &no_bgp_config_type_cmd);
+
+  /* Dummy commands (Currently not supported) */
+  install_element (BGP_NODE, &no_synchronization_cmd);
+  install_element (BGP_NODE, &no_auto_summary_cmd);
+
+  /* "router bgp" commands. */
+  install_element (CONFIG_NODE, &router_bgp_cmd);
+  install_element (CONFIG_NODE, &router_bgp_view_cmd);
+
+  /* "no router bgp" commands. */
+  install_element (CONFIG_NODE, &no_router_bgp_cmd);
+  install_element (CONFIG_NODE, &no_router_bgp_view_cmd);
+
+  /* "bgp router-id" commands. */
+  install_element (BGP_NODE, &bgp_router_id_cmd);
+  install_element (BGP_NODE, &no_bgp_router_id_cmd);
+  install_element (BGP_NODE, &no_bgp_router_id_val_cmd);
+
+  /* "bgp cluster-id" commands. */
+  install_element (BGP_NODE, &bgp_cluster_id_cmd);
+  install_element (BGP_NODE, &bgp_cluster_id32_cmd);
+  install_element (BGP_NODE, &no_bgp_cluster_id_cmd);
+  install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd);
+
+  /* "bgp confederation" commands. */
+  install_element (BGP_NODE, &bgp_confederation_identifier_cmd);
+  install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd);
+  install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd);
+
+  /* "bgp confederation peers" commands. */
+  install_element (BGP_NODE, &bgp_confederation_peers_cmd);
+  install_element (BGP_NODE, &no_bgp_confederation_peers_cmd);
+
+  /* "timers bgp" commands. */
+  install_element (BGP_NODE, &bgp_timers_cmd);
+  install_element (BGP_NODE, &no_bgp_timers_cmd);
+  install_element (BGP_NODE, &no_bgp_timers_arg_cmd);
+
+  /* "bgp client-to-client reflection" commands */
+  install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd);
+  install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd);
+
+  /* "bgp always-compare-med" commands */
+  install_element (BGP_NODE, &bgp_always_compare_med_cmd);
+  install_element (BGP_NODE, &no_bgp_always_compare_med_cmd);
+  
+  /* "bgp deterministic-med" commands */
+  install_element (BGP_NODE, &bgp_deterministic_med_cmd);
+  install_element (BGP_NODE, &no_bgp_deterministic_med_cmd);
+  /* "bgp fast-external-failover" commands */
+  install_element (BGP_NODE, &bgp_fast_external_failover_cmd);
+  install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd);
+
+  /* "bgp enforce-first-as" commands */
+  install_element (BGP_NODE, &bgp_enforce_first_as_cmd);
+  install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd);
+
+  /* "bgp bestpath compare-routerid" commands */
+  install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
+  install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd);
+
+  /* "bgp bestpath as-path ignore" commands */
+  install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd);
+  install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd);
+
+  /* "bgp bestpath med" commands */
+  install_element (BGP_NODE, &bgp_bestpath_med_cmd);
+  install_element (BGP_NODE, &bgp_bestpath_med2_cmd);
+  install_element (BGP_NODE, &bgp_bestpath_med3_cmd);
+  install_element (BGP_NODE, &no_bgp_bestpath_med_cmd);
+  install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd);
+  install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd);
+
+  /* "no bgp default ipv4-unicast" commands. */
+  install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd);
+  install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd);
+  
+  /* "bgp network import-check" commands. */
+  install_element (BGP_NODE, &bgp_network_import_check_cmd);
+  install_element (BGP_NODE, &no_bgp_network_import_check_cmd);
+
+  /* "bgp default local-preference" commands. */
+  install_element (BGP_NODE, &bgp_default_local_preference_cmd);
+  install_element (BGP_NODE, &no_bgp_default_local_preference_cmd);
+  install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd);
+
+  /* "neighbor remote-as" commands. */
+  install_element (BGP_NODE, &neighbor_remote_as_cmd);
+  install_element (BGP_NODE, &no_neighbor_cmd);
+  install_element (BGP_NODE, &no_neighbor_remote_as_cmd);
+
+  /* "neighbor peer-group" commands. */
+  install_element (BGP_NODE, &neighbor_peer_group_cmd);
+  install_element (BGP_NODE, &no_neighbor_peer_group_cmd);
+  install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd);
+
+  /* "neighbor local-as" commands. */
+  install_element (BGP_NODE, &neighbor_local_as_cmd);
+  install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd);
+  install_element (BGP_NODE, &no_neighbor_local_as_cmd);
+  install_element (BGP_NODE, &no_neighbor_local_as_val_cmd);
+  install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd);
+
+  /* "neighbor activate" commands. */
+  install_element (BGP_NODE, &neighbor_activate_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_activate_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_activate_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd);
+
+  /* "no neighbor activate" commands. */
+  install_element (BGP_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd);
+
+  /* "neighbor peer-group set" commands. */
+  install_element (BGP_NODE, &neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd);
+
+  /* "no neighbor peer-group unset" commands. */
+  install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd);
+
+  /* "neighbor softreconfiguration inbound" commands.*/
+  install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
+
+  /* "neighbor attribute-unchanged" commands.  */
+  install_element (BGP_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd);
+
+  /* "transparent-as" and "transparent-nexthop" for old version
+     compatibility.  */
+  install_element (BGP_NODE, &neighbor_transparent_as_cmd);
+  install_element (BGP_NODE, &neighbor_transparent_nexthop_cmd);
+
+  /* "neighbor next-hop-self" commands. */
+  install_element (BGP_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd);
+
+  /* "neighbor remove-private-AS" commands. */
+  install_element (BGP_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd);
+
+  /* "neighbor send-community" commands.*/
+  install_element (BGP_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd);
+
+  /* "neighbor route-reflector" commands.*/
+  install_element (BGP_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd);
+
+  /* "neighbor route-server" commands.*/
+  install_element (BGP_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd);
+
+  /* "neighbor passive" commands. */
+  install_element (BGP_NODE, &neighbor_passive_cmd);
+  install_element (BGP_NODE, &no_neighbor_passive_cmd);
+
+  /* "neighbor shutdown" commands. */
+  install_element (BGP_NODE, &neighbor_shutdown_cmd);
+  install_element (BGP_NODE, &no_neighbor_shutdown_cmd);
+
+  /* "neighbor capability route-refresh" commands.*/
+  install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd);
+  install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd);
+
+  /* "neighbor capability orf prefix-list" commands.*/
+  install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd);
+
+  /* "neighbor capability dynamic" commands.*/
+  install_element (BGP_NODE, &neighbor_capability_dynamic_cmd);
+  install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd);
+
+  /* "neighbor dont-capability-negotiate" commands. */
+  install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd);
+  install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd);
+
+  /* "neighbor ebgp-multihop" commands. */
+  install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd);
+  install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd);
+  install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd);
+  install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd);
+
+  /* "neighbor enforce-multihop" commands.  */
+  install_element (BGP_NODE, &neighbor_enforce_multihop_cmd);
+  install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd);
+
+  /* "neighbor description" commands. */
+  install_element (BGP_NODE, &neighbor_description_cmd);
+  install_element (BGP_NODE, &no_neighbor_description_cmd);
+  install_element (BGP_NODE, &no_neighbor_description_val_cmd);
+
+  /* "neighbor update-source" commands. "*/
+  install_element (BGP_NODE, &neighbor_update_source_cmd);
+  install_element (BGP_NODE, &no_neighbor_update_source_cmd);
+
+  /* "neighbor default-originate" commands. */
+  install_element (BGP_NODE, &neighbor_default_originate_cmd);
+  install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd);
+  install_element (BGP_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd);
+
+  /* "neighbor port" commands. */
+  install_element (BGP_NODE, &neighbor_port_cmd);
+  install_element (BGP_NODE, &no_neighbor_port_cmd);
+  install_element (BGP_NODE, &no_neighbor_port_val_cmd);
+
+  /* "neighbor weight" commands. */
+  install_element (BGP_NODE, &neighbor_weight_cmd);
+  install_element (BGP_NODE, &no_neighbor_weight_cmd);
+  install_element (BGP_NODE, &no_neighbor_weight_val_cmd);
+
+  /* "neighbor override-capability" commands. */
+  install_element (BGP_NODE, &neighbor_override_capability_cmd);
+  install_element (BGP_NODE, &no_neighbor_override_capability_cmd);
+
+  /* "neighbor strict-capability-match" commands. */
+  install_element (BGP_NODE, &neighbor_strict_capability_cmd);
+  install_element (BGP_NODE, &no_neighbor_strict_capability_cmd);
+
+  /* "neighbor timers" commands. */
+  install_element (BGP_NODE, &neighbor_timers_cmd);
+  install_element (BGP_NODE, &no_neighbor_timers_cmd);
+
+  /* "neighbor timers connect" commands. */
+  install_element (BGP_NODE, &neighbor_timers_connect_cmd);
+  install_element (BGP_NODE, &no_neighbor_timers_connect_cmd);
+  install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd);
+
+  /* "neighbor advertisement-interval" commands. */
+  install_element (BGP_NODE, &neighbor_advertise_interval_cmd);
+  install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd);
+  install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd);
+
+  /* "neighbor version" commands. */
+  install_element (BGP_NODE, &neighbor_version_cmd);
+  install_element (BGP_NODE, &no_neighbor_version_cmd);
+
+  /* "neighbor interface" commands. */
+  install_element (BGP_NODE, &neighbor_interface_cmd);
+  install_element (BGP_NODE, &no_neighbor_interface_cmd);
+
+  /* "neighbor distribute" commands. */
+  install_element (BGP_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd);
+
+  /* "neighbor prefix-list" commands. */
+  install_element (BGP_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd);
+
+  /* "neighbor filter-list" commands. */
+  install_element (BGP_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd);
+
+  /* "neighbor route-map" commands. */
+  install_element (BGP_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
+
+  /* "neighbor unsuppress-map" commands. */
+  install_element (BGP_NODE, &neighbor_unsuppress_map_cmd);
+  install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd);
+
+  /* "neighbor maximum-prefix" commands. */
+  install_element (BGP_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_val2_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val2_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val2_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val2_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val2_cmd);
+
+  /* "neighbor allowas-in" */
+  install_element (BGP_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd);
+  install_element (BGP_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd);
+
+  /* address-family commands. */
+  install_element (BGP_NODE, &address_family_ipv4_cmd);
+  install_element (BGP_NODE, &address_family_ipv4_safi_cmd);
+#ifdef HAVE_IPV6
+  install_element (BGP_NODE, &address_family_ipv6_cmd);
+  install_element (BGP_NODE, &address_family_ipv6_unicast_cmd);
+#endif /* HAVE_IPV6 */
+  install_element (BGP_NODE, &address_family_vpnv4_cmd);
+  install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd);
+
+  /* "exit-address-family" command. */
+  install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
+  install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
+
+  /* "clear ip bgp commands" */
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd);
+#ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &clear_bgp_all_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* "clear ip bgp neighbor soft in" */
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd);
+#ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_all_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* "clear ip bgp neighbor soft out" */
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd);
+#ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_all_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* "clear ip bgp neighbor soft" */
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd);
+#ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* "show ip bgp summary" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd);
+#ifdef HAVE_IPV6
+  install_element (VIEW_NODE, &show_bgp_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_instance_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd);
+#endif /* HAVE_IPV6 */
+  install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd);
+#ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &show_bgp_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* "show ip bgp neighbors" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd);
+
+#ifdef HAVE_IPV6
+  install_element (VIEW_NODE, &show_bgp_neighbors_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd);
+  install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_bgp_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd);
+  install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd);
+
+  /* Old commands.  */
+  install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* "show ip bgp paths" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_paths_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd);
+
+  /* "show ip bgp community" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd);
+
+  /* "show ip bgp attribute-info" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd);
+
+  /* "redistribute" commands.  */
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd);
+#ifdef HAVE_IPV6
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd);
+#endif /* HAVE_IPV6 */
+
+  /* Community-list. */
+  community_list_vty ();
+}
+\f
+#include "memory.h"
+#include "bgp_regex.h"
+#include "bgp_clist.h"
+#include "bgp_ecommunity.h"
+
+/* VTY functions.  */
+
+/* Direction value to string conversion.  */
+char *
+community_direct_str (int direct)
+{
+  switch (direct)
+    {
+    case COMMUNITY_DENY:
+      return "deny";
+      break;
+    case COMMUNITY_PERMIT:
+      return "permit";
+      break;
+    default:
+      return "unknown";
+      break;
+    }
+}
+
+/* Display error string.  */
+void
+community_list_perror (struct vty *vty, int ret)
+{
+  switch (ret)
+    {
+    case COMMUNITY_LIST_ERR_CANT_FIND_LIST:
+      vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE);
+      break;
+    case COMMUNITY_LIST_ERR_MALFORMED_VAL:
+      vty_out (vty, "%% Malformed community-list value%s", VTY_NEWLINE);
+      break;
+    case COMMUNITY_LIST_ERR_STANDARD_CONFLICT:
+      vty_out (vty, "%% Community name conflict, previously defined as standard community%s", VTY_NEWLINE);
+      break;
+    case COMMUNITY_LIST_ERR_EXPANDED_CONFLICT:
+      vty_out (vty, "%% Community name conflict, previously defined as expanded community%s", VTY_NEWLINE);
+      break;
+    }
+}
+
+/* VTY interface for community_set() function.  */
+int
+community_list_set_vty (struct vty *vty, int argc, char **argv, int style,
+                       int reject_all_digit_name)
+{
+  int ret;
+  int direct;
+  char *str;
+
+  /* Check the list type. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    direct = COMMUNITY_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    direct = COMMUNITY_DENY;
+  else
+    {
+      vty_out (vty, "%% Matching condition must be permit or deny%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* All digit name check.  */
+  if (reject_all_digit_name && all_digit (argv[0]))
+    {
+      vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Concat community string argument.  */
+  if (argc > 1)
+    str = argv_concat (argv, argc, 2);
+  else
+    str = NULL;
+
+  /* When community_list_set() return nevetive value, it means
+     malformed community string.  */
+  ret = community_list_set (bgp_clist, argv[0], str, direct, style);
+
+  /* Free temporary community list string allocated by
+     argv_concat().  */
+  if (str)
+    XFREE (MTYPE_TMP, str);
+
+  if (ret < 0)
+    {
+      /* Display error string.  */
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Community-list delete with name.  */
+int
+community_list_unset_all_vty (struct vty *vty, char *name)
+{
+  int ret;
+
+  ret = community_list_unset (bgp_clist, name, NULL, 0, COMMUNITY_LIST_AUTO);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+/* Communiyt-list entry delete.  */
+int
+community_list_unset_vty (struct vty *vty, int argc, char **argv, int style)
+{
+  int ret;
+  int direct;
+  char *str;
+
+  /* Check the list direct. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    direct = COMMUNITY_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    direct = COMMUNITY_DENY;
+  else
+    {
+      vty_out (vty, "%% Matching condition must be permit or deny%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Concat community string argument.  */
+  str = argv_concat (argv, argc, 2);
+
+  /* Unset community list.  */
+  ret = community_list_unset (bgp_clist, argv[0], str, direct, style);
+
+  /* Free temporary community list string allocated by
+     argv_concat().  */
+  XFREE (MTYPE_TMP, str);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* "community-list" keyword help string.  */
+#define COMMUNITY_LIST_STR "Add a community list entry\n"
+#define COMMUNITY_VAL_STR  "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n"
+
+DEFUN (ip_community_list,
+       ip_community_list_cmd,
+       "ip community-list WORD (deny|permit) .AA:NN",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       COMMUNITY_VAL_STR)
+{
+  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_AUTO, 1);
+}
+
+DEFUN (ip_community_list_standard,
+       ip_community_list_standard_cmd,
+       "ip community-list <1-99> (deny|permit) .AA:NN",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       COMMUNITY_VAL_STR)
+{
+  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 0);
+}
+
+ALIAS (ip_community_list_standard,
+       ip_community_list_standard2_cmd,
+       "ip community-list <1-99> (deny|permit)",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFUN (ip_community_list_expanded,
+       ip_community_list_expanded_cmd,
+       "ip community-list <100-199> (deny|permit) .LINE",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 0);
+}
+
+DEFUN (ip_community_list_name_standard,
+       ip_community_list_name_standard_cmd,
+       "ip community-list standard WORD (deny|permit) .AA:NN",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Add a standard community-list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       COMMUNITY_VAL_STR)
+{
+  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 1);
+}
+
+ALIAS (ip_community_list_name_standard,
+       ip_community_list_name_standard2_cmd,
+       "ip community-list standard WORD (deny|permit)",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Add a standard community-list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFUN (ip_community_list_name_expanded,
+       ip_community_list_name_expanded_cmd,
+       "ip community-list expanded WORD (deny|permit) .LINE",
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Add an expanded community-list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 1);
+}
+
+DEFUN (no_ip_community_list_all,
+       no_ip_community_list_all_cmd,
+       "no ip community-list (WORD|<1-99>|<100-199>)",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list name\n"
+       "Community list number (standard)\n"
+       "Community list number (expanded)\n")
+{
+  return community_list_unset_all_vty (vty, argv[0]);
+}
+
+DEFUN (no_ip_community_list_name_all,
+       no_ip_community_list_name_all_cmd,
+       "no ip community-list (standard|expanded) WORD",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Add a standard community-list entry\n"
+       "Add an expanded community-list entry\n"
+       "Community list name\n")
+{
+  return community_list_unset_all_vty (vty, argv[1]);
+}
+
+DEFUN (no_ip_community_list,
+       no_ip_community_list_cmd,
+       "no ip community-list WORD (deny|permit) .AA:NN",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       COMMUNITY_VAL_STR)
+{
+  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_AUTO);
+}
+
+DEFUN (no_ip_community_list_standard,
+       no_ip_community_list_standard_cmd,
+       "no ip community-list <1-99> (deny|permit) .AA:NN",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       COMMUNITY_VAL_STR)
+{
+  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_community_list_expanded,
+       no_ip_community_list_expanded_cmd,
+       "no ip community-list <100-199> (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_community_list_name_standard,
+       no_ip_community_list_name_standard_cmd,
+       "no ip community-list standard WORD (deny|permit) .AA:NN",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Specify a standard community-list\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       COMMUNITY_VAL_STR)
+{
+  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_community_list_name_expanded,
+       no_ip_community_list_name_expanded_cmd,
+       "no ip community-list expanded WORD (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       COMMUNITY_LIST_STR
+       "Specify an expanded community-list\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED);
+}
+
+void
+community_list_show (struct vty *vty, struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry == list->head)
+       {
+         if (all_digit (list->name))
+           vty_out (vty, "Community %s list %s%s",
+                    entry->style == COMMUNITY_LIST_STANDARD ?
+                    "standard" : "(expanded) access",
+                    list->name, VTY_NEWLINE);
+         else
+           vty_out (vty, "Named Community %s list %s%s",
+                    entry->style == COMMUNITY_LIST_STANDARD ?
+                    "standard" : "expanded",
+                    list->name, VTY_NEWLINE);
+       }
+      if (entry->any)
+       vty_out (vty, "    %s%s",
+                community_direct_str (entry->direct), VTY_NEWLINE);
+      else
+       vty_out (vty, "    %s %s%s",
+                community_direct_str (entry->direct),
+                entry->style == COMMUNITY_LIST_STANDARD
+                ? community_str (entry->u.com) : entry->config,
+                VTY_NEWLINE);
+    }
+}
+
+DEFUN (show_ip_community_list,
+       show_ip_community_list_cmd,
+       "show ip community-list",
+       SHOW_STR
+       IP_STR
+       "List community-list\n")
+{
+  struct community_list *list;
+  struct community_list_master *cm;
+
+  cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_AUTO);
+  if (! cm)
+    return CMD_SUCCESS;
+
+  for (list = cm->num.head; list; list = list->next)
+    community_list_show (vty, list);
+
+  for (list = cm->str.head; list; list = list->next)
+    community_list_show (vty, list);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_community_list_arg,
+       show_ip_community_list_arg_cmd,
+       "show ip community-list (<1-199>|WORD)",
+       SHOW_STR
+       IP_STR
+       "List community-list\n"
+       "Community-list number\n"
+       "Community-list name\n")
+{
+  struct community_list *list;
+
+  list = community_list_lookup (bgp_clist, argv[0], COMMUNITY_LIST_AUTO);
+  if (! list)
+    {
+      vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  community_list_show (vty, list);
+
+  return CMD_SUCCESS;
+}
+\f
+int
+extcommunity_list_set_vty (struct vty *vty, int argc, char **argv, int style,
+                          int reject_all_digit_name)
+{
+  int ret;
+  int direct;
+  char *str;
+
+  /* Check the list type. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    direct = COMMUNITY_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    direct = COMMUNITY_DENY;
+  else
+    {
+      vty_out (vty, "%% Matching condition must be permit or deny%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* All digit name check.  */
+  if (reject_all_digit_name && all_digit (argv[0]))
+    {
+      vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Concat community string argument.  */
+  if (argc > 1)
+    str = argv_concat (argv, argc, 2);
+  else
+    str = NULL;
+
+  ret = extcommunity_list_set (bgp_clist, argv[0], str, direct, style);
+
+  /* Free temporary community list string allocated by
+     argv_concat().  */
+  if (str)
+    XFREE (MTYPE_TMP, str);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+int
+extcommunity_list_unset_all_vty (struct vty *vty, char *name)
+{
+  int ret;
+
+  ret = extcommunity_list_unset (bgp_clist, name, NULL, 0, EXTCOMMUNITY_LIST_AUTO);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+int
+extcommunity_list_unset_vty (struct vty *vty, int argc, char **argv, int style)
+{
+  int ret;
+  int direct;
+  char *str;
+
+  /* Check the list direct. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    direct = COMMUNITY_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    direct = COMMUNITY_DENY;
+  else
+    {
+      vty_out (vty, "%% Matching condition must be permit or deny%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Concat community string argument.  */
+  str = argv_concat (argv, argc, 2);
+
+  /* Unset community list.  */
+  ret = extcommunity_list_unset (bgp_clist, argv[0], str, direct, style);
+
+  /* Free temporary community list string allocated by
+     argv_concat().  */
+  XFREE (MTYPE_TMP, str);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* "extcommunity-list" keyword help string.  */
+#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
+#define EXTCOMMUNITY_VAL_STR  "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
+
+DEFUN (ip_extcommunity_list_standard,
+       ip_extcommunity_list_standard_cmd,
+       "ip extcommunity-list <1-99> (deny|permit) .AA:NN",
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Extended Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       EXTCOMMUNITY_VAL_STR)
+{
+  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 0);
+}
+
+ALIAS (ip_extcommunity_list_standard,
+       ip_extcommunity_list_standard2_cmd,
+       "ip extcommunity-list <1-99> (deny|permit)",
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Extended Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFUN (ip_extcommunity_list_expanded,
+       ip_extcommunity_list_expanded_cmd,
+       "ip extcommunity-list <100-199> (deny|permit) .LINE",
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Extended Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 0);
+}
+
+DEFUN (ip_extcommunity_list_name_standard,
+       ip_extcommunity_list_name_standard_cmd,
+       "ip extcommunity-list standard WORD (deny|permit) .AA:NN",
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Specify standard extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       EXTCOMMUNITY_VAL_STR)
+{
+  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 1);
+}
+
+ALIAS (ip_extcommunity_list_name_standard,
+       ip_extcommunity_list_name_standard2_cmd,
+       "ip extcommunity-list standard WORD (deny|permit)",
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Specify standard extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFUN (ip_extcommunity_list_name_expanded,
+       ip_extcommunity_list_name_expanded_cmd,
+       "ip extcommunity-list expanded WORD (deny|permit) .LINE",
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Specify expanded extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 1);
+}
+
+DEFUN (no_ip_extcommunity_list_all,
+       no_ip_extcommunity_list_all_cmd,
+       "no ip extcommunity-list (<1-99>|<100-199>)",
+       NO_STR
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Extended Community list number (standard)\n"
+       "Extended Community list number (expanded)\n")
+{
+  return extcommunity_list_unset_all_vty (vty, argv[0]);
+}
+
+DEFUN (no_ip_extcommunity_list_name_all,
+       no_ip_extcommunity_list_name_all_cmd,
+       "no ip extcommunity-list (standard|expanded) WORD",
+       NO_STR
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Specify standard extcommunity-list\n"
+       "Specify expanded extcommunity-list\n"
+       "Extended Community list name\n")
+{
+  return extcommunity_list_unset_all_vty (vty, argv[1]);
+}
+
+DEFUN (no_ip_extcommunity_list_standard,
+       no_ip_extcommunity_list_standard_cmd,
+       "no ip extcommunity-list <1-99> (deny|permit) .AA:NN",
+       NO_STR
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Extended Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       EXTCOMMUNITY_VAL_STR)
+{
+  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_extcommunity_list_expanded,
+       no_ip_extcommunity_list_expanded_cmd,
+       "no ip extcommunity-list <100-199> (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Extended Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_extcommunity_list_name_standard,
+       no_ip_extcommunity_list_name_standard_cmd,
+       "no ip extcommunity-list standard WORD (deny|permit) .AA:NN",
+       NO_STR
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Specify standard extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       EXTCOMMUNITY_VAL_STR)
+{
+  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_extcommunity_list_name_expanded,
+       no_ip_extcommunity_list_name_expanded_cmd,
+       "no ip extcommunity-list expanded WORD (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       EXTCOMMUNITY_LIST_STR
+       "Specify expanded extcommunity-list\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED);
+}
+
+void
+extcommunity_list_show (struct vty *vty, struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry == list->head)
+       {
+         if (all_digit (list->name))
+           vty_out (vty, "Extended community %s list %s%s",
+                    entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+                    "standard" : "(expanded) access",
+                    list->name, VTY_NEWLINE);
+         else
+           vty_out (vty, "Named extended community %s list %s%s",
+                    entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+                    "standard" : "expanded",
+                    list->name, VTY_NEWLINE);
+       }
+      if (entry->any)
+       vty_out (vty, "    %s%s",
+                community_direct_str (entry->direct), VTY_NEWLINE);
+      else
+       vty_out (vty, "    %s %s%s",
+                community_direct_str (entry->direct),
+                entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+                entry->u.ecom->str : entry->config,
+                VTY_NEWLINE);
+    }
+}
+
+DEFUN (show_ip_extcommunity_list,
+       show_ip_extcommunity_list_cmd,
+       "show ip extcommunity-list",
+       SHOW_STR
+       IP_STR
+       "List extended-community list\n")
+{
+  struct community_list *list;
+  struct community_list_master *cm;
+
+  cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_AUTO);
+  if (! cm)
+    return CMD_SUCCESS;
+
+  for (list = cm->num.head; list; list = list->next)
+    extcommunity_list_show (vty, list);
+
+  for (list = cm->str.head; list; list = list->next)
+    extcommunity_list_show (vty, list);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_extcommunity_list_arg,
+       show_ip_extcommunity_list_arg_cmd,
+       "show ip extcommunity-list (<1-199>|WORD)",
+       SHOW_STR
+       IP_STR
+       "List extended-community list\n"
+       "Extcommunity-list number\n"
+       "Extcommunity-list name\n")
+{
+  struct community_list *list;
+
+  list = community_list_lookup (bgp_clist, argv[0], EXTCOMMUNITY_LIST_AUTO);
+  if (! list)
+    {
+      vty_out (vty, "%% Can't find extcommunit-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  extcommunity_list_show (vty, list);
+
+  return CMD_SUCCESS;
+}
+\f
+/* Return configuration string of community-list entry.  */
+static char *
+community_list_config_str (struct community_entry *entry)
+{
+  char *str;
+
+  if (entry->any)
+    str = "";
+  else
+    {
+      if (entry->style == COMMUNITY_LIST_STANDARD)
+       str = community_str (entry->u.com);
+      else
+       str = entry->config;
+    }
+  return str;
+}
+
+/* Display community-list and extcommunity-list configuration.  */
+int
+community_list_config_write (struct vty *vty)
+{
+  struct community_list *list;
+  struct community_entry *entry;
+  struct community_list_master *cm;
+  int write = 0;
+
+  /* Community-list.  */
+  cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_AUTO);
+
+  for (list = cm->num.head; list; list = list->next)
+    for (entry = list->head; entry; entry = entry->next)
+      {
+       if (atol (list->name) < 200)
+         vty_out (vty, "ip community-list %s %s %s%s",
+                  list->name, community_direct_str (entry->direct),
+                  community_list_config_str (entry),
+                  VTY_NEWLINE);
+       else
+         vty_out (vty, "ip community-list %s %s %s %s%s",
+                  entry->style == COMMUNITY_LIST_STANDARD
+                  ? "standard" : "expanded",
+                  list->name, community_direct_str (entry->direct),
+                  community_list_config_str (entry),
+                  VTY_NEWLINE);
+       write++;
+      }
+  for (list = cm->str.head; list; list = list->next)
+    for (entry = list->head; entry; entry = entry->next)
+      {
+       vty_out (vty, "ip community-list %s %s %s %s%s",
+                entry->style == COMMUNITY_LIST_STANDARD
+                ? "standard" : "expanded",
+                list->name, community_direct_str (entry->direct),
+                community_list_config_str (entry),
+                VTY_NEWLINE);
+       write++;
+      }
+
+  /* Extcommunity-list.  */
+  cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_AUTO);
+
+  for (list = cm->num.head; list; list = list->next)
+    for (entry = list->head; entry; entry = entry->next)
+      {
+       if (atol (list->name) < 200)
+         vty_out (vty, "ip extcommunity-list %s %s %s%s",
+                  list->name, community_direct_str (entry->direct),
+                  community_list_config_str (entry), VTY_NEWLINE);
+       else
+         vty_out (vty, "ip extcommunity-list %s %s %s %s%s",
+                  entry->style == EXTCOMMUNITY_LIST_STANDARD
+                  ? "standard" : "expanded",
+                  list->name, community_direct_str (entry->direct),
+                  community_list_config_str (entry), VTY_NEWLINE);
+       write++;
+      }
+  for (list = cm->str.head; list; list = list->next)
+    for (entry = list->head; entry; entry = entry->next)
+      {
+       vty_out (vty, "ip extcommunity-list %s %s %s %s%s",
+                entry->style == EXTCOMMUNITY_LIST_STANDARD
+                ? "standard" : "expanded",
+                list->name, community_direct_str (entry->direct),
+                community_list_config_str (entry), VTY_NEWLINE);
+       write++;
+      }
+  return write;
+}
+
+struct cmd_node community_list_node =
+{
+  COMMUNITY_LIST_NODE,
+  "",
+  1                            /* Export to vtysh.  */
+};
+
+void
+community_list_vty ()
+{
+  install_node (&community_list_node, community_list_config_write);
+
+  /* Community-list.  */
+  install_element (CONFIG_NODE, &ip_community_list_cmd);
+  install_element (CONFIG_NODE, &ip_community_list_standard_cmd);
+  install_element (CONFIG_NODE, &ip_community_list_standard2_cmd);
+  install_element (CONFIG_NODE, &ip_community_list_expanded_cmd);
+  install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd);
+  install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd);
+  install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_name_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd);
+  install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd);
+  install_element (VIEW_NODE, &show_ip_community_list_cmd);
+  install_element (VIEW_NODE, &show_ip_community_list_arg_cmd);
+  install_element (ENABLE_NODE, &show_ip_community_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd);
+
+  /* Extcommunity-list.  */
+  install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd);
+  install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
+  install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
+  install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd);
+}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
new file mode 100644 (file)
index 0000000..15ad581
--- /dev/null
@@ -0,0 +1,21 @@
+/* BGP VTY interface.
+   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+void bgp_vty_init ();
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
new file mode 100644 (file)
index 0000000..3e5cdd2
--- /dev/null
@@ -0,0 +1,1001 @@
+/* zebra client
+   Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "stream.h"
+#include "network.h"
+#include "prefix.h"
+#include "log.h"
+#include "sockunion.h"
+#include "zclient.h"
+#include "routemap.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_fsm.h"
+\f
+/* All information about zebra. */
+static struct zclient *zclient = NULL;
+
+/* Update default router id. */
+int
+bgp_if_update (struct interface *ifp)
+{
+  struct bgp *bgp;
+  listnode cn;
+  struct listnode *nn;
+  struct listnode *nm;
+  struct peer *peer;
+
+  for (cn = listhead (ifp->connected); cn; nextnode (cn))
+    {
+      struct connected *co;
+      struct in_addr addr;
+
+      co = getdata (cn);
+
+      if (co->address->family == AF_INET)
+       {
+         addr = co->address->u.prefix4;
+
+         /* Ignore NET127. */
+         if (IPV4_NET127 (ntohl (addr.s_addr)))
+           continue;
+
+         LIST_LOOP (bm->bgp, bgp, nn)
+           {
+             /* Respect configured router id */
+             if (! (bgp->config & BGP_CONFIG_ROUTER_ID))
+               if (ntohl (bgp->router_id.s_addr) < ntohl (addr.s_addr))
+                 {
+                   bgp->router_id = addr;
+                   LIST_LOOP (bgp->peer, peer, nm)
+                     {
+                       peer->local_id = addr;
+                     }
+                 }
+           }
+       }
+    }
+  return 0;
+}
+
+int
+bgp_if_update_all ()
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; node = nextnode (node))
+    {
+      ifp = getdata (node);
+      bgp_if_update (ifp);
+    }
+  return 0;
+}
+
+/* Inteface addition message from zebra. */
+int
+bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+  bgp_if_update (ifp);
+
+  return 0;
+}
+
+int
+bgp_interface_delete (int command, struct zclient *zclient,
+                     zebra_size_t length)
+{
+  struct stream *s;
+  struct interface *ifp;
+
+  s = zclient->ibuf;
+  ifp = zebra_interface_state_read (s);
+
+  return 0;
+}
+
+int
+bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct interface *ifp;
+  struct connected *c;
+  listnode node;
+
+  s = zclient->ibuf;
+  ifp = zebra_interface_state_read (s);
+
+  if (! ifp)
+    return 0;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      c = getdata (node);
+      bgp_connected_add (c);
+    }
+
+  return 0;
+}
+
+int
+bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct interface *ifp;
+  struct connected *c;
+  listnode node;
+
+  s = zclient->ibuf;
+  ifp = zebra_interface_state_read (s);
+  if (! ifp)
+    return 0;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      c = getdata (node);
+      bgp_connected_delete (c);
+    }
+
+  /* Fast external-failover (Currently IPv4 only) */
+  {
+    struct listnode *nn, *nm;
+    struct bgp *bgp;
+    struct peer *peer;
+    struct interface *peer_if;
+
+    LIST_LOOP (bm->bgp, bgp, nn)
+      {
+       if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+         continue;
+
+       LIST_LOOP (bgp->peer, peer, nm)
+         {
+           if (peer->ttl != 1)
+             continue;
+
+           if (peer->su.sa.sa_family == AF_INET)
+             peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr);
+           else
+             continue;
+
+           if (ifp == peer_if)
+             BGP_EVENT_ADD (peer, BGP_Stop);
+         }
+      }
+  }
+
+  return 0;
+}
+
+int
+bgp_interface_address_add (int command, struct zclient *zclient,
+                          zebra_size_t length)
+{
+  struct connected *ifc;
+
+  ifc = zebra_interface_address_add_read (zclient->ibuf);
+
+  if (ifc == NULL)
+    return 0;
+
+  bgp_if_update (ifc->ifp);
+
+  if (if_is_up (ifc->ifp))
+    bgp_connected_add (ifc);
+
+  return 0;
+}
+
+int
+bgp_interface_address_delete (int command, struct zclient *zclient,
+                             zebra_size_t length)
+{
+  struct connected *ifc;
+
+  ifc = zebra_interface_address_delete_read (zclient->ibuf);
+
+  if (ifc == NULL)
+    return 0;
+
+  bgp_if_update (ifc->ifp);
+
+  if (if_is_up (ifc->ifp))
+    bgp_connected_delete (ifc);
+
+  connected_free (ifc);
+
+  return 0;
+}
+
+/* Zebra route add and delete treatment. */
+int
+zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv4 api;
+  unsigned long ifindex;
+  struct in_addr nexthop;
+  struct prefix_ipv4 p;
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop.s_addr = 0;
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop.s_addr = stream_get_ipv4 (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+
+  if (command == ZEBRA_IPV4_ROUTE_ADD)
+    bgp_redistribute_add ((struct prefix *)&p, &nexthop, api.metric, api.type);
+  else
+    bgp_redistribute_delete ((struct prefix *)&p, api.type);
+
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+/* Zebra route add and delete treatment. */
+int
+zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv6 api;
+  unsigned long ifindex;
+  struct in6_addr nexthop;
+  struct prefix_ipv6 p;
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv6 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      stream_get (&nexthop, s, 16);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+
+  /* Simply ignore link-local address. */
+  if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
+    return 0;
+
+  if (command == ZEBRA_IPV6_ROUTE_ADD)
+    bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type);
+  else
+    bgp_redistribute_delete ((struct prefix *) &p, api.type);
+  
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+\f
+struct interface *
+if_lookup_by_ipv4 (struct in_addr *addr)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *connected;
+  struct prefix_ipv4 p;
+  struct prefix *cp; 
+  
+  p.family = AF_INET;
+  p.prefix = *addr;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         connected = getdata (cnode);
+         cp = connected->address;
+           
+         if (cp->family == AF_INET)
+           if (prefix_match (cp, (struct prefix *)&p))
+             return ifp;
+       }
+    }
+  return NULL;
+}
+
+struct interface *
+if_lookup_by_ipv4_exact (struct in_addr *addr)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *connected;
+  struct prefix *cp; 
+  
+  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         connected = getdata (cnode);
+         cp = connected->address;
+           
+         if (cp->family == AF_INET)
+           if (IPV4_ADDR_SAME (&cp->u.prefix4, addr))
+             return ifp;
+       }
+    }
+  return NULL;
+}
+
+#ifdef HAVE_IPV6
+struct interface *
+if_lookup_by_ipv6 (struct in6_addr *addr)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *connected;
+  struct prefix_ipv6 p;
+  struct prefix *cp; 
+  
+  p.family = AF_INET6;
+  p.prefix = *addr;
+  p.prefixlen = IPV6_MAX_BITLEN;
+
+  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         connected = getdata (cnode);
+         cp = connected->address;
+           
+         if (cp->family == AF_INET6)
+           if (prefix_match (cp, (struct prefix *)&p))
+             return ifp;
+       }
+    }
+  return NULL;
+}
+
+struct interface *
+if_lookup_by_ipv6_exact (struct in6_addr *addr)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *connected;
+  struct prefix *cp; 
+
+  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         connected = getdata (cnode);
+         cp = connected->address;
+           
+         if (cp->family == AF_INET6)
+           if (IPV6_ADDR_SAME (&cp->u.prefix6, addr))
+             return ifp;
+       }
+    }
+  return NULL;
+}
+
+int
+if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr)
+{
+  listnode cnode;
+  struct connected *connected;
+  struct prefix *cp; 
+  
+  for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+    {
+      connected = getdata (cnode);
+      cp = connected->address;
+           
+      if (cp->family == AF_INET6)
+       if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6))
+         {
+           memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
+           return 1;
+         }
+    }
+  return 0;
+}
+
+int
+if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr)
+{
+  listnode cnode;
+  struct connected *connected;
+  struct prefix *cp; 
+  
+  for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+    {
+      connected = getdata (cnode);
+      cp = connected->address;
+           
+      if (cp->family == AF_INET6)
+       if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6))
+         {
+           memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
+           return 1;
+         }
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+int
+bgp_nexthop_set (union sockunion *local, union sockunion *remote, 
+                struct bgp_nexthop *nexthop, struct peer *peer)
+{
+  int ret = 0;
+  struct interface *ifp = NULL;
+
+  memset (nexthop, 0, sizeof (struct bgp_nexthop));
+
+  if (!local)
+    return -1;
+  if (!remote)
+    return -1;
+
+  if (local->sa.sa_family == AF_INET)
+    {
+      nexthop->v4 = local->sin.sin_addr;
+      ifp = if_lookup_by_ipv4 (&local->sin.sin_addr);
+    }
+#ifdef HAVE_IPV6
+  if (local->sa.sa_family == AF_INET6)
+    {
+      if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
+       {
+         if (peer->ifname)
+           ifp = if_lookup_by_index (if_nametoindex (peer->ifname));
+       }
+      else
+       ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr);
+    }
+#endif /* HAVE_IPV6 */
+
+  if (!ifp)
+    return -1;
+
+  nexthop->ifp = ifp;
+
+  /* IPv4 connection. */
+  if (local->sa.sa_family == AF_INET)
+    {
+#ifdef HAVE_IPV6
+      /* IPv6 nexthop*/
+      ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
+
+      /* There is no global nexthop. */
+      if (!ret)
+       if_get_ipv6_local (ifp, &nexthop->v6_global);
+      else
+       if_get_ipv6_local (ifp, &nexthop->v6_local);
+#endif /* HAVE_IPV6 */
+    }
+
+#ifdef HAVE_IPV6
+  /* IPv6 connection. */
+  if (local->sa.sa_family == AF_INET6)
+    {
+      struct interface *direct = NULL;
+
+      /* IPv4 nexthop.  I don't care about it. */
+      if (peer->local_id.s_addr)
+       nexthop->v4 = peer->local_id;
+
+      /* Global address*/
+      if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
+       {
+         memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, 
+                 IPV6_MAX_BYTELEN);
+
+         /* If directory connected set link-local address. */
+         direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr);
+         if (direct)
+           if_get_ipv6_local (ifp, &nexthop->v6_local);
+       }
+      else
+       /* Link-local address. */
+       {
+         ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
+
+         /* If there is no global address.  Set link-local address as
+             global.  I know this break RFC specification... */
+         if (!ret)
+           memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, 
+                   IPV6_MAX_BYTELEN);
+         else
+           memcpy (&nexthop->v6_local, &local->sin6.sin6_addr, 
+                   IPV6_MAX_BYTELEN);
+       }
+    }
+
+  if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) ||
+      if_lookup_by_ipv6 (&remote->sin6.sin6_addr))
+    peer->shared_network = 1;
+  else
+    peer->shared_network = 0;
+
+  /* KAME stack specific treatment.  */
+#ifdef KAME
+  if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global)
+      && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global))
+    {
+      SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0);
+    }
+  if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local)
+      && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local))
+    {
+      SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0);
+    }
+#endif /* KAME */
+#endif /* HAVE_IPV6 */
+  return ret;
+}
+
+#ifdef HAVE_IPV6
+unsigned int
+bgp_ifindex_by_nexthop (struct in6_addr *addr)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *connected;
+  struct prefix_ipv6 p;
+  
+  p.family = AF_INET6;
+  p.prefix = *addr;
+  p.prefixlen = IPV6_MAX_BITLEN;
+
+  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         struct prefix *cp; 
+
+         connected = getdata (cnode);
+         cp = connected->address;
+           
+         if (cp->family == AF_INET6)
+           {
+             if (prefix_match (cp, (struct prefix *)&p))
+               return ifp->ifindex;
+           }
+       }
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+void
+bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
+{
+  int flags;
+  u_char distance;
+  struct peer *peer;
+
+  if (zclient->sock < 0)
+    return;
+
+  if (! zclient->redist[ZEBRA_ROUTE_BGP])
+    return;
+
+  flags = 0;
+  peer = info->peer;
+
+  if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
+    {
+      SET_FLAG (flags, ZEBRA_FLAG_IBGP);
+      SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
+    }
+
+  if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+      || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))
+    SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
+
+  if (p->family == AF_INET)
+    {
+      struct zapi_ipv4 api;
+      struct in_addr *nexthop;
+
+      api.flags = flags;
+      nexthop = &info->attr->nexthop;
+
+      api.type = ZEBRA_ROUTE_BGP;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      api.ifindex_num = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = info->attr->med;
+
+      distance = bgp_distance_apply (p, info, bgp);
+
+      if (distance)
+       {
+         SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+         api.distance = distance;
+       }
+      zapi_ipv4_add (zclient, (struct prefix_ipv4 *) p, &api);
+    }
+#ifdef HAVE_IPV6
+  /* We have to think about a IPv6 link-local address curse. */
+  if (p->family == AF_INET6)
+    {
+      unsigned int ifindex;
+      struct in6_addr *nexthop;
+      struct zapi_ipv6 api;
+
+      ifindex = 0;
+      nexthop = NULL;
+
+      /* Only global address nexthop exists. */
+      if (info->attr->mp_nexthop_len == 16)
+       nexthop = &info->attr->mp_nexthop_global;
+      
+      /* If both global and link-local address present. */
+      if (info->attr->mp_nexthop_len == 32)
+       {
+         /* Workaround for Cisco's nexthop bug.  */
+         if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->mp_nexthop_global)
+             && peer->su_remote->sa.sa_family == AF_INET6)
+           nexthop = &peer->su_remote->sin6.sin6_addr;
+         else
+           nexthop = &info->attr->mp_nexthop_local;
+
+         if (info->peer->nexthop.ifp)
+           ifindex = info->peer->nexthop.ifp->ifindex;
+       }
+
+      if (nexthop == NULL)
+       return;
+
+      if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
+       {
+         if (info->peer->ifname)
+           ifindex = if_nametoindex (info->peer->ifname);
+         else if (info->peer->nexthop.ifp)
+           ifindex = info->peer->nexthop.ifp->ifindex;
+       }
+
+      /* Make Zebra API structure. */
+      api.flags = flags;
+      api.type = ZEBRA_ROUTE_BGP;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+      api.ifindex_num = 1;
+      api.ifindex = &ifindex;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = info->attr->med;
+
+      zapi_ipv6_add (zclient, (struct prefix_ipv6 *) p, &api);
+    }
+#endif /* HAVE_IPV6 */
+}
+
+void
+bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
+{
+  int flags;
+  struct peer *peer;
+
+  if (zclient->sock < 0)
+    return;
+
+  if (! zclient->redist[ZEBRA_ROUTE_BGP])
+    return;
+
+  peer = info->peer;
+  flags = 0;
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    {
+      SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
+      SET_FLAG (flags, ZEBRA_FLAG_IBGP);
+    }
+
+  if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+      || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))
+    SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
+
+  if (p->family == AF_INET)
+    {
+      struct zapi_ipv4 api;
+      struct in_addr *nexthop;
+
+      api.flags = flags;
+      nexthop = &info->attr->nexthop;
+
+      api.type = ZEBRA_ROUTE_BGP;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      api.ifindex_num = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = info->attr->med;
+
+      zapi_ipv4_delete (zclient, (struct prefix_ipv4 *) p, &api);
+    }
+#ifdef HAVE_IPV6
+  /* We have to think about a IPv6 link-local address curse. */
+  if (p->family == AF_INET6)
+    {
+      struct zapi_ipv6 api;
+      unsigned int ifindex;
+      struct in6_addr *nexthop;
+
+      ifindex = 0;
+      nexthop = NULL;
+
+      /* Only global address nexthop exists. */
+      if (info->attr->mp_nexthop_len == 16)
+       nexthop = &info->attr->mp_nexthop_global;
+
+      /* If both global and link-local address present. */
+      if (info->attr->mp_nexthop_len == 32)
+       {
+         nexthop = &info->attr->mp_nexthop_local;
+         if (info->peer->nexthop.ifp)
+           ifindex = info->peer->nexthop.ifp->ifindex;
+       }
+
+      if (nexthop == NULL)
+       return;
+
+      if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
+       if (info->peer->ifname)
+         ifindex = if_nametoindex (info->peer->ifname);
+
+      api.flags = flags;
+      api.type = ZEBRA_ROUTE_BGP;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+      api.ifindex_num = 1;
+      api.ifindex = &ifindex;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = info->attr->med;
+
+      zapi_ipv6_delete (zclient, (struct prefix_ipv6 *) p, &api);
+    }
+#endif /* HAVE_IPV6 */
+}
+\f
+/* Other routes redistribution into BGP. */
+int
+bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type)
+{
+  /* Set flag to BGP instance. */
+  bgp->redist[afi][type] = 1;
+
+  /* Return if already redistribute flag is set. */
+  if (zclient->redist[type])
+    return CMD_WARNING;
+
+  zclient->redist[type] = 1;
+
+  /* Return if zebra connection is not established. */
+  if (zclient->sock < 0)
+    return CMD_WARNING;
+    
+  /* Send distribute add message to zebra. */
+  zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+
+  return CMD_SUCCESS;
+}
+
+/* Redistribute with route-map specification.  */
+int
+bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, char *name)
+{
+  if (bgp->rmap[afi][type].name
+      && (strcmp (bgp->rmap[afi][type].name, name) == 0))
+    return 0;
+
+  if (bgp->rmap[afi][type].name)
+    free (bgp->rmap[afi][type].name);
+  bgp->rmap[afi][type].name = strdup (name);
+  bgp->rmap[afi][type].map = route_map_lookup_by_name (name);
+
+  return 1;
+}
+
+/* Redistribute with metric specification.  */
+int
+bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type,
+                            u_int32_t metric)
+{
+  if (bgp->redist_metric_flag[afi][type]
+      && bgp->redist_metric[afi][type] == metric)
+    return 0;
+
+  bgp->redist_metric_flag[afi][type] = 1;
+  bgp->redist_metric[afi][type] = metric;
+
+  return 1;
+}
+
+/* Unset redistribution.  */
+int
+bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
+{
+  /* Unset flag from BGP instance. */
+  bgp->redist[afi][type] = 0;
+
+  /* Unset route-map. */
+  if (bgp->rmap[afi][type].name)
+    free (bgp->rmap[afi][type].name);
+  bgp->rmap[afi][type].name = NULL;
+  bgp->rmap[afi][type].map = NULL;
+
+  /* Unset metric. */
+  bgp->redist_metric_flag[afi][type] = 0;
+  bgp->redist_metric[afi][type] = 0;
+
+  /* Return if zebra connection is disabled. */
+  if (! zclient->redist[type])
+    return CMD_WARNING;
+  zclient->redist[type] = 0;
+
+  if (bgp->redist[AFI_IP][type] == 0 
+      && bgp->redist[AFI_IP6][type] == 0 
+      && zclient->sock >= 0)
+    /* Send distribute delete message to zebra. */
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+  
+  /* Withdraw redistributed routes from current BGP's routing table. */
+  bgp_redistribute_withdraw (bgp, afi, type);
+
+  return CMD_SUCCESS;
+}
+
+/* Unset redistribution route-map configuration.  */
+int
+bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type)
+{
+  if (! bgp->rmap[afi][type].name)
+    return 0;
+
+  /* Unset route-map. */
+  free (bgp->rmap[afi][type].name);
+  bgp->rmap[afi][type].name = NULL;
+  bgp->rmap[afi][type].map = NULL;
+
+  return 1;
+}
+
+/* Unset redistribution metric configuration.  */
+int
+bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type)
+{
+  if (! bgp->redist_metric_flag[afi][type])
+    return 0;
+
+  /* Unset metric. */
+  bgp->redist_metric_flag[afi][type] = 0;
+  bgp->redist_metric[afi][type] = 0;
+
+  return 1;
+}
+\f
+void
+bgp_zclient_reset ()
+{
+  zclient_reset (zclient);
+}
+
+void
+bgp_zebra_init (int enable)
+{
+  /* Set default values. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_BGP);
+  zclient->interface_add = bgp_interface_add;
+  zclient->interface_delete = bgp_interface_delete;
+  zclient->interface_address_add = bgp_interface_address_add;
+  zclient->interface_address_delete = bgp_interface_address_delete;
+  zclient->ipv4_route_add = zebra_read_ipv4;
+  zclient->ipv4_route_delete = zebra_read_ipv4;
+  zclient->interface_up = bgp_interface_up;
+  zclient->interface_down = bgp_interface_down;
+#ifdef HAVE_IPV6
+  zclient->ipv6_route_add = zebra_read_ipv6;
+  zclient->ipv6_route_delete = zebra_read_ipv6;
+#endif /* HAVE_IPV6 */
+
+  /* Interface related init. */
+  if_init ();
+}
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
new file mode 100644 (file)
index 0000000..1620c84
--- /dev/null
@@ -0,0 +1,39 @@
+/* zebra connection and redistribute fucntions.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+int bgp_if_update_all ();
+int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
+                                  int *);
+void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *);
+void bgp_zebra_withdraw (struct prefix *, struct bgp_info *);
+
+int bgp_redistribute_set (struct bgp *, afi_t, int);
+int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, char *);
+int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t);
+int bgp_redistribute_unset (struct bgp *, afi_t, int);
+int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int);
+int bgp_redistribute_metric_unset (struct bgp *, afi_t, int);
+
+struct interface *if_lookup_by_ipv4 (struct in_addr *);
+struct interface *if_lookup_by_ipv4_exact (struct in_addr *);
+#ifdef HAVE_IPV6
+struct interface *if_lookup_by_ipv6 (struct in6_addr *);
+struct interface *if_lookup_by_ipv6_exact (struct in6_addr *);
+#endif /* HAVE_IPV6 */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
new file mode 100644 (file)
index 0000000..f116a0c
--- /dev/null
@@ -0,0 +1,4601 @@
+/* BGP-4, BGP-4+ daemon program
+   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "thread.h"
+#include "buffer.h"
+#include "stream.h"
+#include "command.h"
+#include "sockunion.h"
+#include "network.h"
+#include "memory.h"
+#include "filter.h"
+#include "routemap.h"
+#include "str.h"
+#include "log.h"
+#include "plist.h"
+#include "linklist.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_vty.h"
+#ifdef HAVE_SNMP
+#include "bgpd/bgp_snmp.h"
+#endif /* HAVE_SNMP */
+\f
+/* BGP process wide configuration.  */
+static struct bgp_master bgp_master;
+
+/* BGP process wide configuration pointer to export.  */
+struct bgp_master *bm;
+
+/* BGP community-list.  */
+struct community_list_handler *bgp_clist;
+\f
+/* BGP global flag manipulation.  */
+int
+bgp_option_set (int flag)
+{
+  switch (flag)
+    {
+    case BGP_OPT_NO_FIB:
+    case BGP_OPT_MULTIPLE_INSTANCE:
+    case BGP_OPT_CONFIG_CISCO:
+      SET_FLAG (bm->options, flag);
+      break;
+    default:
+      return BGP_ERR_INVALID_FLAG;
+      break;
+    }
+  return 0;
+}
+
+int
+bgp_option_unset (int flag)
+{
+  switch (flag)
+    {
+    case BGP_OPT_MULTIPLE_INSTANCE:
+      if (listcount (bm->bgp) > 1)
+       return BGP_ERR_MULTIPLE_INSTANCE_USED;
+      /* Fall through.  */
+    case BGP_OPT_NO_FIB:
+    case BGP_OPT_CONFIG_CISCO:
+      UNSET_FLAG (bm->options, flag);
+      break;
+    default:
+      return BGP_ERR_INVALID_FLAG;
+      break;
+    }
+  return 0;
+}
+
+int
+bgp_option_check (int flag)
+{
+  return CHECK_FLAG (bm->options, flag);
+}
+\f
+/* BGP flag manipulation.  */
+int
+bgp_flag_set (struct bgp *bgp, int flag)
+{
+  SET_FLAG (bgp->flags, flag);
+  return 0;
+}
+
+int
+bgp_flag_unset (struct bgp *bgp, int flag)
+{
+  UNSET_FLAG (bgp->flags, flag);
+  return 0;
+}
+
+int
+bgp_flag_check (struct bgp *bgp, int flag)
+{
+  return CHECK_FLAG (bgp->flags, flag);
+}
+\f
+/* Internal function to set BGP structure configureation flag.  */
+static void
+bgp_config_set (struct bgp *bgp, int config)
+{
+  SET_FLAG (bgp->config, config);
+}
+
+static void
+bgp_config_unset (struct bgp *bgp, int config)
+{
+  UNSET_FLAG (bgp->config, config);
+}
+
+static int
+bgp_config_check (struct bgp *bgp, int config)
+{
+  return CHECK_FLAG (bgp->config, config);
+}
+\f
+/* Set BGP router identifier. */
+int
+bgp_router_id_set (struct bgp *bgp, struct in_addr *id)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID)
+      && IPV4_ADDR_SAME (&bgp->router_id, id))
+    return 0;
+
+  IPV4_ADDR_COPY (&bgp->router_id, id);
+  bgp_config_set (bgp, BGP_CONFIG_ROUTER_ID);
+
+  /* Set all peer's local identifier with this value. */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      IPV4_ADDR_COPY (&peer->local_id, id);
+
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+    }
+  return 0;
+}
+
+/* Unset BGP router identifier. */
+int
+bgp_router_id_unset (struct bgp *bgp)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (! bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID))
+    return 0;
+
+  bgp->router_id.s_addr = 0;
+  bgp_config_unset (bgp, BGP_CONFIG_ROUTER_ID);
+
+  /* Clear peer router id configuration.  */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      peer->local_id.s_addr = 0;
+    }
+
+  /* Set router-id from interface's address. */
+  bgp_if_update_all ();
+
+  /* Reset all BGP sessions to use new router-id.  */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+    }
+
+  return 0;
+}
+\f
+/* BGP's cluster-id control. */
+int
+bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID)
+      && IPV4_ADDR_SAME (&bgp->cluster_id, cluster_id))
+    return 0;
+
+  IPV4_ADDR_COPY (&bgp->cluster_id, cluster_id);
+  bgp_config_set (bgp, BGP_CONFIG_CLUSTER_ID);
+
+  /* Clear all IBGP peer. */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer_sort (peer) != BGP_PEER_IBGP)
+       continue;
+
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+    }
+  return 0;
+}
+
+int
+bgp_cluster_id_unset (struct bgp *bgp)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (! bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID))
+    return 0;
+
+  bgp->cluster_id.s_addr = 0;
+  bgp_config_unset (bgp, BGP_CONFIG_CLUSTER_ID);
+
+  /* Clear all IBGP peer. */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer_sort (peer) != BGP_PEER_IBGP)
+       continue;
+
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+    }
+  return 0;
+}
+\f
+/* BGP timer configuration.  */
+int
+bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime)
+{
+  bgp->default_keepalive = (keepalive < holdtime / 3 
+                           ? keepalive : holdtime / 3);
+  bgp->default_holdtime = holdtime;
+
+  return 0;
+}
+
+int
+bgp_timers_unset (struct bgp *bgp)
+{
+  bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
+  bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
+
+  return 0;
+}
+\f
+/* BGP confederation configuration.  */
+int
+bgp_confederation_id_set (struct bgp *bgp, as_t as)
+{
+  struct peer *peer;
+  struct listnode *nn;
+  int already_confed;
+
+  if (as == 0)
+    return BGP_ERR_INVALID_AS;
+
+  /* Remember - were we doing confederation before? */
+  already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION);
+  bgp->confed_id = as;
+  bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION);
+
+  /* If we were doing confederation already, this is just an external
+     AS change.  Just Reset EBGP sessions, not CONFED sessions.  If we
+     were not doing confederation before, reset all EBGP sessions.  */
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      /* We're looking for peers who's AS is not local or part of our
+        confederation.  */
+      if (already_confed)
+       {
+         if (peer_sort (peer) == BGP_PEER_EBGP)
+           {
+             peer->local_as = as;
+             if (peer->status == Established)
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+             else
+               BGP_EVENT_ADD (peer, BGP_Stop);
+           }
+       }
+      else
+       {
+         /* Not doign confederation before, so reset every non-local
+            session */
+         if (peer_sort (peer) != BGP_PEER_IBGP)
+           {
+             /* Reset the local_as to be our EBGP one */
+             if (peer_sort (peer) == BGP_PEER_EBGP)
+               peer->local_as = as;
+             if (peer->status == Established)
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+             else
+               BGP_EVENT_ADD (peer, BGP_Stop);
+           }
+       }
+    }
+  return 0;
+}
+
+int
+bgp_confederation_id_unset (struct bgp *bgp)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  bgp->confed_id = 0;
+  bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION);
+      
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      /* We're looking for peers who's AS is not local */
+      if (peer_sort (peer) != BGP_PEER_IBGP)
+       {
+         peer->local_as = bgp->as;
+         if (peer->status == Established)
+           bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                            BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+         else
+           BGP_EVENT_ADD (peer, BGP_Stop);
+       }
+    }
+  return 0;
+}
+
+/* Is an AS part of the confed or not? */
+int
+bgp_confederation_peers_check (struct bgp *bgp, as_t as)
+{
+  int i;
+
+  if (! bgp)
+    return 0;
+
+  for (i = 0; i < bgp->confed_peers_cnt; i++)
+    if (bgp->confed_peers[i] == as)
+      return 1;
+  
+  return 0;
+}
+
+/* Add an AS to the confederation set.  */
+int
+bgp_confederation_peers_add (struct bgp *bgp, as_t as)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (! bgp)
+    return BGP_ERR_INVALID_BGP;
+
+  if (bgp->as == as)
+    return BGP_ERR_INVALID_AS;
+
+  if (bgp_confederation_peers_check (bgp, as))
+    return -1;
+
+  if (bgp->confed_peers)
+    bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, 
+                                 bgp->confed_peers,
+                                 (bgp->confed_peers_cnt + 1) * sizeof (as_t));
+  else
+    bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST, 
+                                (bgp->confed_peers_cnt + 1) * sizeof (as_t));
+
+  bgp->confed_peers[bgp->confed_peers_cnt] = as;
+  bgp->confed_peers_cnt++;
+
+  if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION))
+    {
+      LIST_LOOP (bgp->peer, peer, nn)
+       {
+         if (peer->as == as)
+           {
+             peer->local_as = bgp->as;
+             if (peer->status == Established)
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+             else
+               BGP_EVENT_ADD (peer, BGP_Stop);
+           }
+       }
+    }
+  return 0;
+}
+
+/* Delete an AS from the confederation set.  */
+int
+bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
+{
+  int i;
+  int j;
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (! bgp)
+    return -1;
+
+  if (! bgp_confederation_peers_check (bgp, as))
+    return -1;
+
+  for (i = 0; i < bgp->confed_peers_cnt; i++)
+    if (bgp->confed_peers[i] == as)
+      for(j = i + 1; j < bgp->confed_peers_cnt; j++)
+       bgp->confed_peers[j - 1] = bgp->confed_peers[j];
+
+  bgp->confed_peers_cnt--;
+
+  if (bgp->confed_peers_cnt == 0)
+    {
+      if (bgp->confed_peers)
+       XFREE (MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
+      bgp->confed_peers = NULL;
+    }
+  else
+    bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST,
+                                 bgp->confed_peers,
+                                 bgp->confed_peers_cnt * sizeof (as_t));
+
+  /* Now reset any peer who's remote AS has just been removed from the
+     CONFED */
+  if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION))
+    {
+      LIST_LOOP (bgp->peer, peer, nn)
+       {
+         if (peer->as == as)
+           {
+             peer->local_as = bgp->confed_id;
+             if (peer->status == Established)
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+             else
+               BGP_EVENT_ADD (peer, BGP_Stop);
+           }
+       }
+    }
+
+  return 0;
+}
+\f
+/* Local preference configuration.  */
+int
+bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref)
+{
+  if (! bgp)
+    return -1;
+
+  bgp_config_set (bgp, BGP_CONFIG_DEFAULT_LOCAL_PREF);
+  bgp->default_local_pref = local_pref;
+
+  return 0;
+}
+
+int
+bgp_default_local_preference_unset (struct bgp *bgp)
+{
+  if (! bgp)
+    return -1;
+
+  bgp_config_unset (bgp, BGP_CONFIG_DEFAULT_LOCAL_PREF);
+  bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
+
+  return 0;
+}
+\f
+/* Peer comparison function for sorting.  */
+static int
+peer_cmp (struct peer *p1, struct peer *p2)
+{
+  return sockunion_cmp (&p1->su, &p2->su);
+}
+
+int
+peer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+{
+  return CHECK_FLAG (peer->af_flags[afi][safi], flag);
+}
+
+/* Reset all address family specific configuration.  */
+static void
+peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
+{
+  int i;
+  struct bgp_filter *filter;
+  char orf_name[BUFSIZ];
+
+  filter = &peer->filter[afi][safi];
+
+  /* Clear neighbor filter and route-map */
+  for (i = FILTER_IN; i < FILTER_MAX; i++)
+    {
+      if (filter->dlist[i].name)
+       {
+         free (filter->dlist[i].name);
+         filter->dlist[i].name = NULL;
+       }
+      if (filter->plist[i].name)
+       {
+         free (filter->plist[i].name);
+         filter->plist[i].name = NULL; 
+       }
+      if (filter->aslist[i].name)
+       {
+         free (filter->aslist[i].name);
+         filter->aslist[i].name = NULL;
+       }
+      if (filter->map[i].name)
+       {
+         free (filter->map[i].name);
+         filter->map[i].name = NULL;
+       }
+    }
+
+  /* Clear unsuppress map.  */
+  if (filter->usmap.name)
+    free (filter->usmap.name);
+  filter->usmap.name = NULL;
+  filter->usmap.map = NULL;
+
+  /* Clear neighbor's all address family flags.  */
+  peer->af_flags[afi][safi] = 0;
+
+  /* Clear neighbor's all address family sflags. */
+  peer->af_sflags[afi][safi] = 0;
+
+  /* Clear neighbor's all address family capabilities. */
+  peer->af_cap[afi][safi] = 0;
+
+  /* Clear ORF info */
+  peer->orf_plist[afi][safi] = NULL;
+  sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
+  prefix_bgp_orf_remove_all (orf_name);
+
+  /* Set default neighbor send-community.  */
+  if (! bgp_option_check (BGP_OPT_CONFIG_CISCO))
+    {
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+    }
+
+  /* Clear neighbor default_originate_rmap */
+  if (peer->default_rmap[afi][safi].name)
+    free (peer->default_rmap[afi][safi].name);
+  peer->default_rmap[afi][safi].name = NULL;
+  peer->default_rmap[afi][safi].map = NULL;
+
+  /* Clear neighbor maximum-prefix */
+  peer->pmax[afi][safi] = 0;
+}
+
+/* peer global config reset */
+void
+peer_global_config_reset (struct peer *peer)
+{
+  peer->weight = 0;
+  peer->change_local_as = 0;
+  peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1);
+  if (peer->update_source)
+    {
+      sockunion_free (peer->update_source);
+      peer->update_source = NULL;
+    }
+  if (peer->update_if)
+    {
+      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+      peer->update_if = NULL;
+    }
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+  else
+    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+  peer->flags = 0;
+  peer->config = 0;
+  peer->holdtime = 0;
+  peer->keepalive = 0;
+  peer->connect = 0;
+  peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+}
+
+/* Check peer's AS number and determin is this peer IBGP or EBGP */
+int
+peer_sort (struct peer *peer)
+{
+  struct bgp *bgp;
+
+  bgp = peer->bgp;
+
+  /* Peer-group */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->as)
+       return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+      else
+       {
+         struct peer *peer1;
+         peer1 = listnode_head (peer->group->peer);
+         if (peer1)
+           return (peer1->local_as == peer1->as 
+                   ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+       } 
+      return BGP_PEER_INTERNAL;
+    }
+
+  /* Normal peer */
+  if (bgp && CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
+    {
+      if (peer->local_as == 0)
+       return BGP_PEER_INTERNAL;
+
+      if (peer->local_as == peer->as)
+       {
+         if (peer->local_as == bgp->confed_id)
+           return BGP_PEER_EBGP;
+         else
+           return BGP_PEER_IBGP;
+       }
+
+      if (bgp_confederation_peers_check (bgp, peer->as))
+       return BGP_PEER_CONFED;
+
+      return BGP_PEER_EBGP;
+    }
+  else
+    {
+      return (peer->local_as == 0
+             ? BGP_PEER_INTERNAL : peer->local_as == peer->as
+             ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+    }
+}
+
+/* Allocate new peer object.  */
+static struct peer *
+peer_new ()
+{
+  afi_t afi;
+  safi_t safi;
+  struct peer *peer;
+  struct servent *sp;
+
+  /* Allocate new peer. */
+  peer = XMALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
+  memset (peer, 0, sizeof (struct peer));
+
+  /* Set default value. */
+  peer->fd = -1;
+  peer->v_start = BGP_INIT_START_TIMER;
+  peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+  peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
+  peer->status = Idle;
+  peer->ostatus = Idle;
+  peer->version = BGP_VERSION_4;
+  peer->weight = 0;
+
+  /* Set default flags.  */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       if (! bgp_option_check (BGP_OPT_CONFIG_CISCO))
+         {
+           SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
+           SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+         }
+       peer->orf_plist[afi][safi] = NULL;
+      }
+  SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+
+  /* Create buffers.  */
+  peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE);
+  peer->obuf = stream_fifo_new ();
+  peer->work = stream_new (BGP_MAX_PACKET_SIZE);
+
+  bgp_sync_init (peer);
+
+  /* Get service port number.  */
+  sp = getservbyname ("bgp", "tcp");
+  peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port);
+
+  return peer;
+}
+
+/* Create new BGP peer.  */
+struct peer *
+peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
+            as_t remote_as, afi_t afi, safi_t safi)
+{
+  int active;
+  struct peer *peer;
+  char buf[SU_ADDRSTRLEN];
+
+  peer = peer_new ();
+  peer->bgp = bgp;
+  peer->su = *su;
+  peer->local_as = local_as;
+  peer->as = remote_as;
+  peer->local_id = bgp->router_id;
+  peer->v_holdtime = bgp->default_holdtime;
+  peer->v_keepalive = bgp->default_keepalive;
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+  else
+    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+  listnode_add_sort (bgp->peer, peer);
+
+  active = peer_active (peer);
+
+  if (afi && safi)
+    peer->afc[afi][safi] = 1;
+
+  /* Last read time set */
+  peer->readtime = time (NULL);
+
+  /* Default TTL set. */
+  peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1);
+
+  /* Make peer's address string. */
+  sockunion2str (su, buf, SU_ADDRSTRLEN);
+  peer->host = strdup (buf);
+
+  /* Set up peer's events and timers. */
+  if (! active && peer_active (peer))
+    bgp_timer_set (peer);
+
+  return peer;
+}
+
+/* Make accept BGP peer.  Called from bgp_accept (). */
+struct peer *
+peer_create_accept (struct bgp *bgp)
+{
+  struct peer *peer;
+
+  peer = peer_new ();
+  peer->bgp = bgp;
+  listnode_add_sort (bgp->peer, peer);
+
+  return peer;
+}
+
+/* Change peer's AS number.  */
+void
+peer_as_change (struct peer *peer, as_t as)
+{
+  int type;
+
+  /* Stop peer. */
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+  type = peer_sort (peer);
+  peer->as = as;
+
+  /* Advertisement-interval reset */
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+  else
+    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+  /* TTL reset */
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    peer->ttl = 255;
+  else if (type == BGP_PEER_IBGP)
+    peer->ttl = 1;
+
+  /* reflector-client reset */
+  if (peer_sort (peer) != BGP_PEER_IBGP)
+    {
+      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST],
+                 PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
+                 PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
+                 PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST],
+                 PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST],
+                 PEER_FLAG_REFLECTOR_CLIENT);
+    }
+
+  /* local-as reset */
+  if (peer_sort (peer) != BGP_PEER_EBGP)
+    {
+      peer->change_local_as = 0;
+      UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+    }
+}
+
+/* If peer does not exist, create new one.  If peer already exists,
+   set AS number to the peer.  */
+int
+peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
+               afi_t afi, safi_t safi)
+{
+  struct peer *peer;
+  as_t local_as;
+
+  peer = peer_lookup (bgp, su);
+
+  if (peer)
+    {
+      /* When this peer is a member of peer-group.  */
+      if (peer->group)
+       {
+         if (peer->group->conf->as)
+           {
+             /* Return peer group's AS number.  */
+             *as = peer->group->conf->as;
+             return BGP_ERR_PEER_GROUP_MEMBER;
+           }
+         if (peer_sort (peer->group->conf) == BGP_PEER_IBGP)
+           {
+             if (bgp->as != *as)
+               {
+                 *as = peer->as;
+                 return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+               }
+           }
+         else
+           {
+             if (bgp->as == *as)
+               {
+                 *as = peer->as;
+                 return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+               }
+           }
+       }
+
+      /* Existing peer's AS number change. */
+      if (peer->as != *as)
+       peer_as_change (peer, *as);
+    }
+  else
+    {
+
+      /* If the peer is not part of our confederation, and its not an
+        iBGP peer then spoof the source AS */
+      if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)
+         && ! bgp_confederation_peers_check (bgp, *as) 
+         && bgp->as != *as)
+       local_as = bgp->confed_id;
+      else
+       local_as = bgp->as;
+      
+      /* If this is IPv4 unicast configuration and "no bgp default
+         ipv4-unicast" is specified. */
+
+      if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
+         && afi == AFI_IP && safi == SAFI_UNICAST)
+       peer = peer_create (su, bgp, local_as, *as, 0, 0); 
+      else
+       peer = peer_create (su, bgp, local_as, *as, afi, safi); 
+    }
+
+  return 0;
+}
+
+/* Activate the peer or peer group for specified AFI and SAFI.  */
+int
+peer_activate (struct peer *peer, afi_t afi, safi_t safi)
+{
+  int active;
+
+  if (peer->afc[afi][safi])
+    return 0;
+
+  /* Activate the address family configuration. */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    peer->afc[afi][safi] = 1;
+  else
+    {
+      active = peer_active (peer);
+
+      peer->afc[afi][safi] = 1;
+
+      if (! active && peer_active (peer))
+       bgp_timer_set (peer);
+      else
+       {
+         if (peer->status == Established)
+           {
+             if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
+               {
+                 peer->afc_adv[afi][safi] = 1;
+                 bgp_capability_send (peer, afi, safi,
+                                      CAPABILITY_CODE_MP,
+                                      CAPABILITY_ACTION_SET);
+                 if (peer->afc_recv[afi][safi])
+                   {
+                     peer->afc_nego[afi][safi] = 1;
+                     bgp_announce_route (peer, afi, safi);
+                   }
+               }
+             else
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+           }
+       }
+    }
+  return 0;
+}
+
+int
+peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct peer_group *group;
+  struct peer *peer1;
+  struct listnode *nn;
+
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      group = peer->group;
+
+      LIST_LOOP (group->peer, peer1, nn)
+       {
+         if (peer1->af_group[afi][safi])
+           return BGP_ERR_PEER_GROUP_MEMBER_EXISTS;
+       }
+    }
+  else
+    {
+      if (peer->af_group[afi][safi])
+       return BGP_ERR_PEER_BELONGS_TO_GROUP;
+    }
+
+  if (! peer->afc[afi][safi])
+    return 0;
+
+  /* De-activate the address family configuration. */
+  peer->afc[afi][safi] = 0;
+  peer_af_flag_reset (peer, afi, safi);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {  
+      if (peer->status == Established)
+       {
+         if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
+           {
+             peer->afc_adv[afi][safi] = 0;
+             peer->afc_nego[afi][safi] = 0;
+
+             if (peer_active_nego (peer))
+               {
+                 bgp_capability_send (peer, afi, safi,
+                                      CAPABILITY_CODE_MP,
+                                      CAPABILITY_ACTION_UNSET);
+                 bgp_clear_route (peer, afi, safi);
+                 peer->pcount[afi][safi] = 0;
+               }
+             else
+               bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+           }
+         else
+           bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                            BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+       }
+    }
+  return 0;
+}
+
+/* Delete peer from confguration. */
+int
+peer_delete (struct peer *peer)
+{
+  int i;
+  afi_t afi;
+  safi_t safi;
+  struct bgp *bgp;
+  struct bgp_filter *filter;
+
+  bgp = peer->bgp;
+
+  /* If this peer belongs to peer group.  Clearn up the
+     relationship.  */
+  if (peer->group)
+    {
+      listnode_delete (peer->group->peer, peer);
+      peer->group = NULL;
+    }
+
+  /* Withdraw all information from routing table.  We can not use
+     BGP_EVENT_ADD (peer, BGP_Stop) at here.  Because the event is
+     executed after peer structure is deleted. */
+  bgp_stop (peer);
+  bgp_fsm_change_status (peer, Idle);
+
+  /* Stop all timers. */
+  BGP_TIMER_OFF (peer->t_start);
+  BGP_TIMER_OFF (peer->t_connect);
+  BGP_TIMER_OFF (peer->t_holdtime);
+  BGP_TIMER_OFF (peer->t_keepalive);
+  BGP_TIMER_OFF (peer->t_asorig);
+  BGP_TIMER_OFF (peer->t_routeadv);
+
+  /* Delete from all peer list. */
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    listnode_delete (bgp->peer, peer);
+
+  /* Buffer.  */
+  if (peer->ibuf)
+    stream_free (peer->ibuf);
+
+  if (peer->obuf)
+    stream_fifo_free (peer->obuf);
+
+  if (peer->work)
+    stream_free (peer->work);
+
+  /* Free allocated host character. */
+  if (peer->host)
+    free (peer->host);
+
+  /* Local and remote addresses. */
+  if (peer->su_local)
+    XFREE (MTYPE_TMP, peer->su_local);
+  if (peer->su_remote)
+    XFREE (MTYPE_TMP, peer->su_remote);
+
+  /* Peer description string.  */
+  if (peer->desc)
+    XFREE (MTYPE_TMP, peer->desc);
+
+  bgp_sync_delete (peer);
+
+  /* Free filter related memory.  */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       filter = &peer->filter[afi][safi];
+
+       for (i = FILTER_IN; i < FILTER_MAX; i++)
+         {
+           if (filter->dlist[i].name)
+             free (filter->dlist[i].name);
+           if (filter->plist[i].name)
+             free (filter->plist[i].name);
+           if (filter->aslist[i].name)
+             free (filter->aslist[i].name);
+           if (filter->map[i].name)
+             free (filter->map[i].name);
+         }
+
+       if (filter->usmap.name)
+         free (filter->usmap.name);
+
+       if (peer->default_rmap[afi][safi].name)
+         free (peer->default_rmap[afi][safi].name);
+      }
+
+  /* Update source configuration.  */
+  if (peer->update_source)
+    {
+      sockunion_free (peer->update_source);
+      peer->update_source = NULL;
+    }
+  if (peer->update_if)
+    {
+      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+      peer->update_if = NULL;
+    }
+
+  /* Free peer structure. */
+  XFREE (MTYPE_BGP_PEER, peer);
+
+  return 0;
+}
+\f
+int
+peer_group_cmp (struct peer_group *g1, struct peer_group *g2)
+{
+  return strcmp (g1->name, g2->name);
+}
+
+/* If peer is configured at least one address family return 1. */
+int
+peer_group_active (struct peer *peer)
+{
+  if (peer->af_group[AFI_IP][SAFI_UNICAST]
+      || peer->af_group[AFI_IP][SAFI_MULTICAST]
+      || peer->af_group[AFI_IP][SAFI_MPLS_VPN]
+      || peer->af_group[AFI_IP6][SAFI_UNICAST]
+      || peer->af_group[AFI_IP6][SAFI_MULTICAST])
+    return 1;
+  return 0;
+}
+
+/* Peer group cofiguration. */
+static struct peer_group *
+peer_group_new ()
+{
+  return (struct peer_group *) XCALLOC (MTYPE_PEER_GROUP,
+                                       sizeof (struct peer_group));
+}
+
+void
+peer_group_free (struct peer_group *group)
+{
+  XFREE (MTYPE_PEER_GROUP, group);
+}
+
+struct peer_group *
+peer_group_lookup (struct bgp *bgp, char *name)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  LIST_LOOP (bgp->group, group, nn)
+    {
+      if (strcmp (group->name, name) == 0)
+       return group;
+    }
+  return NULL;
+}
+
+struct peer_group *
+peer_group_get (struct bgp *bgp, char *name)
+{
+  struct peer_group *group;
+
+  group = peer_group_lookup (bgp, name);
+  if (group)
+    return group;
+
+  group = peer_group_new ();
+  group->bgp = bgp;
+  group->name = strdup (name);
+  group->peer = list_new ();
+  group->conf = peer_new ();
+  if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
+    group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
+  group->conf->host = strdup (name);
+  group->conf->bgp = bgp;
+  group->conf->group = group;
+  group->conf->as = 0; 
+  group->conf->ttl = 1;
+  group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+  UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER);
+  UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT);
+  group->conf->keepalive = 0;
+  group->conf->holdtime = 0;
+  group->conf->connect = 0;
+  SET_FLAG (group->conf->sflags, PEER_STATUS_GROUP);
+  listnode_add_sort (bgp->group, group);
+
+  return 0;
+}
+
+void 
+peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
+                            afi_t afi, safi_t safi)
+{
+  int in = FILTER_IN;
+  int out = FILTER_OUT;
+  struct peer *conf;
+  struct bgp_filter *pfilter;
+  struct bgp_filter *gfilter;
+
+  conf = group->conf;
+  pfilter = &peer->filter[afi][safi];
+  gfilter = &conf->filter[afi][safi];
+
+  /* remote-as */
+  if (conf->as)
+    peer->as = conf->as;
+
+  /* remote-as */
+  if (conf->change_local_as)
+    peer->change_local_as = conf->change_local_as;
+
+  /* TTL */
+  peer->ttl = conf->ttl;
+
+  /* Weight */
+  peer->weight = conf->weight;
+
+  /* peer flags apply */
+  peer->flags = conf->flags;
+  /* peer af_flags apply */
+  peer->af_flags[afi][safi] = conf->af_flags[afi][safi];
+  /* peer config apply */
+  peer->config = conf->config;
+
+  /* peer timers apply */
+  peer->holdtime = conf->holdtime;
+  peer->keepalive = conf->keepalive;
+  peer->connect = conf->connect;
+  if (CHECK_FLAG (conf->config, PEER_CONFIG_CONNECT))
+    peer->v_connect = conf->connect;
+  else
+    peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+
+  /* advertisement-interval reset */
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+  else
+    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+  /* maximum-prefix */
+  peer->pmax[afi][safi] = conf->pmax[afi][safi];
+
+  /* allowas-in */
+  peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi];
+
+  /* default-originate route-map */
+  if (conf->default_rmap[afi][safi].name)
+    {
+      if (peer->default_rmap[afi][safi].name)
+       free (peer->default_rmap[afi][safi].name);
+      peer->default_rmap[afi][safi].name = strdup (conf->default_rmap[afi][safi].name);
+      peer->default_rmap[afi][safi].map = conf->default_rmap[afi][safi].map;
+    }
+
+  /* update-source apply */
+  if (conf->update_source)
+    {
+      if (peer->update_source)
+       sockunion_free (peer->update_source);
+      if (peer->update_if)
+       {
+         XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+         peer->update_if = NULL;
+       }
+      peer->update_source = sockunion_dup (conf->update_source);
+    }
+  else if (conf->update_if)
+    {
+      if (peer->update_if)
+       XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+      if (peer->update_source)
+       {
+         sockunion_free (peer->update_source);
+         peer->update_source = NULL;
+       }
+      peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, conf->update_if);
+    }
+
+  /* inbound filter apply */
+  if (gfilter->dlist[in].name && ! pfilter->dlist[in].name)
+    {
+      if (pfilter->dlist[in].name)
+       free (pfilter->dlist[in].name);
+      pfilter->dlist[in].name = strdup (gfilter->dlist[in].name);
+      pfilter->dlist[in].alist = gfilter->dlist[in].alist;
+    }
+  if (gfilter->plist[in].name && ! pfilter->plist[in].name)
+    {
+      if (pfilter->plist[in].name)
+       free (pfilter->plist[in].name);
+      pfilter->plist[in].name = strdup (gfilter->plist[in].name);
+      pfilter->plist[in].plist = gfilter->plist[in].plist;
+    }
+  if (gfilter->aslist[in].name && ! pfilter->aslist[in].name)
+    {
+      if (pfilter->aslist[in].name)
+       free (pfilter->aslist[in].name);
+      pfilter->aslist[in].name = strdup (gfilter->aslist[in].name);
+      pfilter->aslist[in].aslist = gfilter->aslist[in].aslist;
+    }
+  if (gfilter->map[in].name && ! pfilter->map[in].name)
+    {
+      if (pfilter->map[in].name)
+       free (pfilter->map[in].name);
+      pfilter->map[in].name = strdup (gfilter->map[in].name);
+      pfilter->map[in].map = gfilter->map[in].map;
+    }
+
+  /* outbound filter apply */
+  if (gfilter->dlist[out].name)
+    {
+      if (pfilter->dlist[out].name)
+       free (pfilter->dlist[out].name);
+      pfilter->dlist[out].name = strdup (gfilter->dlist[out].name);
+      pfilter->dlist[out].alist = gfilter->dlist[out].alist;
+    }
+  else
+    {
+      if (pfilter->dlist[out].name)
+       free (pfilter->dlist[out].name);
+      pfilter->dlist[out].name = NULL;
+      pfilter->dlist[out].alist = NULL;
+    }
+  if (gfilter->plist[out].name)
+    {
+      if (pfilter->plist[out].name)
+       free (pfilter->plist[out].name);
+      pfilter->plist[out].name = strdup (gfilter->plist[out].name);
+      pfilter->plist[out].plist = gfilter->plist[out].plist;
+    }
+  else
+    {
+      if (pfilter->plist[out].name)
+       free (pfilter->plist[out].name);
+      pfilter->plist[out].name = NULL;
+      pfilter->plist[out].plist = NULL;
+    }
+  if (gfilter->aslist[out].name)
+    {
+      if (pfilter->aslist[out].name)
+       free (pfilter->aslist[out].name);
+      pfilter->aslist[out].name = strdup (gfilter->aslist[out].name);
+      pfilter->aslist[out].aslist = gfilter->aslist[out].aslist;
+    }
+  else
+    {
+      if (pfilter->aslist[out].name)
+       free (pfilter->aslist[out].name);
+      pfilter->aslist[out].name = NULL;
+      pfilter->aslist[out].aslist = NULL;
+    }
+  if (gfilter->map[out].name)
+    {
+      if (pfilter->map[out].name)
+       free (pfilter->map[out].name);
+      pfilter->map[out].name = strdup (gfilter->map[out].name);
+      pfilter->map[out].map = gfilter->map[out].map;
+    }
+  else
+    {
+      if (pfilter->map[out].name)
+       free (pfilter->map[out].name);
+      pfilter->map[out].name = NULL;
+      pfilter->map[out].map = NULL;
+    }
+
+  if (gfilter->usmap.name)
+    {
+      if (pfilter->usmap.name)
+       free (pfilter->usmap.name);
+      pfilter->usmap.name = strdup (gfilter->usmap.name);
+      pfilter->usmap.map = gfilter->usmap.map;
+    }
+  else
+    {
+      if (pfilter->usmap.name)
+       free (pfilter->usmap.name);
+      pfilter->usmap.name = NULL;
+      pfilter->usmap.map = NULL;
+    }
+} 
+
+/* Peer group's remote AS configuration.  */
+int
+peer_group_remote_as (struct bgp *bgp, char *group_name, as_t *as)
+{
+  struct peer_group *group;
+  struct peer *peer;
+  struct listnode *nn;
+
+  group = peer_group_lookup (bgp, group_name);
+  if (! group)
+    return -1;
+
+  if (group->conf->as == *as)
+    return 0;
+
+  /* When we setup peer-group AS number all peer group member's AS
+     number must be updated to same number.  */
+  peer_as_change (group->conf, *as);
+
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (peer->as != *as)
+       peer_as_change (peer, *as);
+    }
+
+  return 0;
+}
+
+int
+peer_group_delete (struct peer_group *group)
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  struct listnode *nn;
+
+  bgp = group->bgp;
+
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      peer->group = NULL;
+      peer_delete (peer);
+    }
+  list_delete (group->peer);
+
+  free (group->name);
+  group->name = NULL;
+
+  group->conf->group = NULL;
+  peer_delete (group->conf);
+
+  /* Delete from all peer_group list. */
+  listnode_delete (bgp->group, group);
+
+  peer_group_free (group);
+
+  return 0;
+}
+
+int
+peer_group_remote_as_delete (struct peer_group *group)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (! group->conf->as)
+    return 0;
+
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      peer->group = NULL;
+      peer_delete (peer);
+    }
+  list_delete_all_node (group->peer);
+
+  group->conf->as = 0;
+
+  return 0;
+}
+
+/* Bind specified peer to peer group.  */
+int
+peer_group_bind (struct bgp *bgp, union sockunion *su,
+                struct peer_group *group, afi_t afi, safi_t safi, as_t *as)
+{
+  struct peer *peer;
+  int first_member = 0;
+
+  /* Check peer group's address family.  */
+  if (! group->conf->afc[afi][safi])
+    return BGP_ERR_PEER_GROUP_AF_UNCONFIGURED;
+
+  /* Lookup the peer.  */
+  peer = peer_lookup (bgp, su);
+
+  /* Create a new peer. */
+  if (! peer)
+    {
+      if (! group->conf->as)
+       return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
+
+      peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
+      peer->group = group;
+      peer->af_group[afi][safi] = 1;
+      listnode_add (group->peer, peer);
+      peer_group2peer_config_copy (group, peer, afi, safi);
+
+      return 0;
+    }
+
+  /* When the peer already belongs to peer group, check the consistency.  */
+  if (peer->af_group[afi][safi])
+    {
+      if (strcmp (peer->group->name, group->name) != 0)
+       return BGP_ERR_PEER_GROUP_CANT_CHANGE;
+
+      return 0;
+    }
+
+  /* Check current peer group configuration.  */
+  if (peer_group_active (peer)
+      && strcmp (peer->group->name, group->name) != 0)
+    return BGP_ERR_PEER_GROUP_MISMATCH;
+
+  if (! group->conf->as)
+    {
+      if (peer_sort (group->conf) != BGP_PEER_INTERNAL
+         && peer_sort (group->conf) != peer_sort (peer))
+       {
+         if (as)
+           *as = peer->as;
+         return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+       }
+
+      if (peer_sort (group->conf) == BGP_PEER_INTERNAL)
+       first_member = 1;
+    }
+
+  peer->af_group[afi][safi] = 1;
+  peer->afc[afi][safi] = 1;
+  if (! peer->group)
+    {
+      peer->group = group;
+      listnode_add (group->peer, peer);
+    }
+
+  if (first_member)
+    {
+      /* Advertisement-interval reset */
+      if (peer_sort (group->conf) == BGP_PEER_IBGP)
+       group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+      else
+       group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+      /* ebgp-multihop reset */
+      if (peer_sort (group->conf) == BGP_PEER_IBGP)
+       group->conf->ttl = 255;
+
+      /* local-as reset */
+      if (peer_sort (group->conf) != BGP_PEER_EBGP)
+       {
+         group->conf->change_local_as = 0;
+         UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+       }
+    }
+  peer_group2peer_config_copy (group, peer, afi, safi);
+
+  if (peer->status == Established)
+    bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                    BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+  else
+    BGP_EVENT_ADD (peer, BGP_Stop);
+
+  return 0;
+}
+
+int
+peer_group_unbind (struct bgp *bgp, struct peer *peer,
+                  struct peer_group *group, afi_t afi, safi_t safi)
+{
+  if (! peer->af_group[afi][safi])
+      return 0;
+
+  if (group != peer->group)
+    return BGP_ERR_PEER_GROUP_MISMATCH;
+
+  peer->af_group[afi][safi] = 0;
+  peer->afc[afi][safi] = 0;
+  peer_af_flag_reset (peer, afi, safi);
+
+  if (! peer_group_active (peer))
+    {
+      listnode_delete (group->peer, peer);
+      peer->group = NULL;
+      if (group->conf->as)
+       {
+         peer_delete (peer);
+         return 0;
+       }
+      peer_global_config_reset (peer);
+    }
+
+  if (peer->status == Established)
+    bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                    BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+  else
+    BGP_EVENT_ADD (peer, BGP_Stop);
+
+  return 0;
+}
+\f
+/* BGP instance creation by `router bgp' commands. */
+struct bgp *
+bgp_create (as_t *as, char *name)
+{
+  struct bgp *bgp;
+  afi_t afi;
+  safi_t safi;
+
+  bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp));
+
+  bgp->peer_self = peer_new ();
+  bgp->peer_self->host = "Static announcement";
+
+  bgp->peer = list_new ();
+  bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
+
+  bgp->group = list_new ();
+  bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       bgp->route[afi][safi] = bgp_table_init ();
+       bgp->aggregate[afi][safi] = bgp_table_init ();
+       bgp->rib[afi][safi] = bgp_table_init ();
+      }
+
+  bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
+  bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
+  bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
+
+  bgp->as = *as;
+
+  if (name)
+    bgp->name = strdup (name);
+
+  return bgp;
+}
+
+/* Return first entry of BGP. */
+struct bgp *
+bgp_get_default ()
+{
+  if (bm->bgp->head)
+    return bm->bgp->head->data;
+  return NULL;
+}
+
+/* Lookup BGP entry. */
+struct bgp *
+bgp_lookup (as_t as, char *name)
+{
+  struct bgp *bgp;
+  struct listnode *nn;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    if (bgp->as == as
+       && ((bgp->name == NULL && name == NULL) 
+           || (bgp->name && name && strcmp (bgp->name, name) == 0)))
+      return bgp;
+  return NULL;
+}
+
+/* Lookup BGP structure by view name. */
+struct bgp *
+bgp_lookup_by_name (char *name)
+{
+  struct bgp *bgp;
+  struct listnode *nn;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    if ((bgp->name == NULL && name == NULL)
+       || (bgp->name && name && strcmp (bgp->name, name) == 0))
+      return bgp;
+  return NULL;
+}
+
+/* Called from VTY commands. */
+int
+bgp_get (struct bgp **bgp_val, as_t *as, char *name)
+{
+  struct bgp *bgp;
+
+  /* Multiple instance check. */
+  if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
+    {
+      if (name)
+       bgp = bgp_lookup_by_name (name);
+      else
+       bgp = bgp_get_default ();
+
+      /* Already exists. */
+      if (bgp)
+       {
+          if (bgp->as != *as)
+           {
+             *as = bgp->as;
+             return BGP_ERR_INSTANCE_MISMATCH;
+           }
+         *bgp_val = bgp;
+         return 0;
+       }
+    }
+  else
+    {
+      /* BGP instance name can not be specified for single instance.  */
+      if (name)
+       return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET;
+
+      /* Get default BGP structure if exists. */
+      bgp = bgp_get_default ();
+
+      if (bgp)
+       {
+         if (bgp->as != *as)
+           {
+             *as = bgp->as;
+             return BGP_ERR_AS_MISMATCH;
+           }
+         *bgp_val = bgp;
+         return 0;
+       }
+    }
+
+  bgp = bgp_create (as, name);
+  listnode_add (bm->bgp, bgp);
+  bgp_if_update_all ();
+  *bgp_val = bgp;
+
+  return 0;
+}
+
+/* Delete BGP instance. */
+int
+bgp_delete (struct bgp *bgp)
+{
+  struct peer *peer;
+  struct listnode *nn;
+  struct listnode *next;
+  afi_t afi;
+  safi_t safi;
+  int i;
+
+  /* Delete static route. */
+  bgp_static_delete (bgp);
+
+  /* Unset redistribution. */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
+      if (i != ZEBRA_ROUTE_BGP)
+       bgp_redistribute_unset (bgp, afi, i);
+
+  bgp->group->del = (void (*)(void *)) peer_group_delete;
+  list_delete (bgp->group);
+
+  for (nn = bgp->peer->head; nn; nn = next)
+    {
+      peer = nn->data;
+      next = nn->next;
+      peer_delete (peer);
+    }
+
+  listnode_delete (bm->bgp, bgp);
+
+  if (bgp->name)
+    free (bgp->name);
+  
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+       if (bgp->route[afi][safi])
+         XFREE (MTYPE_ROUTE_TABLE, bgp->route[afi][safi]);
+       if (bgp->aggregate[afi][safi])
+         XFREE (MTYPE_ROUTE_TABLE,bgp->aggregate[afi][safi]) ;
+       if (bgp->rib[afi][safi])
+         XFREE (MTYPE_ROUTE_TABLE,bgp->rib[afi][safi]);
+      }
+  XFREE (MTYPE_BGP, bgp);
+
+  return 0;
+}
+\f
+struct peer *
+peer_lookup (struct bgp *bgp, union sockunion *su)
+{
+  struct peer *peer;
+  struct listnode *nn;
+
+  if (! bgp)
+    bgp = bgp_get_default ();
+
+  if (! bgp)
+    return NULL;
+  
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (sockunion_same (&peer->su, su)
+         && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+       return peer;
+    }
+  return NULL;
+}
+
+struct peer *
+peer_lookup_with_open (union sockunion *su, as_t remote_as,
+                      struct in_addr *remote_id, int *as)
+{
+  struct peer *peer;
+  struct listnode *nn;
+  struct bgp *bgp;
+
+  bgp = bgp_get_default ();
+  if (! bgp)
+    return NULL;
+
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (sockunion_same (&peer->su, su)
+         && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+       {
+         if (peer->as == remote_as
+             && peer->remote_id.s_addr == remote_id->s_addr)
+           return peer;
+         if (peer->as == remote_as)
+           *as = 1;
+       }
+    }
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (sockunion_same (&peer->su, su)
+         &&  ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+       {
+         if (peer->as == remote_as
+             && peer->remote_id.s_addr == 0)
+           return peer;
+         if (peer->as == remote_as)
+           *as = 1;
+       }
+    }
+  return NULL;
+}
+\f
+/* If peer is configured at least one address family return 1. */
+int
+peer_active (struct peer *peer)
+{
+  if (peer->afc[AFI_IP][SAFI_UNICAST]
+      || peer->afc[AFI_IP][SAFI_MULTICAST]
+      || peer->afc[AFI_IP][SAFI_MPLS_VPN]
+      || peer->afc[AFI_IP6][SAFI_UNICAST]
+      || peer->afc[AFI_IP6][SAFI_MULTICAST])
+    return 1;
+  return 0;
+}
+
+/* If peer is negotiated at least one address family return 1. */
+int
+peer_active_nego (struct peer *peer)
+{
+  if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
+      || peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+      || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
+      || peer->afc_nego[AFI_IP6][SAFI_UNICAST]
+      || peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
+    return 1;
+  return 0;
+}
+\f
+/* peer_flag_change_type. */
+enum peer_change_type
+{
+  peer_change_none,
+  peer_change_reset,
+  peer_change_reset_in,
+  peer_change_reset_out,
+};
+
+void
+peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
+                   enum peer_change_type type)
+{
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return;
+
+  if (type == peer_change_reset)
+    bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                    BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+  else if (type == peer_change_reset_in)
+    {
+      if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+         || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+       bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+      else
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+    }
+  else if (type == peer_change_reset_out)
+    bgp_announce_route (peer, afi, safi);
+}
+
+struct peer_flag_action
+{
+  /* Peer's flag.  */
+  u_int32_t flag;
+
+  /* This flag can be set for peer-group member.  */
+  u_char not_for_member;
+
+  /* Action when the flag is changed.  */
+  enum peer_change_type type;
+};
+
+struct peer_flag_action peer_flag_action_list[] = 
+  {
+    { PEER_FLAG_PASSIVE,                  0, peer_change_reset },
+    { PEER_FLAG_SHUTDOWN,                 0, peer_change_reset },
+    { PEER_FLAG_DONT_CAPABILITY,          0, peer_change_none },
+    { PEER_FLAG_OVERRIDE_CAPABILITY,      0, peer_change_none },
+    { PEER_FLAG_STRICT_CAP_MATCH,         0, peer_change_none },
+    { PEER_FLAG_NO_ROUTE_REFRESH_CAP,     0, peer_change_reset },
+    { PEER_FLAG_DYNAMIC_CAPABILITY,       0, peer_change_reset },
+    { PEER_FLAG_ENFORCE_MULTIHOP,         0, peer_change_reset },
+    { 0, 0, 0 }
+  };
+
+struct peer_flag_action peer_af_flag_action_list[] = 
+  {
+    { PEER_FLAG_NEXTHOP_SELF,             1, peer_change_reset_out },
+    { PEER_FLAG_SEND_COMMUNITY,           1, peer_change_reset_out },
+    { PEER_FLAG_SEND_EXT_COMMUNITY,       1, peer_change_reset_out },
+    { PEER_FLAG_SOFT_RECONFIG,            0, peer_change_reset_in },
+    { PEER_FLAG_REFLECTOR_CLIENT,         1, peer_change_reset },
+    { PEER_FLAG_RSERVER_CLIENT,           1, peer_change_reset },
+    { PEER_FLAG_AS_PATH_UNCHANGED,        1, peer_change_reset_out },
+    { PEER_FLAG_NEXTHOP_UNCHANGED,        1, peer_change_reset_out },
+    { PEER_FLAG_MED_UNCHANGED,            1, peer_change_reset_out },
+    { PEER_FLAG_REMOVE_PRIVATE_AS,        1, peer_change_reset_out },
+    { PEER_FLAG_ALLOWAS_IN,               0, peer_change_reset_in },
+    { PEER_FLAG_ORF_PREFIX_SM,            1, peer_change_reset },
+    { PEER_FLAG_ORF_PREFIX_RM,            1, peer_change_reset },
+    { 0, 0, 0 }
+  };
+
+/* Proper action set. */
+int
+peer_flag_action_set (struct peer_flag_action *action_list, int size,
+                     struct peer_flag_action *action, u_int32_t flag)
+{
+  int i;
+  int found = 0;
+  int reset_in = 0;
+  int reset_out = 0;
+  struct peer_flag_action *match = NULL;
+
+  /* Check peer's frag action.  */
+  for (i = 0; i < size; i++)
+    {
+      match = &action_list[i];
+
+      if (match->flag == 0)
+       break;
+
+      if (match->flag & flag)
+       {
+         found = 1;
+
+         if (match->type == peer_change_reset_in)
+           reset_in = 1;
+         if (match->type == peer_change_reset_out)
+           reset_out = 1;
+         if (match->type == peer_change_reset)
+           {
+             reset_in = 1;
+             reset_out = 1;
+           }
+         if (match->not_for_member)
+           action->not_for_member = 1;
+       }
+    }
+
+  /* Set peer clear type.  */
+  if (reset_in && reset_out)
+    action->type = peer_change_reset;
+  else if (reset_in)
+    action->type = peer_change_reset_in;
+  else if (reset_out)
+    action->type = peer_change_reset_out;
+  else
+    action->type = peer_change_none;
+
+  return found;
+}
+
+void
+peer_flag_modify_action (struct peer *peer, u_int32_t flag)
+{
+  if (flag == PEER_FLAG_SHUTDOWN)
+    {
+      if (CHECK_FLAG (peer->flags, flag))
+       {
+         if (peer->status == Established)
+           bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                            BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
+         else
+           BGP_EVENT_ADD (peer, BGP_Stop);
+       }
+      else
+       {
+         peer->v_start = BGP_INIT_START_TIMER;
+         BGP_EVENT_ADD (peer, BGP_Stop);
+       }
+    }
+  else if (peer->status == Established)
+    {
+      if (flag == PEER_FLAG_NO_ROUTE_REFRESH_CAP
+         && CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
+       {
+         if (CHECK_FLAG (peer->flags, flag))
+           UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
+         else
+           SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
+
+         bgp_capability_send (peer, AFI_IP, SAFI_UNICAST,
+                              CAPABILITY_CODE_REFRESH,
+                              CHECK_FLAG (peer->flags, flag) ?
+                              CAPABILITY_ACTION_UNSET : CAPABILITY_ACTION_SET);
+       }
+      else
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+    }
+  else
+    BGP_EVENT_ADD (peer, BGP_Stop);
+}
+
+/* Change specified peer flag. */
+int
+peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
+{
+  int found;
+  int size;
+  struct peer_group *group;
+  struct listnode *nn;
+  struct peer_flag_action action;
+
+  memset (&action, 0, sizeof (struct peer_flag_action));
+  size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action);
+
+  found = peer_flag_action_set (peer_flag_action_list, size, &action, flag);
+
+  /* No flag action is found.  */
+  if (! found)
+    return BGP_ERR_INVALID_FLAG;    
+
+  /* Not for peer-group member.  */
+  if (action.not_for_member && peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  /* When unset the peer-group member's flag we have to check
+     peer-group configuration.  */
+  if (! set && peer_group_active (peer))
+    if (CHECK_FLAG (peer->group->conf->flags, flag))
+      {
+       if (flag == PEER_FLAG_SHUTDOWN)
+         return BGP_ERR_PEER_GROUP_SHUTDOWN;
+       else
+         return BGP_ERR_PEER_GROUP_HAS_THE_FLAG;
+      }
+
+  /* Flag conflict check.  */
+  if (set
+      && CHECK_FLAG (peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH)
+      && CHECK_FLAG (peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY))
+    return BGP_ERR_PEER_FLAG_CONFLICT;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (set && CHECK_FLAG (peer->flags, flag) == flag)
+       return 0;
+      if (! set && ! CHECK_FLAG (peer->flags, flag))
+       return 0;
+    }
+
+  if (set)
+    SET_FLAG (peer->flags, flag);
+  else
+    UNSET_FLAG (peer->flags, flag);
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (action.type == peer_change_reset)
+       peer_flag_modify_action (peer, flag);
+
+      return 0;
+    }
+
+  /* peer-group member updates. */
+  group = peer->group;
+
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (set && CHECK_FLAG (peer->flags, flag) == flag)
+       continue;
+
+      if (! set && ! CHECK_FLAG (peer->flags, flag))
+       continue;
+
+      if (set)
+       SET_FLAG (peer->flags, flag);
+      else
+       UNSET_FLAG (peer->flags, flag);
+
+      if (action.type == peer_change_reset)
+       peer_flag_modify_action (peer, flag);
+    }
+  return 0;
+}
+
+int
+peer_flag_set (struct peer *peer, u_int32_t flag)
+{
+  return peer_flag_modify (peer, flag, 1);
+}
+
+int
+peer_flag_unset (struct peer *peer, u_int32_t flag)
+{
+  return peer_flag_modify (peer, flag, 0);
+}
+
+int
+peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi)
+{
+  if (peer->af_group[afi][safi])
+    return 1;
+  return 0;
+}
+
+int
+peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
+                    int set)
+{
+  int found;
+  int size;
+  struct listnode *nn;
+  struct peer_group *group;
+  struct peer_flag_action action;
+
+  memset (&action, 0, sizeof (struct peer_flag_action));
+  size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action);
+  
+  found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag);
+  
+  /* No flag action is found.  */
+  if (! found)
+    return BGP_ERR_INVALID_FLAG;    
+
+  /* Adress family must be activated.  */
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  /* Not for peer-group member.  */
+  if (action.not_for_member && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+ /* Spcecial check for reflector client.  */
+  if (flag & PEER_FLAG_REFLECTOR_CLIENT
+      && peer_sort (peer) != BGP_PEER_IBGP)
+    return BGP_ERR_NOT_INTERNAL_PEER;
+
+  /* Spcecial check for remove-private-AS.  */
+  if (flag & PEER_FLAG_REMOVE_PRIVATE_AS
+      && peer_sort (peer) == BGP_PEER_IBGP)
+    return BGP_ERR_REMOVE_PRIVATE_AS;
+
+  /* When unset the peer-group member's flag we have to check
+     peer-group configuration.  */
+  if (! set && peer->af_group[afi][safi])
+    if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], flag))
+      return BGP_ERR_PEER_GROUP_HAS_THE_FLAG;
+
+  /* When current flag configuration is same as requested one.  */
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+       return 0;
+      if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
+       return 0;
+    }
+
+  if (set)
+    SET_FLAG (peer->af_flags[afi][safi], flag);
+  else
+    UNSET_FLAG (peer->af_flags[afi][safi], flag);
+
+  /* Execute action when peer is established.  */
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
+      && peer->status == Established)
+    {
+      if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
+       bgp_clear_adj_in (peer, afi, safi);
+      else
+       peer_change_action (peer, afi, safi, action.type);
+    }
+
+  /* Peer group member updates.  */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      group = peer->group;
+      
+      LIST_LOOP (group->peer, peer, nn)
+       {
+         if (! peer->af_group[afi][safi])
+           continue;
+
+         if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+           continue;
+
+         if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
+           continue;
+
+         if (set)
+           SET_FLAG (peer->af_flags[afi][safi], flag);
+         else
+           UNSET_FLAG (peer->af_flags[afi][safi], flag);
+
+         if (peer->status == Established)
+           {
+             if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
+               bgp_clear_adj_in (peer, afi, safi);
+             else
+               peer_change_action (peer, afi, safi, action.type);
+           }
+       }
+    }
+  return 0;
+}
+
+int
+peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+{
+  return peer_af_flag_modify (peer, afi, safi, flag, 1);
+}
+
+int
+peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+{
+  return peer_af_flag_modify (peer, afi, safi, flag, 0);
+}
+\f
+/* EBGP multihop configuration. */
+int
+peer_ebgp_multihop_set (struct peer *peer, int ttl)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    return 0;
+
+  peer->ttl = ttl;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
+       sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
+    }
+  else
+    {
+      group = peer->group;
+      LIST_LOOP (group->peer, peer, nn)
+       {
+         if (peer_sort (peer) == BGP_PEER_IBGP)
+           continue;
+
+         peer->ttl = group->conf->ttl;
+
+         if (peer->fd >= 0)
+           sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
+       }
+    }
+  return 0;
+}
+
+int
+peer_ebgp_multihop_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    return 0;
+
+  if (peer_group_active (peer))
+    peer->ttl = peer->group->conf->ttl;
+  else
+    peer->ttl = 1;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
+       sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
+    }
+  else
+    {
+      group = peer->group;
+      LIST_LOOP (group->peer, peer, nn)
+       {
+         if (peer_sort (peer) == BGP_PEER_IBGP)
+           continue;
+
+         peer->ttl = 1;
+         
+         if (peer->fd >= 0)
+           sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
+       }
+    }
+  return 0;
+}
+\f
+/* Neighbor description. */
+int
+peer_description_set (struct peer *peer, char *desc)
+{
+  if (peer->desc)
+    XFREE (MTYPE_PEER_DESC, peer->desc);
+
+  peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc);
+
+  return 0;
+}
+
+int
+peer_description_unset (struct peer *peer)
+{
+  if (peer->desc)
+    XFREE (MTYPE_PEER_DESC, peer->desc);
+
+  peer->desc = NULL;
+
+  return 0;
+}
+\f
+/* Neighbor update-source. */
+int
+peer_update_source_if_set (struct peer *peer, char *ifname)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer->update_if)
+    {
+      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
+         && strcmp (peer->update_if, ifname) == 0)
+       return 0;
+
+      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+      peer->update_if = NULL;
+    }
+
+  if (peer->update_source)
+    {
+      sockunion_free (peer->update_source);
+      peer->update_source = NULL;
+    }
+
+  peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+      return 0;
+    }
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (peer->update_if)
+       {
+         if (strcmp (peer->update_if, ifname) == 0)
+           continue;
+
+         XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+         peer->update_if = NULL;
+       }
+
+      if (peer->update_source)
+       {
+         sockunion_free (peer->update_source);
+         peer->update_source = NULL;
+       }
+
+      peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname);
+
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+  return 0;
+}
+
+int
+peer_update_source_addr_set (struct peer *peer, union sockunion *su)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer->update_source)
+    {
+      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
+         && sockunion_cmp (peer->update_source, su) == 0)
+       return 0;
+      sockunion_free (peer->update_source);
+      peer->update_source = NULL;
+    }
+
+  if (peer->update_if)
+    {
+      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+      peer->update_if = NULL;
+    }
+
+  peer->update_source = sockunion_dup (su);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+      return 0;
+    }
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (peer->update_source)
+       {
+         if (sockunion_cmp (peer->update_source, su) == 0)
+           continue;
+         sockunion_free (peer->update_source);
+         peer->update_source = NULL;
+       }
+
+      if (peer->update_if)
+       {
+         XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+         peer->update_if = NULL;
+       }
+
+      peer->update_source = sockunion_dup (su);
+
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+  return 0;
+}
+
+int
+peer_update_source_unset (struct peer *peer)
+{
+  union sockunion *su;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
+      && ! peer->update_source
+      && ! peer->update_if)
+    return 0;
+
+  if (peer->update_source)
+    {
+      sockunion_free (peer->update_source);
+      peer->update_source = NULL;
+    }
+  if (peer->update_if)
+    {
+      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+      peer->update_if = NULL;
+    }
+
+  if (peer_group_active (peer))
+    {
+      group = peer->group;
+
+      if (group->conf->update_source)
+       {
+         su = sockunion_dup (group->conf->update_source);
+         peer->update_source = su;
+       }
+      else if (group->conf->update_if)
+       peer->update_if = 
+         XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->conf->update_if);
+    }
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+      return 0;
+    }
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (! peer->update_source && ! peer->update_if)
+       continue;
+
+      if (peer->update_source)
+       {
+         sockunion_free (peer->update_source);
+         peer->update_source = NULL;
+       }
+
+      if (peer->update_if)
+       {
+         XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+         peer->update_if = NULL;
+       }
+
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+       BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+  return 0;
+}
+\f
+int
+peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
+                           char *rmap)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  /* Adress family must be activated.  */
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  /* Default originate can't be used for peer group memeber.  */
+  if (peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
+      || (rmap && ! peer->default_rmap[afi][safi].name)
+      || (rmap && strcmp (rmap, peer->default_rmap[afi][safi].name) != 0))
+    { 
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+
+      if (rmap)
+       {
+         if (peer->default_rmap[afi][safi].name)
+           free (peer->default_rmap[afi][safi].name);
+         peer->default_rmap[afi][safi].name = strdup (rmap);
+         peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
+       }
+    }
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established && peer->afc_nego[afi][safi])
+       bgp_default_originate (peer, afi, safi, 0);
+      return 0;
+    }
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+
+      if (rmap)
+       {
+         if (peer->default_rmap[afi][safi].name)
+           free (peer->default_rmap[afi][safi].name);
+         peer->default_rmap[afi][safi].name = strdup (rmap);
+         peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
+       }
+
+      if (peer->status == Established && peer->afc_nego[afi][safi])
+       bgp_default_originate (peer, afi, safi, 0);
+    }
+  return 0;
+}
+
+int
+peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  /* Adress family must be activated.  */
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  /* Default originate can't be used for peer group memeber.  */
+  if (peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
+    { 
+      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+
+      if (peer->default_rmap[afi][safi].name)
+       free (peer->default_rmap[afi][safi].name);
+      peer->default_rmap[afi][safi].name = NULL;
+      peer->default_rmap[afi][safi].map = NULL;
+    }
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established && peer->afc_nego[afi][safi])
+       bgp_default_originate (peer, afi, safi, 1);
+      return 0;
+    }
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+
+      if (peer->default_rmap[afi][safi].name)
+       free (peer->default_rmap[afi][safi].name);
+      peer->default_rmap[afi][safi].name = NULL;
+      peer->default_rmap[afi][safi].map = NULL;
+
+      if (peer->status == Established && peer->afc_nego[afi][safi])
+       bgp_default_originate (peer, afi, safi, 1);
+    }
+  return 0;
+}
+\f
+int
+peer_port_set (struct peer *peer, u_int16_t port)
+{
+  peer->port = port;
+  return 0;
+}
+
+int
+peer_port_unset (struct peer *peer)
+{
+  peer->port = BGP_PORT_DEFAULT;
+  return 0;
+}
+\f
+/* neighbor weight. */
+int
+peer_weight_set (struct peer *peer, u_int16_t weight)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  SET_FLAG (peer->config, PEER_CONFIG_WEIGHT);
+  peer->weight = weight;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      peer->weight = group->conf->weight;
+    }
+  return 0;
+}
+
+int
+peer_weight_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  /* Set default weight. */
+  if (peer_group_active (peer))
+    peer->weight = peer->group->conf->weight;
+  else
+    peer->weight = 0;
+
+  UNSET_FLAG (peer->config, PEER_CONFIG_WEIGHT);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      peer->weight = 0;
+    }
+  return 0;
+}
+\f
+int
+peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  /* Not for peer group memeber.  */
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  /* keepalive value check.  */
+  if (keepalive > 65535)
+    return BGP_ERR_INVALID_VALUE;
+
+  /* Holdtime value check.  */
+  if (holdtime > 65535)
+    return BGP_ERR_INVALID_VALUE;
+
+  /* Holdtime value must be either 0 or greater than 3.  */
+  if (holdtime < 3 && holdtime != 0)
+    return BGP_ERR_INVALID_VALUE;
+
+  /* Set value to the configuration. */
+  SET_FLAG (peer->config, PEER_CONFIG_TIMER);
+  peer->holdtime = holdtime;
+  peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      SET_FLAG (peer->config, PEER_CONFIG_TIMER);
+      peer->holdtime = group->conf->holdtime;
+      peer->keepalive = group->conf->keepalive;
+    }
+  return 0;
+}
+
+int
+peer_timers_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  /* Clear configuration. */
+  UNSET_FLAG (peer->config, PEER_CONFIG_TIMER);
+  peer->keepalive = 0;
+  peer->holdtime = 0;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  /* peer-group member updates. */
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      UNSET_FLAG (peer->config, PEER_CONFIG_TIMER);
+      peer->holdtime = 0;
+      peer->keepalive = 0;
+    }
+
+  return 0;
+}
+\f
+int
+peer_timers_connect_set (struct peer *peer, u_int32_t connect)
+{
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  if (connect > 65535)
+    return BGP_ERR_INVALID_VALUE;
+
+  /* Set value to the configuration. */
+  SET_FLAG (peer->config, PEER_CONFIG_CONNECT);
+  peer->connect = connect;
+
+  /* Set value to timer setting. */
+  peer->v_connect = connect;
+
+  return 0;
+}
+
+int
+peer_timers_connect_unset (struct peer *peer)
+{
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  /* Clear configuration. */
+  UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT);
+  peer->connect = 0;
+
+  /* Set timer setting to default value. */
+  peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+
+  return 0;
+}
+\f
+int
+peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv)
+{
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  if (routeadv > 600)
+    return BGP_ERR_INVALID_VALUE;
+
+  SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
+  peer->routeadv = routeadv;
+  peer->v_routeadv = routeadv;
+
+  return 0;
+}
+
+int
+peer_advertise_interval_unset (struct peer *peer)
+{
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
+  peer->routeadv = 0;
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+  else
+    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+  
+  return 0;
+}
+\f
+int
+peer_version_set (struct peer *peer, int version)
+{
+  if (version != BGP_VERSION_4 && version != BGP_VERSION_MP_4_DRAFT_00)
+    return BGP_ERR_INVALID_VALUE;
+
+  peer->version = version;
+
+  return 0;
+}
+
+int
+peer_version_unset (struct peer *peer)
+{
+  peer->version = BGP_VERSION_4;
+  return 0;
+}
+\f
+/* neighbor interface */
+int
+peer_interface_set (struct peer *peer, char *str)
+{
+  if (peer->ifname)
+    free (peer->ifname);
+  peer->ifname = strdup (str);
+
+  return 0;
+}
+
+int
+peer_interface_unset (struct peer *peer)
+{
+  if (peer->ifname)
+    free (peer->ifname);
+  peer->ifname = NULL;
+
+  return 0;
+}
+\f
+/* Allow-as in.  */
+int
+peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (allow_num < 1 || allow_num > 10)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (peer->allowas_in[afi][safi] != allow_num)
+    {
+      peer->allowas_in[afi][safi] = allow_num;
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
+      peer_change_action (peer, afi, safi, peer_change_reset_in);
+    }
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (peer->allowas_in[afi][safi] != allow_num)
+       {
+         peer->allowas_in[afi][safi] = allow_num;
+         SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
+         peer_change_action (peer, afi, safi, peer_change_reset_in);
+       }
+         
+    }
+  return 0;
+}
+
+int
+peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
+    {
+      peer->allowas_in[afi][safi] = 0;
+      peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+    }
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
+       {
+         peer->allowas_in[afi][safi] = 0;
+         peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+       }
+    }
+  return 0;
+}
+\f
+int
+peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
+{
+  struct bgp *bgp = peer->bgp;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer_sort (peer) != BGP_PEER_EBGP
+      && peer_sort (peer) != BGP_PEER_INTERNAL)
+    return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP;
+
+  if (bgp->as == as)
+    return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS;
+
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  if (peer->change_local_as == as &&
+      ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend)
+       || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend)))
+    return 0;
+
+  peer->change_local_as = as;
+  if (no_prepend)
+    SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+  else
+    UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                         BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+
+      return 0;
+    }
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      peer->change_local_as = as;
+      if (no_prepend)
+       SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+      else
+       UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                         BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+
+  return 0;
+}
+
+int
+peer_local_as_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (peer_group_active (peer))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  if (! peer->change_local_as)
+    return 0;
+
+  peer->change_local_as = 0;
+  UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                         BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+
+      return 0;
+    }
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      peer->change_local_as = 0;
+      UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+
+      if (peer->status == Established)
+        bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                         BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+  return 0;
+}
+\f
+/* Set distribute list to the peer. */
+int
+peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, 
+                    char *name)
+{
+  struct bgp_filter *filter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  if (filter->plist[direct].name)
+    return BGP_ERR_PEER_FILTER_CONFLICT;
+
+  if (filter->dlist[direct].name)
+    free (filter->dlist[direct].name);
+  filter->dlist[direct].name = strdup (name);
+  filter->dlist[direct].alist = access_list_lookup (afi, name);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->dlist[direct].name)
+       free (filter->dlist[direct].name);
+      filter->dlist[direct].name = strdup (name);
+      filter->dlist[direct].alist = access_list_lookup (afi, name);
+    }
+
+  return 0;
+}
+
+int
+peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
+{
+  struct bgp_filter *filter;
+  struct bgp_filter *gfilter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  /* apply peer-group filter */
+  if (peer->af_group[afi][safi])
+    {
+      gfilter = &peer->group->conf->filter[afi][safi];
+
+      if (gfilter->dlist[direct].name)
+       {
+         if (filter->dlist[direct].name)
+           free (filter->dlist[direct].name);
+         filter->dlist[direct].name = strdup (gfilter->dlist[direct].name);
+         filter->dlist[direct].alist = gfilter->dlist[direct].alist;
+         return 0;
+       }
+    }
+
+  if (filter->dlist[direct].name)
+    free (filter->dlist[direct].name);
+  filter->dlist[direct].name = NULL;
+  filter->dlist[direct].alist = NULL;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+    group = peer->group;
+    LIST_LOOP (group->peer, peer, nn)
+      {
+       filter = &peer->filter[afi][safi];
+
+       if (! peer->af_group[afi][safi])
+         continue;
+
+       if (filter->dlist[direct].name)
+         free (filter->dlist[direct].name);
+       filter->dlist[direct].name = NULL;
+       filter->dlist[direct].alist = NULL;
+      }
+
+  return 0;
+}
+
+/* Update distribute list. */
+void
+peer_distribute_update (struct access_list *access)
+{
+  afi_t afi;
+  safi_t safi;
+  int direct;
+  struct listnode *nn, *nm;
+  struct bgp *bgp;
+  struct peer *peer;
+  struct peer_group *group;
+  struct bgp_filter *filter;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      LIST_LOOP (bgp->peer, peer, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &peer->filter[afi][safi];
+
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->dlist[direct].name)
+                     filter->dlist[direct].alist = 
+                       access_list_lookup (afi, filter->dlist[direct].name);
+                   else
+                     filter->dlist[direct].alist = NULL;
+                 }
+             }
+       }
+      LIST_LOOP (bgp->group, group, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &group->conf->filter[afi][safi];
+
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->dlist[direct].name)
+                     filter->dlist[direct].alist = 
+                       access_list_lookup (afi, filter->dlist[direct].name);
+                   else
+                     filter->dlist[direct].alist = NULL;
+                 }
+             }
+       }
+    }
+}
+\f
+/* Set prefix list to the peer. */
+int
+peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct, 
+                     char *name)
+{
+  struct bgp_filter *filter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  if (filter->dlist[direct].name)
+    return BGP_ERR_PEER_FILTER_CONFLICT;
+
+  if (filter->plist[direct].name)
+    free (filter->plist[direct].name);
+  filter->plist[direct].name = strdup (name);
+  filter->plist[direct].plist = prefix_list_lookup (afi, name);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->plist[direct].name)
+       free (filter->plist[direct].name);
+      filter->plist[direct].name = strdup (name);
+      filter->plist[direct].plist = prefix_list_lookup (afi, name);
+    }
+  return 0;
+}
+
+int
+peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
+{
+  struct bgp_filter *filter;
+  struct bgp_filter *gfilter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  /* apply peer-group filter */
+  if (peer->af_group[afi][safi])
+    {
+      gfilter = &peer->group->conf->filter[afi][safi];
+
+      if (gfilter->plist[direct].name)
+       {
+         if (filter->plist[direct].name)
+           free (filter->plist[direct].name);
+         filter->plist[direct].name = strdup (gfilter->plist[direct].name);
+         filter->plist[direct].plist = gfilter->plist[direct].plist;
+         return 0;
+       }
+    }
+
+  if (filter->plist[direct].name)
+    free (filter->plist[direct].name);
+  filter->plist[direct].name = NULL;
+  filter->plist[direct].plist = NULL;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->plist[direct].name)
+       free (filter->plist[direct].name);
+      filter->plist[direct].name = NULL;
+      filter->plist[direct].plist = NULL;
+    }
+
+  return 0;
+}
+
+/* Update prefix-list list. */
+void
+peer_prefix_list_update (struct prefix_list *plist)
+{
+  struct listnode *nn, *nm;
+  struct bgp *bgp;
+  struct peer *peer;
+  struct peer_group *group;
+  struct bgp_filter *filter;
+  afi_t afi;
+  safi_t safi;
+  int direct;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      LIST_LOOP (bgp->peer, peer, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &peer->filter[afi][safi];
+
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->plist[direct].name)
+                     filter->plist[direct].plist = 
+                       prefix_list_lookup (afi, filter->plist[direct].name);
+                   else
+                     filter->plist[direct].plist = NULL;
+                 }
+             }
+       }
+      LIST_LOOP (bgp->group, group, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &group->conf->filter[afi][safi];
+
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->plist[direct].name)
+                     filter->plist[direct].plist = 
+                       prefix_list_lookup (afi, filter->plist[direct].name);
+                   else
+                     filter->plist[direct].plist = NULL;
+                 }
+             }
+       }
+    }
+}
+\f
+int
+peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
+                char *name)
+{
+  struct bgp_filter *filter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  if (filter->aslist[direct].name)
+    free (filter->aslist[direct].name);
+  filter->aslist[direct].name = strdup (name);
+  filter->aslist[direct].aslist = as_list_lookup (name);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->aslist[direct].name)
+       free (filter->aslist[direct].name);
+      filter->aslist[direct].name = strdup (name);
+      filter->aslist[direct].aslist = as_list_lookup (name);
+    }
+  return 0;
+}
+
+int
+peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
+{
+  struct bgp_filter *filter;
+  struct bgp_filter *gfilter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  /* apply peer-group filter */
+  if (peer->af_group[afi][safi])
+    {
+      gfilter = &peer->group->conf->filter[afi][safi];
+
+      if (gfilter->aslist[direct].name)
+       {
+         if (filter->aslist[direct].name)
+           free (filter->aslist[direct].name);
+         filter->aslist[direct].name = strdup (gfilter->aslist[direct].name);
+         filter->aslist[direct].aslist = gfilter->aslist[direct].aslist;
+         return 0;
+       }
+    }
+
+  if (filter->aslist[direct].name)
+    free (filter->aslist[direct].name);
+  filter->aslist[direct].name = NULL;
+  filter->aslist[direct].aslist = NULL;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->aslist[direct].name)
+       free (filter->aslist[direct].name);
+      filter->aslist[direct].name = NULL;
+      filter->aslist[direct].aslist = NULL;
+    }
+
+  return 0;
+}
+
+void
+peer_aslist_update ()
+{
+  afi_t afi;
+  safi_t safi;
+  int direct;
+  struct listnode *nn, *nm;
+  struct bgp *bgp;
+  struct peer *peer;
+  struct peer_group *group;
+  struct bgp_filter *filter;
+
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      LIST_LOOP (bgp->peer, peer, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &peer->filter[afi][safi];
+
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->aslist[direct].name)
+                     filter->aslist[direct].aslist = 
+                       as_list_lookup (filter->aslist[direct].name);
+                   else
+                     filter->aslist[direct].aslist = NULL;
+                 }
+             }
+       }
+      LIST_LOOP (bgp->group, group, nm)
+       {
+         for (afi = AFI_IP; afi < AFI_MAX; afi++)
+           for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+             {
+               filter = &group->conf->filter[afi][safi];
+
+               for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+                 {
+                   if (filter->aslist[direct].name)
+                     filter->aslist[direct].aslist = 
+                       as_list_lookup (filter->aslist[direct].name);
+                   else
+                     filter->aslist[direct].aslist = NULL;
+                 }
+             }
+       }
+    }
+}
+\f
+/* Set route-map to the peer. */
+int
+peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, 
+                   char *name)
+{
+  struct bgp_filter *filter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  if (filter->map[direct].name)
+    free (filter->map[direct].name);
+  
+  filter->map[direct].name = strdup (name);
+  filter->map[direct].map = route_map_lookup_by_name (name);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->map[direct].name)
+       free (filter->map[direct].name);
+      filter->map[direct].name = strdup (name);
+      filter->map[direct].map = route_map_lookup_by_name (name);
+    }
+  return 0;
+}
+
+/* Unset route-map from the peer. */
+int
+peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
+{
+  struct bgp_filter *filter;
+  struct bgp_filter *gfilter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (direct != FILTER_IN && direct != FILTER_OUT)
+    return BGP_ERR_INVALID_VALUE;
+
+  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  /* apply peer-group filter */
+  if (peer->af_group[afi][safi])
+    {
+      gfilter = &peer->group->conf->filter[afi][safi];
+
+      if (gfilter->map[direct].name)
+       {
+         if (filter->map[direct].name)
+           free (filter->map[direct].name);
+         filter->map[direct].name = strdup (gfilter->map[direct].name);
+         filter->map[direct].map = gfilter->map[direct].map;
+         return 0;
+       }
+    }
+
+  if (filter->map[direct].name)
+    free (filter->map[direct].name);
+  filter->map[direct].name = NULL;
+  filter->map[direct].map = NULL;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->map[direct].name)
+       free (filter->map[direct].name);
+      filter->map[direct].name = NULL;
+      filter->map[direct].map = NULL;
+    }
+  return 0;
+}
+\f
+/* Set unsuppress-map to the peer. */
+int
+peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi, char *name)
+{
+  struct bgp_filter *filter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  if (peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+      
+  filter = &peer->filter[afi][safi];
+
+  if (filter->usmap.name)
+    free (filter->usmap.name);
+  
+  filter->usmap.name = strdup (name);
+  filter->usmap.map = route_map_lookup_by_name (name);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->usmap.name)
+       free (filter->usmap.name);
+      filter->usmap.name = strdup (name);
+      filter->usmap.map = route_map_lookup_by_name (name);
+    }
+  return 0;
+}
+
+/* Unset route-map from the peer. */
+int
+peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+  
+  if (peer_is_group_member (peer, afi, safi))
+    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
+
+  filter = &peer->filter[afi][safi];
+
+  if (filter->usmap.name)
+    free (filter->usmap.name);
+  filter->usmap.name = NULL;
+  filter->usmap.map = NULL;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      filter = &peer->filter[afi][safi];
+
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      if (filter->usmap.name)
+       free (filter->usmap.name);
+      filter->usmap.name = NULL;
+      filter->usmap.map = NULL;
+    }
+  return 0;
+}
+\f
+int
+peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi,
+                        u_int32_t max, int warning)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+  peer->pmax[afi][safi] = max;
+  if (warning)
+    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+  else
+    UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+      peer->pmax[afi][safi] = max;
+      if (warning)
+       SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+      else
+       UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+    }
+  return 0;
+}
+
+int
+peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct peer_group *group;
+  struct listnode *nn;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_PEER_INACTIVE;
+
+  /* apply peer-group config */
+  if (peer->af_group[afi][safi])
+    {
+      if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi],
+         PEER_FLAG_MAX_PREFIX))
+       SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+      else
+       UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+
+      if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi],
+         PEER_FLAG_MAX_PREFIX_WARNING))
+       SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+      else
+       UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+
+      peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi];
+      return 0;
+    }
+
+  UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+  UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+  peer->pmax[afi][safi] = 0;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  group = peer->group;
+  LIST_LOOP (group->peer, peer, nn)
+    {
+      if (! peer->af_group[afi][safi])
+       continue;
+
+      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+      peer->pmax[afi][safi] = 0;
+    }
+  return 0;
+}
+\f
+int
+peer_clear (struct peer *peer)
+{
+  if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
+    {
+      UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+      peer->v_start = BGP_INIT_START_TIMER;
+      if (peer->status == Established)
+       bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+                        BGP_NOTIFY_CEASE_ADMIN_RESET);
+      else
+        BGP_EVENT_ADD (peer, BGP_Stop);
+    }
+  return 0;
+}
+
+int
+peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
+                enum bgp_clear_type stype)
+{
+  if (peer->status != Established)
+    return 0;
+
+  if (! peer->afc[afi][safi])
+    return BGP_ERR_AF_UNCONFIGURED;
+
+  if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH)
+    bgp_announce_route (peer, afi, safi);
+
+  if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX)
+    {
+      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
+         && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)
+             || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)))
+       {
+         struct bgp_filter *filter = &peer->filter[afi][safi];
+         u_char prefix_type;
+
+         if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
+           prefix_type = ORF_TYPE_PREFIX;
+         else
+           prefix_type = ORF_TYPE_PREFIX_OLD;
+
+         if (filter->plist[FILTER_IN].plist)
+           {
+             if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND))
+               bgp_route_refresh_send (peer, afi, safi,
+                                       prefix_type, REFRESH_DEFER, 1);
+             bgp_route_refresh_send (peer, afi, safi, prefix_type,
+                                     REFRESH_IMMEDIATE, 0);
+           }
+         else
+           {
+             if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND))
+               bgp_route_refresh_send (peer, afi, safi,
+                                       prefix_type, REFRESH_IMMEDIATE, 1);
+             else
+               bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+           }
+         return 0;
+       }
+    }
+
+  if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH
+      || stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX)
+    {
+      /* If neighbor has soft reconfiguration inbound flag.
+        Use Adj-RIB-In database. */
+      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+       bgp_soft_reconfig_in (peer, afi, safi);
+      else
+       {
+         /* If neighbor has route refresh capability, send route refresh
+            message to the peer. */
+         if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+             || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+           bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+         else
+           return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED;
+       }
+    }
+  return 0;
+}
+\f
+/* Display peer uptime. */
+char *
+peer_uptime (time_t uptime2, char *buf, size_t len)
+{
+  time_t uptime1;
+  struct tm *tm;
+
+  /* Check buffer length. */
+  if (len < BGP_UPTIME_LEN)
+    {
+      zlog_warn ("peer_uptime (): buffer shortage %d", len);
+      return "";
+    }
+
+  /* If there is no connection has been done before print `never'. */
+  if (uptime2 == 0)
+    {
+      snprintf (buf, len, "never   ");
+      return buf;
+    }
+
+  /* Get current time. */
+  uptime1 = time (NULL);
+  uptime1 -= uptime2;
+  tm = gmtime (&uptime1);
+
+  /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+  if (uptime1 < ONE_DAY_SECOND)
+    snprintf (buf, len, "%02d:%02d:%02d", 
+             tm->tm_hour, tm->tm_min, tm->tm_sec);
+  else if (uptime1 < ONE_WEEK_SECOND)
+    snprintf (buf, len, "%dd%02dh%02dm", 
+             tm->tm_yday, tm->tm_hour, tm->tm_min);
+  else
+    snprintf (buf, len, "%02dw%dd%02dh", 
+             tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+  return buf;
+}
+\f
+void
+bgp_config_write_filter (struct vty *vty, struct peer *peer,
+                        afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+  struct bgp_filter *gfilter = NULL;
+  char *addr;
+  int in = FILTER_IN;
+  int out = FILTER_OUT;
+
+  addr = peer->host;
+  filter = &peer->filter[afi][safi];
+  if (peer->af_group[afi][safi])
+    gfilter = &peer->group->conf->filter[afi][safi];
+
+  /* distribute-list. */
+  if (filter->dlist[in].name)
+    if (! gfilter || ! gfilter->dlist[in].name
+       || strcmp (filter->dlist[in].name, gfilter->dlist[in].name) != 0)
+    vty_out (vty, " neighbor %s distribute-list %s in%s", addr, 
+            filter->dlist[in].name, VTY_NEWLINE);
+  if (filter->dlist[out].name && ! gfilter)
+    vty_out (vty, " neighbor %s distribute-list %s out%s", addr, 
+            filter->dlist[out].name, VTY_NEWLINE);
+
+  /* prefix-list. */
+  if (filter->plist[in].name)
+    if (! gfilter || ! gfilter->plist[in].name
+       || strcmp (filter->plist[in].name, gfilter->plist[in].name) != 0)
+    vty_out (vty, " neighbor %s prefix-list %s in%s", addr, 
+            filter->plist[in].name, VTY_NEWLINE);
+  if (filter->plist[out].name && ! gfilter)
+    vty_out (vty, " neighbor %s prefix-list %s out%s", addr, 
+            filter->plist[out].name, VTY_NEWLINE);
+
+  /* route-map. */
+  if (filter->map[in].name)
+    if (! gfilter || ! gfilter->map[in].name
+       || strcmp (filter->map[in].name, gfilter->map[in].name) != 0)
+      vty_out (vty, " neighbor %s route-map %s in%s", addr, 
+              filter->map[in].name, VTY_NEWLINE);
+  if (filter->map[out].name && ! gfilter)
+    vty_out (vty, " neighbor %s route-map %s out%s", addr, 
+            filter->map[out].name, VTY_NEWLINE);
+
+  /* unsuppress-map */
+  if (filter->usmap.name && ! gfilter)
+    vty_out (vty, " neighbor %s unsuppress-map %s%s", addr,
+            filter->usmap.name, VTY_NEWLINE);
+
+  /* filter-list. */
+  if (filter->aslist[in].name)
+    if (! gfilter || ! gfilter->aslist[in].name
+       || strcmp (filter->aslist[in].name, gfilter->aslist[in].name) != 0)
+      vty_out (vty, " neighbor %s filter-list %s in%s", addr, 
+              filter->aslist[in].name, VTY_NEWLINE);
+  if (filter->aslist[out].name && ! gfilter)
+    vty_out (vty, " neighbor %s filter-list %s out%s", addr, 
+            filter->aslist[out].name, VTY_NEWLINE);
+}
+
+/* BGP peer configuration display function. */
+void
+bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
+                      struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_filter *filter;
+  struct peer *g_peer = NULL;
+  char buf[SU_ADDRSTRLEN];
+  char *addr;
+
+  filter = &peer->filter[afi][safi];
+  addr = peer->host;
+  if (peer_group_active (peer))
+    g_peer = peer->group->conf;
+
+  /************************************
+   ****** Global to the neighbor ******
+   ************************************/
+  if (afi == AFI_IP && safi == SAFI_UNICAST)
+    {
+      /* remote-as. */
+      if (! peer_group_active (peer))
+       {
+         if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+           vty_out (vty, " neighbor %s peer-group%s", addr,
+                    VTY_NEWLINE);
+         if (peer->as)
+           vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as,
+                    VTY_NEWLINE);
+       }
+      else
+       {
+         if (! g_peer->as)
+           vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as,
+                    VTY_NEWLINE);
+         if (peer->af_group[AFI_IP][SAFI_UNICAST])
+           vty_out (vty, " neighbor %s peer-group %s%s", addr,
+                    peer->group->name, VTY_NEWLINE);
+       }
+
+      /* local-as. */
+      if (peer->change_local_as)
+       if (! peer_group_active (peer))
+         vty_out (vty, " neighbor %s local-as %d%s%s", addr,
+                  peer->change_local_as,
+                  CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
+                  " no-prepend" : "", VTY_NEWLINE);
+
+      /* Description. */
+      if (peer->desc)
+       vty_out (vty, " neighbor %s description %s%s", addr, peer->desc,
+                VTY_NEWLINE);
+
+      /* Shutdown. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN))
+         vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE);
+
+      /* BGP port. */
+      if (peer->port != BGP_PORT_DEFAULT)
+       vty_out (vty, " neighbor %s port %d%s", addr, peer->port, 
+                VTY_NEWLINE);
+
+      /* Local interface name. */
+      if (peer->ifname)
+       vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname,
+                VTY_NEWLINE);
+  
+      /* Passive. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE))
+         vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE);
+
+      /* EBGP multihop.  */
+      if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1)
+        if (! peer_group_active (peer) ||
+           g_peer->ttl != peer->ttl)
+         vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl,
+                  VTY_NEWLINE);
+
+      /* Enforce multihop.  */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))
+       if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))
+         vty_out (vty, " neighbor %s enforce-multihop%s", addr, VTY_NEWLINE);
+
+      /* Update-source. */
+      if (peer->update_if)
+       if (! peer_group_active (peer) || ! g_peer->update_if
+           || strcmp (g_peer->update_if, peer->update_if) != 0)
+         vty_out (vty, " neighbor %s update-source %s%s", addr,
+                  peer->update_if, VTY_NEWLINE);
+      if (peer->update_source)
+       if (! peer_group_active (peer) || ! g_peer->update_source
+           || sockunion_cmp (g_peer->update_source,
+                             peer->update_source) != 0)
+         vty_out (vty, " neighbor %s update-source %s%s", addr,
+                  sockunion2str (peer->update_source, buf, SU_ADDRSTRLEN),
+                  VTY_NEWLINE);
+
+      /* BGP version print. */
+      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
+       vty_out (vty, " neighbor %s version %s%s",
+                addr,"4-", VTY_NEWLINE);
+
+      /* advertisement-interval */
+      if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV))
+       vty_out (vty, " neighbor %s advertisement-interval %d%s",
+                addr, peer->v_routeadv, VTY_NEWLINE); 
+
+      /* timers. */
+      if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)
+         && ! peer_group_active (peer))
+         vty_out (vty, " neighbor %s timers %d %d%s", addr, 
+         peer->keepalive, peer->holdtime, VTY_NEWLINE);
+
+      if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT))
+         vty_out (vty, " neighbor %s timers connect %d%s", addr, 
+         peer->connect, VTY_NEWLINE);
+
+      /* Default weight. */
+      if (CHECK_FLAG (peer->config, PEER_CONFIG_WEIGHT))
+        if (! peer_group_active (peer) ||
+           g_peer->weight != peer->weight)
+         vty_out (vty, " neighbor %s weight %d%s", addr, peer->weight,
+                  VTY_NEWLINE);
+
+      /* Route refresh. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP))
+         vty_out (vty, " no neighbor %s capability route-refresh%s", addr,
+         VTY_NEWLINE);
+
+      /* Dynamic capability.  */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
+       vty_out (vty, " neighbor %s capability dynamic%s", addr,
+            VTY_NEWLINE);
+
+      /* dont capability negotiation. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DONT_CAPABILITY))
+       vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr,
+                VTY_NEWLINE);
+
+      /* override capability negotiation. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+       vty_out (vty, " neighbor %s override-capability%s", addr,
+                VTY_NEWLINE);
+
+      /* strict capability negotiation. */
+      if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
+        if (! peer_group_active (peer) ||
+           ! CHECK_FLAG (g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
+       vty_out (vty, " neighbor %s strict-capability-match%s", addr,
+            VTY_NEWLINE);
+
+      if (! peer_group_active (peer))
+       {
+         if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
+           {
+             if (peer->afc[AFI_IP][SAFI_UNICAST])
+               vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE);
+           }
+          else
+           {
+             if (! peer->afc[AFI_IP][SAFI_UNICAST])
+               vty_out (vty, " no neighbor %s activate%s", addr, VTY_NEWLINE);
+           }
+       }
+    }
+
+
+  /************************************
+   ****** Per AF to the neighbor ******
+   ************************************/
+
+  if (! (afi == AFI_IP && safi == SAFI_UNICAST))
+    {
+      if (peer->af_group[afi][safi])
+       vty_out (vty, " neighbor %s peer-group %s%s", addr,
+                peer->group->name, VTY_NEWLINE);
+      else
+       vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE);
+    }
+
+  /* ORF capability.  */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
+      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
+    if (! peer->af_group[afi][safi])
+    {
+      vty_out (vty, " neighbor %s capability orf prefix-list", addr);
+
+      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
+         && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
+       vty_out (vty, " both");
+      else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
+       vty_out (vty, " send");
+      else
+       vty_out (vty, " receive");
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  /* Route reflector client. */
+  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)
+      && ! peer->af_group[afi][safi])
+    vty_out (vty, " neighbor %s route-reflector-client%s", addr, 
+            VTY_NEWLINE);
+
+  /* Nexthop self. */
+  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)
+      && ! peer->af_group[afi][safi])
+    vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE);
+
+  /* Remove private AS. */
+  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
+      && ! peer->af_group[afi][safi])
+    vty_out (vty, " neighbor %s remove-private-AS%s",
+            addr, VTY_NEWLINE);
+
+  /* send-community print. */
+  if (! peer->af_group[afi][safi])
+    {
+      if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
+       {
+         if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
+             && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
+           vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE);
+         else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))  
+           vty_out (vty, " neighbor %s send-community extended%s",
+                    addr, VTY_NEWLINE);
+         else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
+           vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE);
+       }
+      else
+       {
+         if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
+             && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
+           vty_out (vty, " no neighbor %s send-community both%s",
+                    addr, VTY_NEWLINE);
+         else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
+           vty_out (vty, " no neighbor %s send-community extended%s",
+                    addr, VTY_NEWLINE);
+         else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
+           vty_out (vty, " no neighbor %s send-community%s",
+                    addr, VTY_NEWLINE);
+       }
+    }
+
+  /* Default information */
+  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE)
+      && ! peer->af_group[afi][safi])
+    {
+      vty_out (vty, " neighbor %s default-originate", addr);
+      if (peer->default_rmap[afi][safi].name)
+       vty_out (vty, " route-map %s", peer->default_rmap[afi][safi].name);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  /* Soft reconfiguration inbound. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+    if (! peer->af_group[afi][safi] ||
+       ! CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+    vty_out (vty, " neighbor %s soft-reconfiguration inbound%s", addr,
+            VTY_NEWLINE);
+
+  /* maximum-prefix. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
+    if (! peer->af_group[afi][safi]
+       || g_peer->pmax[afi][safi] != peer->pmax[afi][safi]
+       || CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)
+          != CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
+      vty_out (vty, " neighbor %s maximum-prefix %ld%s%s",
+              addr, peer->pmax[afi][safi],
+              CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)
+              ? " warning-only" : "", VTY_NEWLINE);
+
+  /* Route server client. */
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
+      && ! peer->af_group[afi][safi])
+    vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE);
+
+  /* Allow AS in.  */
+  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN))
+    if (! peer_group_active (peer)
+       || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN)
+       || peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi])
+      {
+       if (peer->allowas_in[afi][safi] == 3)
+         vty_out (vty, " neighbor %s allowas-in%s", addr, VTY_NEWLINE);
+       else
+         vty_out (vty, " neighbor %s allowas-in %d%s", addr,
+                  peer->allowas_in[afi][safi], VTY_NEWLINE);
+      }
+
+  /* Filter. */
+  bgp_config_write_filter (vty, peer, afi, safi);
+
+  /* atribute-unchanged. */
+  if ((CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
+      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
+      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
+      && ! peer->af_group[afi][safi])
+    {
+      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
+          && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
+          && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
+       vty_out (vty, " neighbor %s attribute-unchanged%s", addr, VTY_NEWLINE);
+      else
+       vty_out (vty, " neighbor %s attribute-unchanged%s%s%s%s", addr, 
+            (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) ?
+            " as-path" : "",
+            (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) ?
+            " next-hop" : "",
+            (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) ?
+            " med" : "", VTY_NEWLINE);
+    }
+}
+
+/* Display "address-family" configuration header. */
+void
+bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
+                               int *write)
+{
+  if (*write)
+    return;
+
+  if (afi == AFI_IP && safi == SAFI_UNICAST)
+    return;
+
+  vty_out (vty, "!%s address-family ", VTY_NEWLINE);
+
+  if (afi == AFI_IP)
+    {
+      if (safi == SAFI_MULTICAST)
+       vty_out (vty, "ipv4 multicast");
+      else if (safi == SAFI_MPLS_VPN)
+       vty_out (vty, "vpnv4 unicast");
+    }
+  else if (afi == AFI_IP6)
+    vty_out (vty, "ipv6");
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  *write = 1;
+}
+
+/* Address family based peer configuration display.  */
+int
+bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
+                        safi_t safi)
+{
+  int write = 0;
+  struct peer *peer;
+  struct peer_group *group;
+  struct listnode *nn;
+
+  bgp_config_write_network (vty, bgp, afi, safi, &write);
+
+  bgp_config_write_redistribute (vty, bgp, afi, safi, &write);
+
+  LIST_LOOP (bgp->group, group, nn)
+    {
+      if (group->conf->afc[afi][safi])
+       {
+         bgp_config_write_family_header (vty, afi, safi, &write);
+         bgp_config_write_peer (vty, bgp, group->conf, afi, safi);
+       }
+    }
+  LIST_LOOP (bgp->peer, peer, nn)
+    {
+      if (peer->afc[afi][safi])
+       {
+         if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+           {
+             bgp_config_write_family_header (vty, afi, safi, &write);
+             bgp_config_write_peer (vty, bgp, peer, afi, safi);
+           }
+       }
+    }
+  if (write)
+    vty_out (vty, " exit-address-family%s", VTY_NEWLINE);
+
+  return write;
+}
+
+int
+bgp_config_write (struct vty *vty)
+{
+  int write = 0;
+  struct bgp *bgp;
+  struct peer_group *group;
+  struct peer *peer;
+  struct listnode *nn, *nm, *no;
+
+  /* BGP Multiple instance. */
+  if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
+    {    
+      vty_out (vty, "bgp multiple-instance%s", VTY_NEWLINE);
+      write++;
+    }
+
+  /* BGP Config type. */
+  if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
+    {    
+      vty_out (vty, "bgp config-type cisco%s", VTY_NEWLINE);
+      write++;
+    }
+
+  /* BGP configuration. */
+  LIST_LOOP (bm->bgp, bgp, nn)
+    {
+      if (write)
+       vty_out (vty, "!%s", VTY_NEWLINE);
+
+      /* Router bgp ASN */
+      vty_out (vty, "router bgp %d", bgp->as);
+
+      if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
+       {
+         if (bgp->name)
+           vty_out (vty, " view %s", bgp->name);
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+      /* No Synchronization */
+      if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
+       vty_out (vty, " no synchronization%s", VTY_NEWLINE);
+
+      /* BGP fast-external-failover. */
+      if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+       vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE); 
+
+      /* BGP router ID. */
+      if (CHECK_FLAG (bgp->config, BGP_CONFIG_ROUTER_ID))
+       vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->router_id), 
+                VTY_NEWLINE);
+
+      /* BGP configuration. */
+      if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED))
+       vty_out (vty, " bgp always-compare-med%s", VTY_NEWLINE);
+
+      /* BGP default ipv4-unicast. */
+      if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
+       vty_out (vty, " no bgp default ipv4-unicast%s", VTY_NEWLINE);
+
+      /* BGP default local-preference. */
+      if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
+       vty_out (vty, " bgp default local-preference %d%s",
+                bgp->default_local_pref, VTY_NEWLINE);
+
+      /* BGP client-to-client reflection. */
+      if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
+       vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE);
+      
+      /* BGP cluster ID. */
+      if (CHECK_FLAG (bgp->config, BGP_CONFIG_CLUSTER_ID))
+       vty_out (vty, " bgp cluster-id %s%s", inet_ntoa (bgp->cluster_id),
+                VTY_NEWLINE);
+
+      /* Confederation Information */
+      if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
+       {
+         vty_out (vty, " bgp confederation identifier %i%s", bgp->confed_id,
+                  VTY_NEWLINE);
+         if (bgp->confed_peers_cnt > 0)
+           {
+             int i;
+
+             vty_out (vty, " bgp confederation peers");
+
+             for (i = 0; i < bgp->confed_peers_cnt; i++)
+               {
+                 vty_out(vty, " ");
+                 vty_out(vty, "%d", bgp->confed_peers[i]);
+               }
+
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+       }
+
+      /* BGP enforce-first-as. */
+      if (bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
+       vty_out (vty, " bgp enforce-first-as%s", VTY_NEWLINE);
+
+      /* BGP deterministic-med. */
+      if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+       vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE);
+      
+      /* BGP bestpath method. */
+      if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE))
+       vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE);
+      if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID))
+       vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE);
+      if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
+         || bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST))
+       {
+         vty_out (vty, " bgp bestpath med");
+         if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED))
+           vty_out (vty, " confed");
+         if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST))
+           vty_out (vty, " missing-as-worst");
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+
+      /* BGP network import check. */
+      if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+       vty_out (vty, " bgp network import-check%s", VTY_NEWLINE);
+
+      /* BGP scan interval. */
+      bgp_config_write_scan_time (vty);
+
+      /* BGP flag dampening. */
+      if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST],
+         BGP_CONFIG_DAMPENING))
+       bgp_config_write_damp (vty);
+
+      /* BGP static route configuration. */
+      bgp_config_write_network (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
+
+      /* BGP redistribute configuration. */
+      bgp_config_write_redistribute (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
+
+      /* BGP timers configuration. */
+      if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE
+         && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
+       vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive, 
+                bgp->default_holdtime, VTY_NEWLINE);
+
+      /* peer-group */
+      LIST_LOOP (bgp->group, group, nm)
+       {
+         bgp_config_write_peer (vty, bgp, group->conf, AFI_IP, SAFI_UNICAST);
+       }
+
+      /* Normal neighbor configuration. */
+      LIST_LOOP (bgp->peer, peer, no)
+       {
+         if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+           bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
+       }
+
+      /* Distance configuration. */
+      bgp_config_write_distance (vty, bgp);
+      
+      /* No auto-summary */
+      if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
+       vty_out (vty, " no auto-summary%s", VTY_NEWLINE);
+
+      /* IPv4 multicast configuration.  */
+      write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST);
+
+      /* IPv4 VPN configuration.  */
+      write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN);
+
+      /* IPv6 unicast configuration.  */
+      write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST);
+
+      write++;
+    }
+  return write;
+}
+
+void
+bgp_master_init ()
+{
+  memset (&bgp_master, 0, sizeof (struct bgp_master));
+
+  bm = &bgp_master;
+  bm->bgp = list_new ();
+  bm->port = BGP_PORT_DEFAULT;
+  bm->master = thread_master_create ();
+  bm->start_time = time (NULL);
+}
+\f
+void
+bgp_init ()
+{
+  void bgp_zebra_init ();
+  void bgp_route_map_init ();
+  void bgp_filter_init ();
+
+  /* BGP VTY commands installation.  */
+  bgp_vty_init ();
+
+  /* Create BGP server socket.  */
+  bgp_socket (NULL, bm->port);
+
+  /* Init zebra. */
+  bgp_zebra_init ();
+
+  /* BGP inits. */
+  bgp_attr_init ();
+  bgp_debug_init ();
+  bgp_dump_init ();
+  bgp_route_init ();
+  bgp_route_map_init ();
+  bgp_scan_init ();
+  bgp_mplsvpn_init ();
+
+  /* Access list initialize. */
+  access_list_init ();
+  access_list_add_hook (peer_distribute_update);
+  access_list_delete_hook (peer_distribute_update);
+
+  /* Filter list initialize. */
+  bgp_filter_init ();
+  as_list_add_hook (peer_aslist_update);
+  as_list_delete_hook (peer_aslist_update);
+
+  /* Prefix list initialize.*/
+  prefix_list_init ();
+  prefix_list_add_hook (peer_prefix_list_update);
+  prefix_list_delete_hook (peer_prefix_list_update);
+
+  /* Community list initialize. */
+  bgp_clist = community_list_init ();
+
+#ifdef HAVE_SNMP
+  bgp_snmp_init ();
+#endif /* HAVE_SNMP */
+}
diff --git a/bgpd/bgpd.conf.sample b/bgpd/bgpd.conf.sample
new file mode 100644 (file)
index 0000000..b6a8b6f
--- /dev/null
@@ -0,0 +1,29 @@
+! -*- bgp -*-
+!
+! BGPd sample configuratin file
+!
+! $Id: bgpd.conf.sample,v 1.1 2002/12/13 20:15:29 paul Exp $
+!
+hostname bgpd
+password zebra
+!enable password please-set-at-here
+!
+!bgp mulitple-instance
+!
+router bgp 7675
+! bgp router-id 10.0.0.1
+! network 10.0.0.0/8
+! neighbor 10.0.0.2 remote-as 7675
+! neighbor 10.0.0.2 route-map set-nexthop out
+! neighbor 10.0.0.2 ebgp-multihop
+! neighbor 10.0.0.2 next-hop-self
+!
+! access-list all permit any
+!
+!route-map set-nexthop permit 10
+! match ip address all
+! set ip next-hop 10.0.0.1
+!
+!log file bgpd.log
+!
+log stdout
diff --git a/bgpd/bgpd.conf.sample2 b/bgpd/bgpd.conf.sample2
new file mode 100644 (file)
index 0000000..d376ad2
--- /dev/null
@@ -0,0 +1,77 @@
+!
+! Zebra configuration saved from vty
+!   2002/07/01 03:16:33
+!
+hostname bgpd
+password zebra
+log file bgpd.log
+log stdout
+!
+router bgp 7675
+ no bgp default ipv4-unicast
+ neighbor 3ffe:506:1000::2 remote-as 7675
+ neighbor fe80::200:c0ff:fe30:9be3 remote-as 9377
+ neighbor fe80::200:c0ff:fe30:9be3 interface sit3
+ neighbor fe80::210:5aff:fe6b:3cee remote-as 7675
+ neighbor fe80::210:5aff:fe6b:3cee interface eth0
+ neighbor fe80::290:27ff:fe51:84c7 remote-as 4691
+ neighbor fe80::290:27ff:fe51:84c7 description DTI 
+ neighbor fe80::290:27ff:fe51:84c7 interface sit7
+ neighbor fe80::2a0:c9ff:fec8:82ec remote-as 7530
+ neighbor fe80::2a0:c9ff:fec8:82ec description IRI 
+ neighbor fe80::2a0:c9ff:fec8:82ec interface sit8
+ neighbor fe80::2e0:18ff:fe98:2725 remote-as 2500
+ neighbor fe80::2e0:18ff:fe98:2725 description WIDE 
+ neighbor fe80::2e0:18ff:fe98:2725 interface sit5
+ neighbor fe80::2e0:18ff:fea8:bf5 remote-as 65000
+ neighbor fe80::2e0:18ff:fea8:bf5 interface sit6
+!
+ address-family ipv6
+ network 3ffe:506::/33
+ network 3ffe:1800:e800::/40
+ aggregate-address 3ffe:506::/32
+ redistribute connected
+ neighbor 3ffe:506:1000::2 activate
+ neighbor fe80::200:c0ff:fe30:9be3 activate
+ neighbor fe80::200:c0ff:fe30:9be3 route-map set-nexthop out
+ neighbor fe80::210:5aff:fe6b:3cee activate
+ neighbor fe80::290:27ff:fe51:84c7 activate
+ neighbor fe80::290:27ff:fe51:84c7 route-map set-nexthop out
+ neighbor fe80::2a0:c9ff:fec8:82ec activate
+ neighbor fe80::2a0:c9ff:fec8:82ec route-map set-nexthop out
+ neighbor fe80::2e0:18ff:fe98:2725 activate
+ neighbor fe80::2e0:18ff:fe98:2725 distribute-list nla1 out
+ neighbor fe80::2e0:18ff:fe98:2725 route-map set-nexthop out
+ neighbor fe80::2e0:18ff:fea8:bf5 activate
+ neighbor fe80::2e0:18ff:fea8:bf5 route-map set-nexthop out
+ exit-address-family
+!
+ipv6 access-list all permit any
+ipv6 access-list nla1 deny 3ffe:506::/33
+ipv6 access-list nla1 permit 3ffe:506::/32
+ipv6 access-list nla1 deny any
+ipv6 access-list ntt-nla1 permit 3ffe:1800:0:ffff::c/127
+ipv6 access-list ntt-nla1 deny 3ffe:1800:e800::/41
+ipv6 access-list ntt-nla1 permit 3ffe:1800:e800::/40
+ipv6 access-list ntt-nla1 deny any
+!
+ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 ge 24 le 24
+ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 ge 28 le 28
+ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16
+ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 ge 16 le 16
+ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 ge 35 le 35
+!
+route-map set-nexthop permit 10
+ match ipv6 address all
+ set ipv6 next-hop global 3ffe:506::1
+ set ipv6 next-hop local fe80::cbb5:591a
+ set ip next-hop 203.181.89.26
+ set community 7675:0
+!
+route-map set-link-local permit 10
+ match ipv6 address all
+ set ipv6 next-hop local fe80::cbb5:591a
+ set ipv6 next-hop global 3ffe:1800:0:ffff::d
+!
+line vty
+!
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
new file mode 100644 (file)
index 0000000..01d4721
--- /dev/null
@@ -0,0 +1,824 @@
+/* BGP message definition header.
+   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* For union sockunion.  */
+#include "sockunion.h"
+
+/* Typedef BGP specific types.  */
+typedef u_int16_t as_t;
+typedef u_int16_t bgp_size_t;
+
+/* BGP master for system wide configurations and variables.  */
+struct bgp_master
+{
+  /* BGP instance list.  */
+  struct list *bgp;
+
+  /* BGP thread master.  */
+  struct thread_master *master;
+
+  /* BGP port number.  */
+  u_int16_t port;
+
+  /* BGP start time.  */
+  time_t start_time;
+
+  /* Various BGP global configuration.  */
+  u_char options;
+#define BGP_OPT_NO_FIB                   (1 << 0)
+#define BGP_OPT_MULTIPLE_INSTANCE        (1 << 1)
+#define BGP_OPT_CONFIG_CISCO             (1 << 2)
+};
+
+/* BGP instance structure.  */
+struct bgp 
+{
+  /* AS number of this BGP instance.  */
+  as_t as;
+
+  /* Name of this BGP instance.  */
+  char *name;
+
+  /* Self peer.  */
+  struct peer *peer_self;
+
+  /* BGP peer. */
+  struct list *peer;
+
+  /* BGP peer group.  */
+  struct list *group;
+
+  /* BGP configuration.  */
+  u_int16_t config;
+#define BGP_CONFIG_ROUTER_ID              (1 << 0)
+#define BGP_CONFIG_CLUSTER_ID             (1 << 1)
+#define BGP_CONFIG_CONFEDERATION          (1 << 2)
+#define BGP_CONFIG_DEFAULT_LOCAL_PREF     (1 << 3)
+
+  /* BGP router identifier.  */
+  struct in_addr router_id;
+
+  /* BGP route reflector cluster ID.  */
+  struct in_addr cluster_id;
+
+  /* BGP confederation information.  */
+  as_t confed_id;
+  as_t *confed_peers;
+  int confed_peers_cnt;
+
+  /* BGP flags. */
+  u_int16_t flags;
+#define BGP_FLAG_ALWAYS_COMPARE_MED       (1 << 0)
+#define BGP_FLAG_DETERMINISTIC_MED        (1 << 1)
+#define BGP_FLAG_MED_MISSING_AS_WORST     (1 << 2)
+#define BGP_FLAG_MED_CONFED               (1 << 3)
+#define BGP_FLAG_NO_DEFAULT_IPV4          (1 << 4)
+#define BGP_FLAG_NO_CLIENT_TO_CLIENT      (1 << 5)
+#define BGP_FLAG_ENFORCE_FIRST_AS         (1 << 6)
+#define BGP_FLAG_COMPARE_ROUTER_ID        (1 << 7)
+#define BGP_FLAG_ASPATH_IGNORE            (1 << 8)
+#define BGP_FLAG_IMPORT_CHECK             (1 << 9)
+#define BGP_FLAG_NO_FAST_EXT_FAILOVER     (1 << 10)
+
+  /* BGP Per AF flags */
+  u_int16_t af_flags[AFI_MAX][SAFI_MAX];
+#define BGP_CONFIG_DAMPENING              (1 << 0)
+
+  /* Static route configuration.  */
+  struct bgp_table *route[AFI_MAX][SAFI_MAX];
+
+  /* Aggregate address configuration.  */
+  struct bgp_table *aggregate[AFI_MAX][SAFI_MAX];
+
+  /* BGP routing information base.  */
+  struct bgp_table *rib[AFI_MAX][SAFI_MAX];
+
+  /* BGP redistribute configuration. */
+  u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX];
+
+  /* BGP redistribute metric configuration. */
+  u_char redist_metric_flag[AFI_MAX][ZEBRA_ROUTE_MAX];
+  u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX];
+
+  /* BGP redistribute route-map.  */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
+
+  /* BGP distance configuration.  */
+  u_char distance_ebgp;
+  u_char distance_ibgp;
+  u_char distance_local;
+  
+  /* BGP default local-preference.  */
+  u_int32_t default_local_pref;
+
+  /* BGP default timer.  */
+  u_int32_t default_holdtime;
+  u_int32_t default_keepalive;
+};
+
+/* BGP peer-group support. */
+struct peer_group
+{
+  /* Name of the peer-group. */
+  char *name;
+
+  /* Pointer to BGP.  */
+  struct bgp *bgp;
+  
+  /* Peer-group client list. */
+  struct list *peer;
+
+  /* Peer-group config */
+  struct peer *conf;
+};
+
+/* BGP Notify message format. */
+struct bgp_notify 
+{
+  u_char code;
+  u_char subcode;
+  char *data;
+  bgp_size_t length;
+};
+
+/* Next hop self address. */
+struct bgp_nexthop
+{
+  struct interface *ifp;
+  struct in_addr v4;
+#ifdef HAVE_IPV6
+  struct in6_addr v6_global;
+  struct in6_addr v6_local;
+#endif /* HAVE_IPV6 */  
+};
+
+/* BGP router distinguisher value.  */
+#define BGP_RD_SIZE                8
+
+struct bgp_rd
+{
+  u_char val[BGP_RD_SIZE];
+};
+
+/* BGP filter structure. */
+struct bgp_filter
+{
+  /* Distribute-list.  */
+  struct 
+  {
+    char *name;
+    struct access_list *alist;
+  } dlist[FILTER_MAX];
+
+  /* Prefix-list.  */
+  struct
+  {
+    char *name;
+    struct prefix_list *plist;
+  } plist[FILTER_MAX];
+
+  /* Filter-list.  */
+  struct
+  {
+    char *name;
+    struct as_list *aslist;
+  } aslist[FILTER_MAX];
+
+  /* Route-map.  */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } map[FILTER_MAX];
+
+  /* Unsuppress-map.  */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } usmap;
+};
+
+/* BGP neighbor structure. */
+struct peer
+{
+  /* BGP structure.  */
+  struct bgp *bgp;
+
+  /* BGP peer group.  */
+  struct peer_group *group;
+  u_char af_group[AFI_MAX][SAFI_MAX];
+
+  /* Peer's remote AS number. */
+  as_t as;                     
+
+  /* Peer's local AS number. */
+  as_t local_as;
+
+  /* Peer's Change local AS number. */
+  as_t change_local_as;
+
+  /* Remote router ID. */
+  struct in_addr remote_id;
+
+  /* Local router ID. */
+  struct in_addr local_id;
+
+  /* Packet receive and send buffer. */
+  struct stream *ibuf;
+  struct stream_fifo *obuf;
+  struct stream *work;
+
+  /* Status of the peer. */
+  int status;
+  int ostatus;
+
+  /* Peer information */
+  int fd;                      /* File descriptor */
+  int ttl;                     /* TTL of TCP connection to the peer. */
+  char *desc;                  /* Description of the peer. */
+  unsigned short port;          /* Destination port for peer */
+  char *host;                  /* Printable address of the peer. */
+  union sockunion su;          /* Sockunion address of the peer. */
+  time_t uptime;               /* Last Up/Down time */
+  time_t readtime;             /* Last read time */
+  
+  unsigned int ifindex;                /* ifindex of the BGP connection. */
+  char *ifname;                        /* bind interface name. */
+  char *update_if;
+  union sockunion *update_source;
+  struct zlog *log;
+  u_char version;              /* Peer BGP version. */
+
+  union sockunion *su_local;   /* Sockunion of local address.  */
+  union sockunion *su_remote;  /* Sockunion of remote address.  */
+  int shared_network;          /* Is this peer shared same network. */
+  struct bgp_nexthop nexthop;  /* Nexthop */
+
+  /* Peer address family configuration. */
+  u_char afc[AFI_MAX][SAFI_MAX];
+  u_char afc_nego[AFI_MAX][SAFI_MAX];
+  u_char afc_adv[AFI_MAX][SAFI_MAX];
+  u_char afc_recv[AFI_MAX][SAFI_MAX];
+
+  /* Capability Flags.*/
+  u_char cap;
+#define PEER_CAP_REFRESH_ADV                (1 << 0) /* refresh advertised */
+#define PEER_CAP_REFRESH_OLD_RCV            (1 << 1) /* refresh old received */
+#define PEER_CAP_REFRESH_NEW_RCV            (1 << 2) /* refresh rfc received */
+#define PEER_CAP_DYNAMIC_ADV                (1 << 3) /* dynamic advertised */
+#define PEER_CAP_DYNAMIC_RCV                (1 << 4) /* dynamic received */
+
+  /* Capability Flags.*/
+  u_int16_t af_cap[AFI_MAX][SAFI_MAX];
+#define PEER_CAP_ORF_PREFIX_SM_ADV          (1 << 0) /* send-mode advertised */
+#define PEER_CAP_ORF_PREFIX_RM_ADV          (1 << 1) /* receive-mode advertised */
+#define PEER_CAP_ORF_PREFIX_SM_RCV          (1 << 2) /* send-mode received */
+#define PEER_CAP_ORF_PREFIX_RM_RCV          (1 << 3) /* receive-mode received */
+#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV      (1 << 4) /* send-mode received */
+#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV      (1 << 5) /* receive-mode received */
+
+  /* Global configuration flags. */
+  u_int32_t flags;
+#define PEER_FLAG_PASSIVE                   (1 << 0) /* passive mode */
+#define PEER_FLAG_SHUTDOWN                  (1 << 1) /* shutdown */
+#define PEER_FLAG_DONT_CAPABILITY           (1 << 2) /* dont-capability */
+#define PEER_FLAG_OVERRIDE_CAPABILITY       (1 << 3) /* override-capability */
+#define PEER_FLAG_STRICT_CAP_MATCH          (1 << 4) /* strict-match */
+#define PEER_FLAG_NO_ROUTE_REFRESH_CAP      (1 << 5) /* route-refresh */
+#define PEER_FLAG_DYNAMIC_CAPABILITY        (1 << 6) /* dynamic capability */
+#define PEER_FLAG_ENFORCE_MULTIHOP          (1 << 7) /* enforce-multihop */
+#define PEER_FLAG_LOCAL_AS_NO_PREPEND       (1 << 8) /* local-as no-prepend */
+
+  /* Per AF configuration flags. */
+  u_int32_t af_flags[AFI_MAX][SAFI_MAX];
+#define PEER_FLAG_SEND_COMMUNITY            (1 << 0) /* send-community */
+#define PEER_FLAG_SEND_EXT_COMMUNITY        (1 << 1) /* send-community ext. */
+#define PEER_FLAG_NEXTHOP_SELF              (1 << 2) /* next-hop-self */
+#define PEER_FLAG_REFLECTOR_CLIENT          (1 << 3) /* reflector-client */
+#define PEER_FLAG_RSERVER_CLIENT            (1 << 4) /* route-server-client */
+#define PEER_FLAG_SOFT_RECONFIG             (1 << 5) /* soft-reconfiguration */
+#define PEER_FLAG_AS_PATH_UNCHANGED         (1 << 6) /* transparent-as */
+#define PEER_FLAG_NEXTHOP_UNCHANGED         (1 << 7) /* transparent-next-hop */
+#define PEER_FLAG_MED_UNCHANGED             (1 << 8) /* transparent-next-hop */
+#define PEER_FLAG_DEFAULT_ORIGINATE         (1 << 9) /* default-originate */
+#define PEER_FLAG_REMOVE_PRIVATE_AS         (1 << 10) /* remove-private-as */
+#define PEER_FLAG_ALLOWAS_IN                (1 << 11) /* set allowas-in */
+#define PEER_FLAG_ORF_PREFIX_SM             (1 << 12) /* orf capability send-mode */
+#define PEER_FLAG_ORF_PREFIX_RM             (1 << 13) /* orf capability receive-mode */
+#define PEER_FLAG_MAX_PREFIX                (1 << 14) /* maximum prefix */
+#define PEER_FLAG_MAX_PREFIX_WARNING        (1 << 15) /* maximum prefix warning-only */
+
+  /* default-originate route-map.  */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } default_rmap[AFI_MAX][SAFI_MAX];
+
+  /* Peer status flags. */
+  u_int16_t sflags;
+#define PEER_STATUS_ACCEPT_PEER              (1 << 0) /* accept peer */
+#define PEER_STATUS_PREFIX_OVERFLOW   (1 << 1) /* prefix-overflow */
+#define PEER_STATUS_CAPABILITY_OPEN   (1 << 2) /* capability open send */
+#define PEER_STATUS_HAVE_ACCEPT       (1 << 3) /* accept peer's parent */
+#define PEER_STATUS_GROUP             (1 << 4) /* peer-group conf */
+
+  /* Peer status af flags. */
+  u_int16_t af_sflags[AFI_MAX][SAFI_MAX];
+#define PEER_STATUS_ORF_PREFIX_SEND   (1 << 0) /* prefix-list send peer */
+#define PEER_STATUS_ORF_WAIT_REFRESH  (1 << 1) /* wait refresh received peer */
+#define PEER_STATUS_DEFAULT_ORIGINATE (1 << 2) /* default-originate peer */
+
+  /* Default attribute value for the peer. */
+  u_int32_t config;
+#define PEER_CONFIG_WEIGHT            (1 << 0) /* Default weight. */
+#define PEER_CONFIG_TIMER             (1 << 1) /* keepalive & holdtime */
+#define PEER_CONFIG_CONNECT           (1 << 2) /* connect */
+#define PEER_CONFIG_ROUTEADV          (1 << 3) /* route advertise */
+  u_int32_t weight;
+  u_int32_t holdtime;
+  u_int32_t keepalive;
+  u_int32_t connect;
+  u_int32_t routeadv;
+
+  /* Timer values. */
+  u_int32_t v_start;
+  u_int32_t v_connect;
+  u_int32_t v_holdtime;
+  u_int32_t v_keepalive;
+  u_int32_t v_asorig;
+  u_int32_t v_routeadv;
+
+  /* Threads. */
+  struct thread *t_read;
+  struct thread *t_write;
+  struct thread *t_start;
+  struct thread *t_connect;
+  struct thread *t_holdtime;
+  struct thread *t_keepalive;
+  struct thread *t_asorig;
+  struct thread *t_routeadv;
+
+  /* Statistics field */
+  u_int32_t open_in;           /* Open message input count */
+  u_int32_t open_out;          /* Open message output count */
+  u_int32_t update_in;         /* Update message input count */
+  u_int32_t update_out;                /* Update message ouput count */
+  time_t update_time;          /* Update message received time. */
+  u_int32_t keepalive_in;      /* Keepalive input count */
+  u_int32_t keepalive_out;     /* Keepalive output count */
+  u_int32_t notify_in;         /* Notify input count */
+  u_int32_t notify_out;                /* Notify output count */
+  u_int32_t refresh_in;                /* Route Refresh input count */
+  u_int32_t refresh_out;       /* Route Refresh output count */
+  u_int32_t dynamic_cap_in;    /* Dynamic Capability input count.  */
+  u_int32_t dynamic_cap_out;   /* Dynamic Capability output count.  */
+
+  /* BGP state count */
+  u_int32_t established;       /* Established */
+  u_int32_t dropped;           /* Dropped */
+
+  /* Syncronization list and time.  */
+  struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX];
+  time_t synctime;
+
+  /* Send prefix count. */
+  unsigned long scount[AFI_MAX][SAFI_MAX];
+
+  /* Announcement attribute hash.  */
+  struct hash *hash[AFI_MAX][SAFI_MAX];
+
+  /* Notify data. */
+  struct bgp_notify notify;
+
+  /* Whole packet size to be read. */
+  unsigned long packet_size;
+
+  /* Filter structure. */
+  struct bgp_filter filter[AFI_MAX][SAFI_MAX];
+
+  /* ORF Prefix-list */
+  struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
+
+  /* Prefix count. */
+  unsigned long pcount[AFI_MAX][SAFI_MAX];
+
+  /* Max prefix count. */
+  unsigned long pmax[AFI_MAX][SAFI_MAX];
+
+  /* allowas-in. */
+  char allowas_in[AFI_MAX][SAFI_MAX];
+};
+
+/* This structure's member directly points incoming packet data
+   stream. */
+struct bgp_nlri
+{
+  /* AFI.  */
+  afi_t afi;
+
+  /* SAFI.  */
+  safi_t safi;
+
+  /* Pointer to NLRI byte stream.  */
+  u_char *nlri;
+
+  /* Length of whole NLRI.  */
+  bgp_size_t length;
+};
+
+/* BGP versions.  */
+#define BGP_VERSION_4                           4
+#define BGP_VERSION_MP_4_DRAFT_00               40
+
+/* Default BGP port number.  */
+#define BGP_PORT_DEFAULT                       179
+
+/* BGP message header and packet size.  */
+#define BGP_MARKER_SIZE                                16
+#define BGP_HEADER_SIZE                                19
+#define BGP_MAX_PACKET_SIZE                   4096
+
+/* BGP minimum message size.  */
+#define BGP_MSG_OPEN_MIN_SIZE                   (BGP_HEADER_SIZE + 10)
+#define BGP_MSG_UPDATE_MIN_SIZE                 (BGP_HEADER_SIZE + 4)
+#define BGP_MSG_NOTIFY_MIN_SIZE                 (BGP_HEADER_SIZE + 2)
+#define BGP_MSG_KEEPALIVE_MIN_SIZE              (BGP_HEADER_SIZE + 0)
+#define BGP_MSG_ROUTE_REFRESH_MIN_SIZE          (BGP_HEADER_SIZE + 4)
+#define BGP_MSG_CAPABILITY_MIN_SIZE             (BGP_HEADER_SIZE + 3)
+
+/* BGP message types.  */
+#define        BGP_MSG_OPEN                             1
+#define        BGP_MSG_UPDATE                           2
+#define        BGP_MSG_NOTIFY                           3
+#define        BGP_MSG_KEEPALIVE                        4
+#define BGP_MSG_ROUTE_REFRESH_NEW                5
+#define BGP_MSG_CAPABILITY                       6
+#define BGP_MSG_ROUTE_REFRESH_OLD              128
+
+/* BGP open optional parameter.  */
+#define BGP_OPEN_OPT_AUTH                        1
+#define BGP_OPEN_OPT_CAP                         2
+
+/* BGP4 attribute type codes.  */
+#define BGP_ATTR_ORIGIN                          1
+#define BGP_ATTR_AS_PATH                         2
+#define BGP_ATTR_NEXT_HOP                        3
+#define BGP_ATTR_MULTI_EXIT_DISC                 4
+#define BGP_ATTR_LOCAL_PREF                      5
+#define BGP_ATTR_ATOMIC_AGGREGATE                6
+#define BGP_ATTR_AGGREGATOR                      7
+#define BGP_ATTR_COMMUNITIES                     8
+#define BGP_ATTR_ORIGINATOR_ID                   9
+#define BGP_ATTR_CLUSTER_LIST                   10
+#define BGP_ATTR_DPA                            11
+#define BGP_ATTR_ADVERTISER                     12
+#define BGP_ATTR_RCID_PATH                      13
+#define BGP_ATTR_MP_REACH_NLRI                  14
+#define BGP_ATTR_MP_UNREACH_NLRI                15
+#define BGP_ATTR_EXT_COMMUNITIES                16
+
+/* BGP update origin.  */
+#define BGP_ORIGIN_IGP                           0
+#define BGP_ORIGIN_EGP                           1
+#define BGP_ORIGIN_INCOMPLETE                    2
+
+/* BGP notify message codes.  */
+#define BGP_NOTIFY_HEADER_ERR                    1
+#define BGP_NOTIFY_OPEN_ERR                      2
+#define BGP_NOTIFY_UPDATE_ERR                    3
+#define BGP_NOTIFY_HOLD_ERR                      4
+#define BGP_NOTIFY_FSM_ERR                       5
+#define BGP_NOTIFY_CEASE                         6
+#define BGP_NOTIFY_CAPABILITY_ERR                7
+#define BGP_NOTIFY_MAX                          8
+
+/* BGP_NOTIFY_HEADER_ERR sub codes.  */
+#define BGP_NOTIFY_HEADER_NOT_SYNC               1
+#define BGP_NOTIFY_HEADER_BAD_MESLEN             2
+#define BGP_NOTIFY_HEADER_BAD_MESTYPE            3
+#define BGP_NOTIFY_HEADER_MAX                    4
+
+/* BGP_NOTIFY_OPEN_ERR sub codes.  */
+#define BGP_NOTIFY_OPEN_UNSUP_VERSION            1
+#define BGP_NOTIFY_OPEN_BAD_PEER_AS              2
+#define BGP_NOTIFY_OPEN_BAD_BGP_IDENT            3
+#define BGP_NOTIFY_OPEN_UNSUP_PARAM              4
+#define BGP_NOTIFY_OPEN_AUTH_FAILURE             5
+#define BGP_NOTIFY_OPEN_UNACEP_HOLDTIME          6
+#define BGP_NOTIFY_OPEN_UNSUP_CAPBL              7
+#define BGP_NOTIFY_OPEN_MAX                      8
+
+/* BGP_NOTIFY_UPDATE_ERR sub codes.  */
+#define BGP_NOTIFY_UPDATE_MAL_ATTR               1
+#define BGP_NOTIFY_UPDATE_UNREC_ATTR             2
+#define BGP_NOTIFY_UPDATE_MISS_ATTR              3
+#define BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR          4
+#define BGP_NOTIFY_UPDATE_ATTR_LENG_ERR          5
+#define BGP_NOTIFY_UPDATE_INVAL_ORIGIN           6
+#define BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP          7
+#define BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP         8
+#define BGP_NOTIFY_UPDATE_OPT_ATTR_ERR           9
+#define BGP_NOTIFY_UPDATE_INVAL_NETWORK         10
+#define BGP_NOTIFY_UPDATE_MAL_AS_PATH           11
+#define BGP_NOTIFY_UPDATE_MAX                   12
+
+/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-00).  */
+#define BGP_NOTIFY_CEASE_MAX_PREFIX              1
+#define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN          2
+#define BGP_NOTIFY_CEASE_PEER_UNCONFIG           3
+#define BGP_NOTIFY_CEASE_ADMIN_RESET             4
+#define BGP_NOTIFY_CEASE_CONNECT_REJECT          5
+#define BGP_NOTIFY_CEASE_CONFIG_CHANGE           6
+#define BGP_NOTIFY_CEASE_MAX                     7
+
+/* BGP_NOTIFY_CAPABILITY_ERR sub codes (draft-ietf-idr-dynamic-cap-02). */
+#define BGP_NOTIFY_CAPABILITY_INVALID_ACTION     1
+#define BGP_NOTIFY_CAPABILITY_INVALID_LENGTH     2
+#define BGP_NOTIFY_CAPABILITY_MALFORMED_CODE     3
+#define BGP_NOTIFY_CAPABILITY_MAX                4
+
+/* BGP finite state machine status.  */
+#define Idle                                     1
+#define Connect                                  2
+#define Active                                   3
+#define OpenSent                                 4
+#define OpenConfirm                              5
+#define Established                              6
+#define BGP_STATUS_MAX                           7
+
+/* BGP finite state machine events.  */
+#define BGP_Start                                1
+#define BGP_Stop                                 2
+#define TCP_connection_open                      3
+#define TCP_connection_closed                    4
+#define TCP_connection_open_failed               5
+#define TCP_fatal_error                          6
+#define ConnectRetry_timer_expired               7
+#define Hold_Timer_expired                       8
+#define KeepAlive_timer_expired                  9
+#define Receive_OPEN_message                    10
+#define Receive_KEEPALIVE_message               11
+#define Receive_UPDATE_message                  12
+#define Receive_NOTIFICATION_message            13
+#define BGP_EVENTS_MAX                          14
+
+/* BGP timers default value.  */
+#define BGP_INIT_START_TIMER                     5
+#define BGP_ERROR_START_TIMER                   30
+#define BGP_DEFAULT_HOLDTIME                   180
+#define BGP_DEFAULT_KEEPALIVE                   60 
+#define BGP_DEFAULT_ASORIGINATE                 15
+#define BGP_DEFAULT_EBGP_ROUTEADV               30
+#define BGP_DEFAULT_IBGP_ROUTEADV                5
+#define BGP_CLEAR_CONNECT_RETRY                 20
+#define BGP_DEFAULT_CONNECT_RETRY              120
+
+/* BGP default local preference.  */
+#define BGP_DEFAULT_LOCAL_PREF                 100
+
+/* SAFI which used in open capability negotiation.  */
+#define BGP_SAFI_VPNV4                         128
+#define BGP_SAFI_VPNV6                         129
+
+/* Max TTL value.  */
+#define TTL_MAX                                255
+
+/* BGP uptime string length.  */
+#define BGP_UPTIME_LEN 25
+
+/* Default configuration settings for bgpd.  */
+#define BGP_VTY_PORT                          2605
+#define BGP_VTYSH_PATH                "/tmp/.bgpd"
+#define BGP_DEFAULT_CONFIG             "bgpd.conf"
+
+/* Check AS path loop when we send NLRI.  */
+/* #define BGP_SEND_ASPATH_CHECK */
+
+/* IBGP/EBGP identifier.  We also have a CONFED peer, which is to say,
+   a peer who's AS is part of our Confederation.  */
+enum
+{
+  BGP_PEER_IBGP,
+  BGP_PEER_EBGP,
+  BGP_PEER_INTERNAL,
+  BGP_PEER_CONFED
+};
+
+/* Flag for peer_clear_soft().  */
+enum bgp_clear_type
+{
+  BGP_CLEAR_SOFT_NONE,
+  BGP_CLEAR_SOFT_OUT,
+  BGP_CLEAR_SOFT_IN,
+  BGP_CLEAR_SOFT_BOTH,
+  BGP_CLEAR_SOFT_IN_ORF_PREFIX
+};
+
+/* Macros. */
+#define BGP_INPUT(P)         ((P)->ibuf)
+#define BGP_INPUT_PNT(P)     (STREAM_PNT(BGP_INPUT(P)))
+
+/* Macro to check BGP information is alive or not.  */
+#define BGP_INFO_HOLDDOWN(BI)                         \
+  (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID)         \
+   || CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY)      \
+   || CHECK_FLAG ((BI)->flags, BGP_INFO_DAMPED))
+
+/* Count prefix size from mask length */
+#define PSIZE(a) (((a) + 7) / (8))
+
+/* BGP error codes.  */
+#define BGP_SUCCESS                               0
+#define BGP_ERR_INVALID_VALUE                    -1
+#define BGP_ERR_INVALID_FLAG                     -2
+#define BGP_ERR_INVALID_AS                       -3
+#define BGP_ERR_INVALID_BGP                      -4
+#define BGP_ERR_PEER_GROUP_MEMBER                -5
+#define BGP_ERR_MULTIPLE_INSTANCE_USED           -6
+#define BGP_ERR_PEER_GROUP_MEMBER_EXISTS         -7
+#define BGP_ERR_PEER_BELONGS_TO_GROUP            -8
+#define BGP_ERR_PEER_GROUP_AF_UNCONFIGURED       -9
+#define BGP_ERR_PEER_GROUP_NO_REMOTE_AS         -10
+#define BGP_ERR_PEER_GROUP_CANT_CHANGE          -11
+#define BGP_ERR_PEER_GROUP_MISMATCH             -12
+#define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT  -13
+#define BGP_ERR_MULTIPLE_INSTANCE_NOT_SET       -14
+#define BGP_ERR_AS_MISMATCH                     -15
+#define BGP_ERR_PEER_INACTIVE                   -16
+#define BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER   -17
+#define BGP_ERR_PEER_GROUP_HAS_THE_FLAG         -18
+#define BGP_ERR_PEER_FLAG_CONFLICT              -19
+#define BGP_ERR_PEER_GROUP_SHUTDOWN             -20
+#define BGP_ERR_PEER_FILTER_CONFLICT            -21
+#define BGP_ERR_NOT_INTERNAL_PEER               -22
+#define BGP_ERR_REMOVE_PRIVATE_AS               -23
+#define BGP_ERR_AF_UNCONFIGURED                 -24
+#define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED      -25
+#define BGP_ERR_INSTANCE_MISMATCH               -26
+#define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP  -27
+#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS    -28
+#define BGP_ERR_MAX                             -29
+
+extern struct bgp_master *bm;
+
+extern struct thread_master *master;
+
+/* Prototypes. */
+void bgp_terminate (void);
+void bgp_reset (void);
+void bgp_zclient_reset ();
+int bgp_nexthop_set (union sockunion *, union sockunion *, 
+                    struct bgp_nexthop *, struct peer *);
+struct bgp *bgp_get_default ();
+struct bgp *bgp_lookup (as_t, char *);
+struct bgp *bgp_lookup_by_name (char *);
+struct peer *peer_lookup (struct bgp *, union sockunion *);
+struct peer_group *peer_group_lookup (struct bgp *, char *);
+struct peer_group *peer_group_get (struct bgp *, char *);
+struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *,
+                                   int *);
+int peer_sort (struct peer *peer);
+int peer_active (struct peer *);
+int peer_active_nego (struct peer *);
+struct peer *peer_create_accept (struct bgp *);
+char *peer_uptime (time_t, char *, size_t);
+void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *);
+\f
+void bgp_master_init ();
+
+void bgp_init ();
+
+int bgp_option_set (int);
+int bgp_option_unset (int);
+int bgp_option_check (int);
+
+int bgp_get (struct bgp **, as_t *, char *);
+int bgp_delete (struct bgp *);
+
+int bgp_flag_set (struct bgp *, int);
+int bgp_flag_unset (struct bgp *, int);
+int bgp_flag_check (struct bgp *, int);
+
+int bgp_router_id_set (struct bgp *, struct in_addr *);
+int bgp_router_id_unset (struct bgp *);
+
+int bgp_cluster_id_set (struct bgp *, struct in_addr *);
+int bgp_cluster_id_unset (struct bgp *);
+
+int bgp_confederation_id_set (struct bgp *, as_t);
+int bgp_confederation_id_unset (struct bgp *);
+int bgp_confederation_peers_check (struct bgp *, as_t);
+
+int bgp_confederation_peers_add (struct bgp *, as_t);
+int bgp_confederation_peers_remove (struct bgp *, as_t);
+
+int bgp_timers_set (struct bgp *, u_int32_t, u_int32_t);
+int bgp_timers_unset (struct bgp *);
+
+int bgp_default_local_preference_set (struct bgp *, u_int32_t);
+int bgp_default_local_preference_unset (struct bgp *);
+
+int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t);
+int peer_group_remote_as (struct bgp *, char *, as_t *);
+int peer_delete (struct peer *peer);
+int peer_group_delete (struct peer_group *);
+int peer_group_remote_as_delete (struct peer_group *);
+
+int peer_activate (struct peer *, afi_t, safi_t);
+int peer_deactivate (struct peer *, afi_t, safi_t);
+
+int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *,
+                    afi_t, safi_t, as_t *);
+int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *,
+                      afi_t, safi_t);
+
+int peer_flag_set (struct peer *, u_int32_t);
+int peer_flag_unset (struct peer *, u_int32_t);
+
+int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t);
+int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t);
+int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t);
+
+int peer_ebgp_multihop_set (struct peer *, int);
+int peer_ebgp_multihop_unset (struct peer *);
+
+int peer_description_set (struct peer *, char *);
+int peer_description_unset (struct peer *);
+
+int peer_update_source_if_set (struct peer *, char *);
+int peer_update_source_addr_set (struct peer *, union sockunion *);
+int peer_update_source_unset (struct peer *);
+
+int peer_default_originate_set (struct peer *, afi_t, safi_t, char *);
+int peer_default_originate_unset (struct peer *, afi_t, safi_t);
+
+int peer_port_set (struct peer *, u_int16_t);
+int peer_port_unset (struct peer *);
+
+int peer_weight_set (struct peer *, u_int16_t);
+int peer_weight_unset (struct peer *);
+
+int peer_timers_set (struct peer *, u_int32_t, u_int32_t);
+int peer_timers_unset (struct peer *);
+
+int peer_timers_connect_set (struct peer *, u_int32_t);
+int peer_timers_connect_unset (struct peer *);
+
+int peer_advertise_interval_set (struct peer *, u_int32_t);
+int peer_advertise_interval_unset (struct peer *);
+
+int peer_version_set (struct peer *, int);
+int peer_version_unset (struct peer *);
+
+int peer_interface_set (struct peer *, char *);
+int peer_interface_unset (struct peer *);
+
+int peer_distribute_set (struct peer *, afi_t, safi_t, int, char *);
+int peer_distribute_unset (struct peer *, afi_t, safi_t, int);
+
+int peer_allowas_in_set (struct peer *, afi_t, safi_t, int);
+int peer_allowas_in_unset (struct peer *, afi_t, safi_t);
+
+int peer_local_as_set (struct peer *, as_t, int);
+int peer_local_as_unset (struct peer *);
+
+int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, char *);
+int peer_prefix_list_unset (struct peer *, afi_t, safi_t, int);
+
+int peer_aslist_set (struct peer *, afi_t, safi_t, int, char *);
+int peer_aslist_unset (struct peer *,afi_t, safi_t, int);
+
+int peer_route_map_set (struct peer *, afi_t, safi_t, int, char *);
+int peer_route_map_unset (struct peer *, afi_t, safi_t, int);
+
+int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, char *);
+int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t);
+
+int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, int);
+int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t);
+
+int peer_clear (struct peer *);
+int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..a7983e6
--- /dev/null
@@ -0,0 +1,1321 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+#   Free Software Foundation, Inc.
+
+version='2000-11-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of this system.
+
+Operation modes:
+  -h, --help               print this help, then exit
+  -V, --version            print version number, then exit"
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case "$1" in
+    --version | --vers* | -V )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       exec >&2
+       echo "$me: invalid option $1"
+       echo "$help"
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+  if test x"$HOST_CC" != x; then
+    CC_FOR_BUILD="$HOST_CC"
+  else
+    if test x"$CC" != x; then
+      CC_FOR_BUILD="$CC"
+    else
+      echo 'int dummy(){}' >$dummy.c
+      for c in cc c89 gcc; do 
+       ($c $dummy.c -c) >/dev/null 2>&1
+       if test $? = 0; then
+         CC_FOR_BUILD="$c"; break
+       fi
+      done
+      rm -f $dummy.c $dummy.o
+      if test x"$CC_FOR_BUILD" = x; then
+       CC_FOR_BUILD=no_compiler_found
+      fi
+    fi
+  fi
+fi
+
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # Netbsd (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       # Determine the machine/vendor (is the vendor relevant).
+       case "${UNAME_MACHINE}" in
+           amiga) machine=m68k-unknown ;;
+           arm32) machine=arm-unknown ;;
+           atari*) machine=m68k-atari ;;
+           sun3*) machine=m68k-sun ;;
+           mac68k) machine=m68k-apple ;;
+           macppc) machine=powerpc-apple ;;
+           hp3[0-9][05]) machine=m68k-hp ;;
+           ibmrt|romp-ibm) machine=romp-ibm ;;
+           *) machine=${UNAME_MACHINE}-unknown ;;
+       esac
+       # The Operating System including object format.
+       if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+               | grep __ELF__ >/dev/null
+       then
+           # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+           # Return netbsd for either.  FIX?
+           os=netbsd
+       else
+           os=netbsdelf
+       fi
+       # The OS release
+       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:4)
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=4.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+              sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+       rm -f $dummy.c $dummy
+       esac
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i?86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    hppa*:OpenBSD:*:*)
+       echo hppa-unknown-openbsd
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F300:UNIX_System_V:*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    F301:UNIX_System_V:*:*)
+       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    *:Linux:*:*)
+
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       ld_supported_emulations=`cd /; ld --help 2>&1 \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         *ia64)
+               echo "${UNAME_MACHINE}-unknown-linux"
+               exit 0
+               ;;
+         i?86linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0
+               ;;
+         elf_i?86)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         i?86coff)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0
+               ;;
+         sparclinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32_sparc)
+               echo "${UNAME_MACHINE}-unknown-linux-gnu"
+               exit 0
+               ;;
+         armlinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32arm*)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuoldld"
+               exit 0
+               ;;
+         armelf_linux*)
+               echo "${UNAME_MACHINE}-unknown-linux-gnu"
+               exit 0
+               ;;
+         m68klinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32ppc | elf32ppclinux)
+               # Determine Lib Version
+               cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unkown\n");
+#endif
+  return 0;
+}
+EOF
+               LIBC=""
+               $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       ./$dummy | grep 1\.99 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi
+               rm -f $dummy.c $dummy
+               echo powerpc-unknown-linux-gnu${LIBC}
+               exit 0
+               ;;
+         shelf_linux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnu"
+               exit 0
+               ;;
+       esac
+
+       if test "${UNAME_MACHINE}" = "alpha" ; then
+               cat <<EOF >$dummy.s
+                       .data
+               \$Lformat:
+                       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+                       .text
+                       .globl main
+                       .align 4
+                       .ent main
+               main:
+                       .frame \$30,16,\$26,0
+                       ldgp \$29,0(\$27)
+                       .prologue 1
+                       .long 0x47e03d80 # implver \$0
+                       lda \$2,-1
+                       .long 0x47e20c21 # amask \$2,\$1
+                       lda \$16,\$Lformat
+                       mov \$0,\$17
+                       not \$1,\$18
+                       jsr \$26,printf
+                       ldgp \$29,0(\$26)
+                       mov 0,\$16
+                       jsr \$26,exit
+                       .end main
+EOF
+               LIBC=""
+               $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+                       esac
+
+                       objdump --private-headers $dummy | \
+                         grep ld.so.1 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi
+               rm -f $dummy.s $dummy
+               echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+       elif test "${UNAME_MACHINE}" = "mips" ; then
+         cat >$dummy.c <<EOF
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       elif test "${UNAME_MACHINE}" = "s390"; then
+         echo s390-ibm-linux && exit 0
+       elif test "${UNAME_MACHINE}" = "x86_64"; then
+         echo x86_64-unknown-linux-gnu && exit 0
+       elif test "${UNAME_MACHINE}" = "parisc" -o "${UNAME_MACHINE}" = "hppa"; then
+         # Look for CPU level
+         case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+           PA7*)
+               echo hppa1.1-unknown-linux-gnu
+               ;;
+           PA8*)
+               echo hppa2.0-unknown-linux-gnu
+               ;;
+           *)
+               echo hppa-unknown-linux-gnu
+               ;;
+         esac
+         exit 0
+       else
+         # Either a pre-BFD a.out linker (linux-gnuoldld)
+         # or one that does not give us useful --help.
+         # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+         # If ld does not provide *any* "supported emulations:"
+         # that means it is gnuoldld.
+         test -z "$ld_supported_emulations" \
+           && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+         case "${UNAME_MACHINE}" in
+         i?86)
+           VENDOR=pc;
+           ;;
+         *)
+           VENDOR=unknown;
+           ;;
+         esac
+         # Determine whether the default compiler is a.out or elf
+         cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+         test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i?86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i?86:*:5:7*)
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+       else
+           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i?86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i?86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       if test "${UNAME_MACHINE}" = "x86pc"; then
+               UNAME_MACHINE=pc
+       fi
+       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[KW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+The $version version of this script cannot recognize your system type.
+Please download the most up to date version of the config scripts:
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess version = $version
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "version='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..4c5dbea
--- /dev/null
@@ -0,0 +1,367 @@
+/* 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
+
+/* 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/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..004c7de
--- /dev/null
@@ -0,0 +1,1332 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+#   Free Software Foundation, Inc.
+
+version='2000-11-10'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help               print this help, then exit
+  -V, --version            print version number, then exit"
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case "$1" in
+    --version | --vers* | -V )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       exec >&2
+       echo "$me: invalid option $1"
+       echo "$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | storm-chaos*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+               | arme[lb] | armv[2345] | armv[345][lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 \
+               | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \
+               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+               | hppa64 \
+               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+               | alphaev6[78] \
+               | we32k | ns16k | clipper | i370 | sh | sh[34] \
+               | powerpc | powerpcle \
+               | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
+               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+               | mips64vr5000 | miprs64vr5000el | mcore \
+               | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+               | thumb | d10v | d30v | fr30 | avr)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i[234567]86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       # FIXME: clean up the formatting here.
+       vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+             | xmp-* | ymp-* \
+             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+             | hppa2.0n-* | hppa64-* \
+             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+             | alphaev6[78]-* \
+             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+             | clipper-* | orion-* \
+             | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+             | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* \
+             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+             | mipstx39-* | mipstx39el-* | mcore-* \
+             | f301-* | armv*-* | s390-* | sv1-* | t3e-* \
+             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+             | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \
+             | bs2000-* | tic54x-* | c54x-* | x86_64-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [ctj]90-cray)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i[34567]86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i[34567]86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i[34567]86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i[34567]86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       i386-go32 | go32)
+               basic_machine=i386-unknown
+               os=-go32
+               ;;
+       i386-mingw32 | mingw32)
+               basic_machine=i386-unknown
+               os=-mingw32
+               ;;
+       i[34567]86-pw32 | pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       msdos)
+               basic_machine=i386-unknown
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i686-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=rs6000-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=t3e-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv9)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* | -storm-chaos*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i[34567]86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto*)
+               os=-nto-qnx
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+        -*mint | -*MiNT)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f301-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -*MiNT)
+                               vendor=atari
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "version='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..b1b3213
--- /dev/null
+++ b/configure
@@ -0,0 +1,8114 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.54.
+#
+# 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.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_NUMERIC LC_MESSAGES LC_TIME
+do
+  if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)$' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+         /^X\/\(\/\/\)$/{ s//\1/; q; }
+         /^X\/\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conftest.sh
+  echo  "exit 0"   >>conftest.sh
+  chmod +x conftest.sh
+  if (PATH="/nonexistent;."; 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
+            $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+            $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+            CONFIG_SHELL=$as_dir/$as_base
+            export CONFIG_SHELL
+            exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+          fi;;
+        esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='     ' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  as_mkdir_p=false
+fi
+
+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
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete.  It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="lib/zebra.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <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"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM AWK SET_MAKE build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP AR ac_ct_AR RANLIB ac_ct_RANLIB EGREP MULTIPATH_NUM LIBPAM RT_METHOD KERNEL_METHOD OTHER_METHOD RTREAD_METHOD IF_METHOD IF_PROC IPFORWARD LIB_IPV6 ZEBRA BGPD RIPD RIPNGD OSPFD OSPF6D VTYSH INCLUDES CURSES LIB_REGEX LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_option in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval "enable_$ac_feature=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_$ac_feature='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_$ac_package='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/-/_/g'`
+    eval "with_$ac_package=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+    eval "$ac_envvar='$ac_optarg'"
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+              localstatedir libdir includedir oldincludedir infodir mandir
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+         X"$0" : 'X\(//\)[^/]' \| \
+         X"$0" : 'X\(//\)$' \| \
+         X"$0" : 'X\(/\)' \| \
+         .     : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+   { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+  cat <<_ACEOF
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --infodir=DIR          info documentation [PREFIX/info]
+  --mandir=DIR           man documentation [PREFIX/man]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-dependency-tracking Speeds up one-time builds
+  --enable-dependency-tracking  Do not reject slow dependency extractors
+  --enable-vtysh,       Make integrated VTY version of zebra
+  --disable-ipv6          turn off IPv6 related features and daemons
+  --disable-zebra         do not build zebra daemon
+  --disable-bgpd          do not build bgpd
+  --disable-ripd          do not build ripd
+  --disable-ripngd        do not build ripngd
+  --disable-ospfd         do not build ospfd
+  --disable-ospf6d        do not build ospf6d
+  --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.54.  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
+  ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+  # Get rid of the leading space.
+  ac_sep=" "
+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
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=$`echo $ac_var`
+      echo "$ac_var='"'"'$ac_val'"'"'"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=$`echo $ac_var`
+        echo "$ac_var='"'"'$ac_val'"'"'"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      sed "/^$/d" confdefs.h | sort
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core core.* *.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.7"
+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
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE=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.
+
+
+
+          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
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CC" && break
+done
+
+  CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&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"
+
+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 a_out.exe a.exe conftest.exe a.out conftest a.* conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    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
+check \`config.log' for details." >&5
+echo "$as_me: error: C compiler cannot create executables
+check \`config.log' for details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&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 conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+          export ac_cv_exeext
+          break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&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"
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+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"
+
+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"
+
+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
+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;
+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
+
+# 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
+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
+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 | grep -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$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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 egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+
+echo "$as_me:$LINENO: checking for AIX" >&5
+echo $ECHO_N "checking for AIX... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#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-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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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 gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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 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"
+
+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
+
+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"
+
+
+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"
+
+
+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"
+
+
+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 ();
+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 ();
+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"
+
+
+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 ();
+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 ();
+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"
+
+
+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=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  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 ();
+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 ();
+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 ();
+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 ();
+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) ();
+
+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) ();
+
+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 ();
+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 gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+  fi
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking route read method check" >&5
+echo $ECHO_N "checking route read method check... $ECHO_C" >&6
+if test "${zebra_rtread+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$netlink" = yes; then
+  RTREAD_METHOD="rtread_netlink.o"
+  zebra_rtread="netlink"
+else
+for zebra_rtread in /proc/net/route /dev/ip /dev/null;
+do
+  test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break
+done
+case $zebra_rtread in
+  "/proc/net/route") RTREAD_METHOD="rtread_proc.o"
+                     zebra_rtread="proc";;
+  "/dev/ip")         RTREAD_METHOD="rtread_getmsg.o"
+                     zebra_rtread="getmsg";;
+  *)                 RTREAD_METHOD="rtread_sysctl.o"
+                     zebra_rtread="sysctl";;
+esac
+fi
+fi
+echo "$as_me:$LINENO: result: $zebra_rtread" >&5
+echo "${ECHO_T}$zebra_rtread" >&6
+
+
+echo "$as_me:$LINENO: checking interface looking up method" >&5
+echo $ECHO_N "checking interface looking up method... $ECHO_C" >&6
+if test "$netlink" = yes; then
+  echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+  IF_METHOD=if_netlink.o
+else
+  if test "$opsys" = "sol2-6";then
+    echo "$as_me:$LINENO: result: solaris" >&5
+echo "${ECHO_T}solaris" >&6
+    IF_METHOD=if_ioctl.o
+  elif test "$opsys" = "openbsd";then
+    echo "$as_me:$LINENO: result: openbsd" >&5
+echo "${ECHO_T}openbsd" >&6
+    IF_METHOD=if_ioctl.o
+  elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
+    echo "$as_me:$LINENO: result: sysctl" >&5
+echo "${ECHO_T}sysctl" >&6
+    IF_METHOD=if_sysctl.o
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_NET_RT_IFLIST 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) ();
+
+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
+
+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 ();
+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 ();
+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 ();
+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 ();
+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"
+
+
+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) ();
+
+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) ();
+
+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) ();
+
+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 ();
+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 ();
+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"
+
+
+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 ();
+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 ();
+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 ();
+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>
+
+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>
+
+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>
+
+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>
+
+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>
+
+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>
+
+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>
+
+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
+
+
+
+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
+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 vtysh/Makefile doc/Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+  (set) 2>&1 |
+    case `(ac_space=' '; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+        "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;;
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n \
+        "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} |
+  sed '
+     t clear
+     : clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     : end' >>confcache
+if 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
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_i=`echo "$ac_i" |
+         sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+  # 2. Add them.
+  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" 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=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_NUMERIC LC_MESSAGES LC_TIME
+do
+  if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)$' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+         /^X\/\(\/\/\)$/{ s//\1/; q; }
+         /^X\/\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conftest.sh
+  echo  "exit 0"   >>conftest.sh
+  chmod +x conftest.sh
+  if (PATH="/nonexistent;."; 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
+            $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+            $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+            CONFIG_SHELL=$as_dir/$as_base
+            export CONFIG_SHELL
+            exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+          fi;;
+        esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='     ' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  as_mkdir_p=false
+fi
+
+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
+
+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.54.  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.54,
+  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[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  -*)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_option=$1
+     ac_need_defaults=false;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    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 )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+
+  # 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" ;;
+  "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,@CYGPATH_W@,$CYGPATH_W,;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,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s,@CPP@,$CPP,;t t
+s,@AR@,$AR,;t t
+s,@ac_ct_AR@,$ac_ct_AR,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@EGREP@,$EGREP,;t t
+s,@MULTIPATH_NUM@,$MULTIPATH_NUM,;t t
+s,@LIBPAM@,$LIBPAM,;t t
+s,@RT_METHOD@,$RT_METHOD,;t t
+s,@KERNEL_METHOD@,$KERNEL_METHOD,;t t
+s,@OTHER_METHOD@,$OTHER_METHOD,;t t
+s,@RTREAD_METHOD@,$RTREAD_METHOD,;t t
+s,@IF_METHOD@,$IF_METHOD,;t t
+s,@IF_PROC@,$IF_PROC,;t t
+s,@IPFORWARD@,$IPFORWARD,;t t
+s,@LIB_IPV6@,$LIB_IPV6,;t t
+s,@ZEBRA@,$ZEBRA,;t t
+s,@BGPD@,$BGPD,;t t
+s,@RIPD@,$RIPD,;t t
+s,@RIPNGD@,$RIPNGD,;t t
+s,@OSPFD@,$OSPFD,;t t
+s,@OSPF6D@,$OSPF6D,;t t
+s,@VTYSH@,$VTYSH,;t t
+s,@INCLUDES@,$INCLUDES,;t t
+s,@CURSES@,$CURSES,;t t
+s,@LIB_REGEX@,$LIB_REGEX,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+  cat >>$CONFIG_STATUS <<\_ACEOF
+  # Split the substitutions into bite-sized pieces for seds with
+  # small command number limits, like on Digital OSF/1 and HP-UX.
+  ac_max_sed_lines=48
+  ac_sed_frag=1 # Number of current file.
+  ac_beg=1 # First line for current file.
+  ac_end=$ac_max_sed_lines # Line after last line for current file.
+  ac_more_lines=:
+  ac_sed_cmds=
+  while $ac_more_lines; do
+    if test $ac_beg -gt 1; then
+      sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    else
+      sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    fi
+    if test ! -s $tmp/subs.frag; then
+      ac_more_lines=false
+    else
+      # The purpose of the label and of the branching condition is to
+      # speed up the sed processing (if there are no `@' at all, there
+      # is no need to browse any of the substitutions).
+      # These are the two extra sed commands mentioned above.
+      (echo ':t
+  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+      if test -z "$ac_sed_cmds"; then
+       ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+      else
+       ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+      fi
+      ac_sed_frag=`expr $ac_sed_frag + 1`
+      ac_beg=$ac_end
+      ac_end=`expr $ac_end + $ac_max_sed_lines`
+    fi
+  done
+  if test -z "$ac_sed_cmds"; then
+    ac_sed_cmds=cat
+  fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+        cat >$tmp/stdin
+        ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+        ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+        ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+  ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+         X"$ac_file" : 'X\(//\)[^/]' \| \
+         X"$ac_file" : 'X\(//\)$' \| \
+         X"$ac_file" : 'X\(/\)' \| \
+         .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+  { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+         X"$as_dir" : 'X\(//\)[^/]' \| \
+         X"$as_dir" : 'X\(//\)$' \| \
+         X"$as_dir" : 'X\(/\)' \| \
+         .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+  ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# 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 grep "^[    ]*#[    ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<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 # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<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'`
+      { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+         X"$as_dir" : 'X\(//\)[^/]' \| \
+         X"$as_dir" : 'X\(//\)$' \| \
+         X"$as_dir" : 'X\(/\)' \| \
+         .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  fi
+_am_stamp_count=`expr ${_am_stamp_count-0} + 1`
+echo "timestamp for $ac_file" >`(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'`/stamp-h$_am_stamp_count
+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'`
+    { if $as_mkdir_p; then
+    mkdir -p $dirpart/$fdir
+  else
+    as_dir=$dirpart/$fdir
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+         X"$as_dir" : 'X\(//\)[^/]' \| \
+         X"$as_dir" : 'X\(//\)$' \| \
+         X"$as_dir" : 'X\(/\)' \| \
+         .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+    # echo "creating $dirpart/$file"
+    echo '# dummy' > "$dirpart/$file"
+  done
+done
+ ;;
+  esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  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/configure.in b/configure.in
new file mode 100755 (executable)
index 0000000..bee8296
--- /dev/null
@@ -0,0 +1,873 @@
+##
+## 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(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
+
+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(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")
+
+
+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 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/depcomp b/depcomp
new file mode 100755 (executable)
index 0000000..807b991
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,423 @@
+#! /bin/sh
+
+# depcomp - compile a program generating dependencies as side-effects
+# Copyright 1999, 2000 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+# `libtool' can also be set to `yes' or `no'.
+
+if test -z "$depfile"; then
+   base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'`
+   dir=`echo "$object" | sed 's,/.*$,/,'`
+   if test "$dir" = "$object"; then
+      dir=
+   fi
+   # FIXME: should be _deps on DOS.
+   depfile="$dir.deps/$base"
+fi
+
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+  "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'.  On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like `#:fec' to the end of the
+    # dependency line.
+    tr ' ' '
+' < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr '
+' ' ' >> $depfile
+    echo >> $depfile
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' '
+' < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> $depfile
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  This file always lives in the current directory.
+  # Also, the AIX compiler puts `$object:' at the start of each line;
+  # $object doesn't have directory information.
+  stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
+  tmpdepfile="$stripped.u"
+  outname="$stripped.o"
+  if test "$libtool" = yes; then
+    "$@" -Wc,-M
+  else
+    "$@" -M
+  fi
+
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form `foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # `$object: dependent.h' and one to simply `dependent.h:'.
+    sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+    sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in `foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      tmpdepfile1="$dir.libs/$base.lo.d"
+      tmpdepfile2="$dir.libs/$base.d"
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1="$dir$base.o.d"
+      tmpdepfile2="$dir$base.d"
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2"
+      exit $stat
+   fi
+
+   if test -f "$tmpdepfile1"; then
+      tmpdepfile="$tmpdepfile1"
+   else
+      tmpdepfile="$tmpdepfile2"
+   fi
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      # That's a space and a tab in the [].
+      sed -e 's,^.*\.[a-z]*:[  ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the proprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.  We will use -o /dev/null later,
+  # however we can't do the remplacement now because
+  # `-o $object' might simply not be used
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  "$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[      ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # X makedepend
+  shift
+  cleared=no
+  for arg in "$@"; do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    -*)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix="`echo $object | sed 's/^.*\././'`"
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the proprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the proprocessed file to stdout, regardless of -o,
+  # because we must use -o when running libtool.
+  "$@" || exit $?
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+       set fnord "$@"
+       shift
+       shift
+       ;;
+    *)
+       set fnord "$@" "$arg"
+       shift
+       shift
+       ;;
+    esac
+  done
+  "$@" -E |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::   \1 \\:p' >> "$depfile"
+  echo "       " >> "$depfile"
+  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644 (file)
index 0000000..2916b2f
--- /dev/null
@@ -0,0 +1,3 @@
+Makefile
+draft-zebra-00.txt
+zebra.info-*
diff --git a/doc/BGP-TypeCode b/doc/BGP-TypeCode
new file mode 100644 (file)
index 0000000..0904e19
--- /dev/null
@@ -0,0 +1,24 @@
+
+                BGP-4[+] UPDATE Attribute TypeCode list
+
+  Value  Attribute            References
+=========================================================================
+    1    ORIGIN               [RFC 1771]
+    2    AS_PATH              [RFC 1771]
+    3    NEXT_HOP             [RFC 1771]
+    4    MULTI_EXIT_DISC      [RFC 1771]
+    5    LOCAL_PREF           [RFC 1771]
+    6    ATOMIC_AGGREGATE     [RFC 1771]
+    7    AGGREGATOR           [RFC 1771]
+    8    COMMUNITIES          [RFC 1997]
+    9    ORIGINATOR_ID        [RFC 1966]
+   10    CLUSTER_LIST         [RFC 1966]
+   11    DPA                  [draft-ietf-idr-bgp-dpa-05.txt(expired)]
+   12    ADVERTISER           [Changed from RFC 1863 bgp@ans.net ML?]
+   13    RCID_PATH            [Changed from RFC 1863 bgp@ans.net ML?]
+   14    MP_REACH_NLRI        [RFC 2283]
+   15    MP_UNREACH_NLRI      [RFC 2283]
+   16    EXT_COMMUNITIES      [draft-ramachandra-bgp-ext-communities-09.txt]
+  254    RCID_PATH            [RFC 1863]
+  255    ADVERTISER           [RFC 1863]
+=========================================================================
diff --git a/doc/ChangeLog b/doc/ChangeLog
new file mode 100644 (file)
index 0000000..cfe6e0e
--- /dev/null
@@ -0,0 +1,90 @@
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2001-02-07  Pekka Savola <pekkas@netcore.fi>
+
+       * Correct bad English ;-).
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 released.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 released.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 released.
+
+2000-10-02  Horms <horms@vergenet.net>
+
+       * Makefile.am: Fix texinfo file installation problem.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 released.
+
+       * ospfd.texi (Redistribute routes to OSPF): distance <1-255>
+       @var{source} command is temporary disabled.  So it is removed from
+       document.
+
+2000-07-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.1: Add man entry for vtysh.
+
+       * bgpd.1: Change section to 8.
+       * ospfd.1: Likewise.
+       * ospf6d.1: Likewise.
+       * ripd.1: Likewise.
+       * ripngd.1: Likewise.
+       * zebra.1: Likewise.
+
+1999-09-01  "A.Waddington" <waddington@usa.net>
+
+       * zebra.texi: Replace @command with @code until it gets ready.
+       Remove @macro.
+
+1999-08-26  Andrew Waddington <waddington@usa.net>
+
+       * bgpd.1: Add man page.
+       ospf6d.1: Likewise.
+       ospfd.1: Likewise.
+       ripd.1: Likewise.
+       ripngd.1: Likewise.
+       zebra.1: Likewise.
+
+1999-08-14  Andrew Waddington <waddington@usa.net>
+
+       * zebra.texi: Many typo is fixed.  Some grammatical rectifications
+       is made.
+
+1999-07-27  Gerhard Poul <gpoul@gnu.org>
+
+       * zebra.texi: Update zebra.texi.
+
+1999-07-02  Gerhard Poul <gpoul@gnu.org>
+
+       * draft-zebra-00.ms: New file added.  This is groff version of
+       draft-zebra-00.txt.  This is a master file of draft-zebra-00.txt.
+
+       * draft-zebra-00.txt: Generated from draft-zebra-00.txt.
+
+1999-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.texi (Top): Add ospf6d chapter.
+
+1999-03-31  Jeroen Ruigrok/Asmodai <asmodai@wxs.nl>
+
+       * zebra.texi: Improve some sections.
+
+1999-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * archfig.tex, zebra.sty, zebra.tex: Temporary removed due to the
+       description is out of date.
+
+1999-02-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * texinfo.tex: New file added.  Automake complains the absence of
+       texinfo.tex.
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..ee49cbd
--- /dev/null
@@ -0,0 +1,14 @@
+## Process this file with automake to produce Makefile.in.
+
+info_TEXINFOS = zebra.texi
+
+zebra_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \
+       ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \
+       protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi vtysh.texi
+
+man_MANS = vtysh.1 bgpd.8 ospf6d.8 ospfd.8 ripd.8 ripngd.8 zebra.8
+
+EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt $(man_MANS) 
+
+draft-zebra-00.txt:
+       groff -T ascii -ms draft-zebra-00.ms > draft-zebra-00.txt
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..66e35ec
--- /dev/null
@@ -0,0 +1,482 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+INCLUDES = @INCLUDES@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+
+info_TEXINFOS = zebra.texi
+
+zebra_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \
+       ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \
+       protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi vtysh.texi
+
+
+man_MANS = vtysh.1 bgpd.8 ospf6d.8 ospfd.8 ripd.8 ripngd.8 zebra.8
+
+EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt $(man_MANS) 
+subdir = doc
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+DIST_SOURCES =
+am__TEXINFO_TEX_DIR = $(srcdir)
+INFO_DEPS = zebra.info
+DVIS = zebra.dvi
+PDFS = zebra.pdf
+PSS = zebra.ps
+TEXINFOS = zebra.texi
+
+NROFF = nroff
+MANS = $(man_MANS)
+DIST_COMMON = $(zebra_TEXINFOS) ChangeLog Makefile.am Makefile.in \
+       texinfo.tex
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .dvi .info .pdf .ps .texi
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  doc/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+.texi.info:
+       @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+       $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+       `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+
+.texi.dvi:
+       TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+       MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+       $(TEXI2DVI) `test -f '$<' || echo '$(srcdir)/'`$<
+
+.texi.pdf:
+       TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+       MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+       $(TEXI2PDF) `test -f '$<' || echo '$(srcdir)/'`$<
+zebra.info: zebra.texi $(zebra_TEXINFOS)
+zebra.dvi: zebra.texi $(zebra_TEXINFOS)
+zebra.pdf: zebra.texi $(zebra_TEXINFOS)
+TEXI2DVI = texi2dvi
+
+TEXI2PDF = $(TEXI2DVI) --pdf --batch
+DVIPS = dvips
+.dvi.ps:
+       $(DVIPS) $< -o $@
+
+uninstall-info-am:
+       $(PRE_UNINSTALL)
+       @if (install-info --version && \
+            install-info --version | grep -i -v debian) >/dev/null 2>&1; then \
+         list='$(INFO_DEPS)'; \
+         for file in $$list; do \
+           echo " install-info --info-dir=$(DESTDIR)$(infodir) --remove $(DESTDIR)$(infodir)/$$file"; \
+           install-info --info-dir=$(DESTDIR)$(infodir) --remove $(DESTDIR)$(infodir)/$$file; \
+         done; \
+       else :; fi
+       @$(NORMAL_UNINSTALL)
+       @list='$(INFO_DEPS)'; \
+       for file in $$list; do \
+         (if cd $(DESTDIR)$(infodir); then \
+            echo " rm -f $$file $$file-[0-9] $$file-[0-9][0-9])"; \
+            rm -f $$file $$file-[0-9] $$file-[0-9][0-9]; \
+          else :; fi); \
+       done
+
+dist-info: $(INFO_DEPS)
+       list='$(INFO_DEPS)'; \
+       for base in $$list; do \
+         if test -f $$base; then d=.; else d=$(srcdir); fi; \
+         for file in $$d/$$base*; do \
+           relfile=`expr "$$file" : "$$d/\(.*\)"`; \
+           test -f $(distdir)/$$relfile || \
+             cp -p $$file $(distdir)/$$relfile; \
+         done; \
+       done
+
+mostlyclean-aminfo:
+       -rm -f zebra.aux zebra.cp zebra.cps zebra.fn zebra.ky zebra.log zebra.op \
+         zebra.pg zebra.tmp zebra.toc zebra.tp zebra.vr zebra.dvi \
+         zebra.pdf zebra.ps
+
+maintainer-clean-aminfo:
+       list='$(INFO_DEPS)'; for i in $$list; do \
+         rm -f $$i; \
+         if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \
+           rm -f $$i-[0-9]*; \
+         fi; \
+       done
+
+man1dir = $(mandir)/man1
+install-man1: $(man1_MANS) $(man_MANS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(man1dir)
+       @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+       for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         case "$$ext" in \
+           1*) ;; \
+           *) ext='1' ;; \
+         esac; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed -e 's/^.*\///'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
+       done
+uninstall-man1:
+       @$(NORMAL_UNINSTALL)
+       @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+       for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed -e 's/^.*\///'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man1dir)/$$inst; \
+       done
+
+man8dir = $(mandir)/man8
+install-man8: $(man8_MANS) $(man_MANS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(man8dir)
+       @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+       for i in $$l2; do \
+         case "$$i" in \
+           *.8*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         case "$$ext" in \
+           8*) ;; \
+           *) ext='8' ;; \
+         esac; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed -e 's/^.*\///'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+       done
+uninstall-man8:
+       @$(NORMAL_UNINSTALL)
+       @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+       for i in $$l2; do \
+         case "$$i" in \
+           *.8*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed -e 's/^.*\///'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man8dir)/$$inst; \
+       done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+           dir="/$$dir"; \
+           $(mkinstalldirs) "$(distdir)$$dir"; \
+         else \
+           dir=''; \
+         fi; \
+         if test -d $$d/$$file; then \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-info
+check-am: all-am
+check: check-am
+all-am: Makefile $(INFO_DEPS) $(MANS)
+
+installdirs:
+       $(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(man1dir) $(DESTDIR)$(man8dir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am: $(DVIS)
+
+info: info-am
+
+info-am: $(INFO_DEPS)
+
+install-data-am: install-info-am install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-info-am: $(INFO_DEPS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(infodir)
+       @list='$(INFO_DEPS)'; \
+       for file in $$list; do \
+         if test -f $$file; then d=.; else d=$(srcdir); fi; \
+         for ifile in echo $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9]; do \
+           if test -f $$ifile; then \
+             relfile=`expr "$$ifile" : "$$d/\(.*\)"`; \
+             echo " $(INSTALL_DATA) $$ifile $(DESTDIR)$(infodir)/$$relfile"; \
+             $(INSTALL_DATA) $$ifile $(DESTDIR)$(infodir)/$$relfile; \
+           else : ; fi; \
+         done; \
+       done
+       @$(POST_INSTALL)
+       @if (install-info --version && \
+            install-info --version | grep -i -v debian) >/dev/null 2>&1; then \
+         list='$(INFO_DEPS)'; \
+         for file in $$list; do \
+           echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\
+           install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\
+         done; \
+       else : ; fi
+install-man: install-man1 install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-aminfo \
+       maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-aminfo mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am: $(PDFS)
+
+ps: ps-am
+
+ps-am: $(PSS)
+
+uninstall-am: uninstall-info-am uninstall-man
+
+uninstall-man: uninstall-man1 uninstall-man8
+
+.PHONY: all all-am check check-am clean clean-generic dist-info \
+       distclean distclean-generic distdir dvi dvi-am info info-am \
+       install install-am install-data install-data-am install-exec \
+       install-exec-am install-info install-info-am install-man \
+       install-man1 install-man8 install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-aminfo maintainer-clean-generic mostlyclean \
+       mostlyclean-aminfo mostlyclean-generic pdf pdf-am ps ps-am \
+       uninstall uninstall-am uninstall-info-am uninstall-man \
+       uninstall-man1 uninstall-man8
+
+
+draft-zebra-00.txt:
+       groff -T ascii -ms draft-zebra-00.ms > draft-zebra-00.txt
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/appendix.texi b/doc/appendix.texi
new file mode 100644 (file)
index 0000000..7a052bc
--- /dev/null
@@ -0,0 +1,238 @@
+@node  Packet Binary Dump Format, , Zebra Protocol, Top
+@comment  node-name,  next,  previous,  up
+@appendix Packet Binary Dump Format
+
+  Zebra can dump routing protocol packet into file with a binary format
+(@pxref{Dump BGP packets and table}).
+
+  It seems to be better that we share the MRT's header format for
+backward compatibility with MRT's dump logs. We should also define the
+binary format excluding the header, because we must support both IP
+v4 and v6 addresses as socket addresses and / or routing entries.
+
+  In the last meeting, we discussed to have a version field in the
+header. But Masaki told us that we can define new `type' value rather
+than having a `version' field, and it seems to be better because we
+don't need to change header format.
+
+  Here is the common header format. This is same as that of MRT.
+
+@example
+@group
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                              Time                             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|             Type              |            Subtype            |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                             Length                            |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+  If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and
+Address Family == IP (version 4)
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Source AS number       |     Destination AS number     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Interface Index        |      Address Family           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address                    |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|            Old State          |           New State           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+Where State is the value defined in RFC1771.
+
+If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE,
+and Address Family == IP version 6
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Source AS number       |     Destination AS number     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Interface Index        |      Address Family           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address (Cont'd)             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address (Cont'd)             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address (Cont'd)             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address                    |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address (Cont'd)           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address (Cont'd)           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address (Cont'd)           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|            Old State          |           New State           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE,
+and Address Family == IP (version 4)
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Source AS number       |     Destination AS number     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Interface Index        |      Address Family           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address                    |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                       BGP Message Packet                      |
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+Where BGP Message Packet is the whole contents of the
+BGP4 message including header portion.
+
+If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE,
+and Address Family == IP version 6
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Source AS number       |     Destination AS number     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Interface Index        |      Address Family           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address (Cont'd)             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address (Cont'd)             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Source IP address (Cont'd)             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address                    |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address (Cont'd)           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address (Cont'd)           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                     Destination IP address (Cont'd)           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                       BGP Message Packet                      |
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY,
+and Address Family == IP (version 4)
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|            View #             |            Status             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Time Last Change                       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Address Family          |    SAFI       | Next-Hop-Len  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Next Hop Address                       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Prefix Length |             Address Prefix [variable]         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Attribute Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      BGP Attribute [variable length]                         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY,
+and Address Family == IP version 6
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|            View #             |            Status             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Time Last Change                       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Address Family          |    SAFI       | Next-Hop-Len  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Next Hop Address                       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Next Hop Address (Cont'd)              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Next Hop Address (Cont'd)              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Next Hop Address (Cont'd)              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Prefix Length |             Address Prefix [variable]         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Address Prefix (cont'd) [variable]        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Attribute Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      BGP Attribute [variable length]                             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+       BGP4 Attribute must not contain MP_UNREACH_NLRI.
+       If BGP Attribute has MP_REACH_NLRI field, it must has
+       zero length NLRI, e.g., MP_REACH_NLRI has only Address
+       Family, SAFI and next-hop values.
+
+If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT,
+
+@example
+@group
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|           View #              |       File Name [variable]    |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+    The file specified in "File Name" contains all routing entries,
+    which are in the format of ``subtype == BGP4MP_ENTRY''.
+
+@example
+@group
+Constants:
+  /* type value */
+  #define MSG_PROTOCOL_BGP4MP 16
+  /* subtype value */
+  #define BGP4MP_STATE_CHANGE 0
+  #define BGP4MP_MESSAGE 1
+  #define BGP4MP_ENTRY 2
+  #define BGP4MP_SNAPSHOT 3
+@end group
+@end example
diff --git a/doc/basic.texi b/doc/basic.texi
new file mode 100644 (file)
index 0000000..8812b78
--- /dev/null
@@ -0,0 +1,510 @@
+@node Basic commands
+@comment  node-name,  next,  previous,  up
+@chapter Basic commands
+
+There are five routing daemons in use, and there is one manager daemon.
+These daemons may be located on separate machines from the manager
+daemon.  Each of these daemons will listen on a particular port for
+incoming VTY connections.  The routing daemons are:
+
+@itemize @bullet
+@item @command{ripd}, @command{ripngd}, @command{ospfd}, @command{ospf6d}, @command{bgpd}
+@item @command{zebra}
+@end itemize
+
+The following sections discuss commands common to all the routing
+daemons.
+
+@menu
+* Config Commands::             Commands used in config files
+* Common Invocation Options::   Starting the daemons
+* Virtual Terminal Interfaces::  Interacting with the daemons
+@end menu
+
+
+
+@node Config Commands, Common Invocation Options, Basic commands, Basic commands
+@comment  node-name,  next,  previous,  up
+@section Config Commands
+
+@cindex Configuration files for running the software
+@c A -not configuration files for installing the software
+@cindex Files for running configurations
+@cindex Modifying the herd's behavior
+@cindex Getting the herd running
+
+
+@menu
+* Basic Config Commands::       Some of the generic config commands
+* Sample Config File::          An example config file
+@end menu
+
+
+In a config file, you can write the debugging options, a vty's password,
+routing daemon configurations, a log file name, and so forth. This
+information forms the initial command set for a routing beast as it is
+starting.
+
+Config files are generally found in:
+
+@itemize @asis
+@item @file{@value{INSTALL_PREFIX_ETC}/*.conf}
+@end itemize
+
+Each of the daemons has its own
+config file.  For example, zebra's default config file name is:
+
+@itemize @asis
+@item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf}
+@end itemize
+
+The daemon name plus @file{.conf} is the default config file name. You
+can specify a config file using the @kbd{-f} or @kbd{--config-file}
+options when starting the daemon.
+
+
+
+@node Basic Config Commands, Sample Config File, Config Commands, Config Commands
+@comment  node-name,  next,  previous,  up
+@subsection Basic Config Commands
+
+@deffn Command {hostname @var{hostname}} {}
+Set hostname of the router.
+@end deffn
+
+@deffn Command {password @var{password}} {}
+Set password for vty interface.  If there is no password, a vty won't
+accept connections.
+@end deffn
+
+@deffn Command {enable password @var{password}} {}
+Set enable password.
+@end deffn
+
+@deffn Command {log stdout} {}
+@deffnx Command {no log stdout} {}
+Set logging output to stdout.
+@end deffn
+
+@deffn Command {log file @var{filename}} {}
+If you want to log into a file please specify @code{filename} as
+follows.
+@example
+log file /usr/local/etc/bgpd.log
+@end example
+@end deffn
+
+@deffn Command {log syslog} {}
+@deffnx Command {no log syslog} {}
+Set logging output to syslog.
+@end deffn
+
+@deffn Command {write terminal} {}
+Displays the current configuration to the vty interface.
+@end deffn
+
+@deffn Command {write file} {}
+Write current configuration to configuration file.
+@end deffn
+
+@deffn Command {configure terminal} {}
+Change to configuration mode.  This command is the first step to
+configuration.
+@end deffn
+
+@deffn Command {terminal length @var{<0-512>}} {}
+Set terminal display length to @var{<0-512>}.  If length is 0, no
+display control is performed.
+@end deffn
+
+@deffn Command {who} {}
+@end deffn
+
+@deffn Command {list} {}
+List commands.
+@end deffn
+
+@deffn Command {service password-encryption} {}
+Encrypt password.
+@end deffn
+
+@deffn Command {service advanced-vty} {}
+Enable advanced mode VTY.
+@end deffn
+
+@deffn Command {service terminal-length @var{<0-512>}} {}
+Set system wide line configuration.  This configuration command applies
+to all VTY interfaces.
+@end deffn
+
+@deffn Command {show version} {}
+Show the current version of the Zebra and its build host information.
+@end deffn
+
+@deffn Command {line vty} {}
+Enter vty configuration mode.
+@end deffn
+
+@deffn Command {banner motd default} {}
+Set default motd string.
+@end deffn
+
+@deffn Command {no banner motd} {}
+No motd banner string will be printed.
+@end deffn
+
+@deffn {Line Command} {exec-timeout @var{minute}} {}
+@deffnx {Line Command} {exec-timeout @var{minute} @var{second}} {}
+Set VTY connection timeout value.  When only one argument is specified
+it is used for timeout value in minutes.  Optional second argument is
+used for timeout value in seconds. Default timeout value is 10 minutes.
+When timeout value is zero, it means no timeout.
+@end deffn
+
+@deffn {Line Command} {no exec-timeout} {}
+Do not perform timeout at all.  This command is as same as
+@command{exec-timeout 0 0}.
+@end deffn
+
+@deffn {Line Command} {access-class @var{access-list}} {}
+Restrict vty connections with an access list.
+@end deffn
+
+
+
+@node   Sample Config File,  , Basic Config Commands, Config Commands
+@comment  node-name,  next,  previous,  up
+@subsection Sample Config File
+
+
+Below is a sample configuration file for the zebra daemon.
+
+@example
+@group
+!
+! Zebra configuration file
+!
+hostname Router
+password zebra
+enable password zebra
+!
+log stdout
+!
+!
+@end group
+@end example
+
+'!' and '#' are comment characters.  If the first character of the word
+is one of the comment characters then from the rest of the line forward
+will be ignored as a comment.
+
+@example
+password zebra!password
+@end example
+
+If a comment character is not the first character of the word, it's a
+normal character. So in the above example '!' will not be regarded as a
+comment and the password is set to 'zebra!password'.
+
+
+
+@node Common Invocation Options, Virtual Terminal Interfaces, Config Commands, Basic commands
+@comment  node-name,  next,  previous,  up
+@section Common Invocation Options
+@c COMMON_OPTIONS
+@c OPTIONS section of the man page
+
+These options apply to all Zebra daemons.
+
+@table @samp
+
+@item -d
+@itemx --daemon
+Runs in daemon mode.
+
+@item -f @var{file}
+@itemx --config_file=@var{file}
+Set configuration file name.
+
+@item -h
+@itemx --help
+Display this help and exit.
+
+@item -i @var{file}
+@itemx --pid_file=@var{file}
+
+Upon startup the process identifier of the daemon is written to a file,
+typically in @file{/var/run}.  This file can be used by the init system
+to implement commands such as @command{@dots{}/init.d/zebra status},
+@command{@dots{}/init.d/zebra restart} or @command{@dots{}/init.d/zebra
+stop}.
+
+The file name is an run-time option rather than a configure-time option
+so that multiple routing daemons can be run simultaneously.  This is
+useful when using Zebra to implement a routing looking glass.  One
+machine can be used to collect differing routing views from differing
+points in the network.
+
+@item -P @var{port}
+@itemx --vty_port=@var{port}
+Set the VTY port number.
+
+@item -v
+@itemx --version
+Print program version.
+
+@end table
+
+
+
+@node  Virtual Terminal Interfaces,  , Common Invocation Options, Basic commands
+@comment  node-name,  next,  previous,  up
+@section Virtual Terminal Interfaces
+
+VTY -- Virtual Terminal [aka TeletYpe] Interface is a command line
+interface (CLI) for user interaction with the routing daemon.
+
+@menu
+* VTY Overview::                Basics about VTYs                
+* VTY Modes::                   View, Enable, and Other VTY modes
+* VTY CLI Commands::            Commands for movement, edition, and management
+@end menu
+
+
+
+@node  VTY Overview, VTY Modes, Virtual Terminal Interfaces, Virtual Terminal Interfaces
+@comment  node-name,  next,  previous,  up
+@subsection VTY Overview
+
+
+VTY stands for Virtual TeletYpe interface.  It means you can connect to
+the daemon via the telnet protocol.
+
+To enable a VTY interface, you have to setup a VTY password.  If there
+is no VTY password, one cannot connect to the VTY interface at all.
+
+@example
+@group
+% telnet localhost 2601
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+
+Hello, this is zebra (version @value{VERSION})
+Copyright 1997-2000 Kunihiro Ishiguro
+
+
+User Access Verification
+
+Password: XXXXX
+Router> ?
+  enable            Turn on privileged commands
+  exit              Exit current mode and down to previous mode
+  help              Description of the interactive help system
+  list              Print command list
+  show              Show running system information
+  who               Display who is on a vty
+Router> enable
+Password: XXXXX
+Router# configure terminal
+Router(config)# interface eth0
+Router(config-if)# ip address 10.0.0.1/8
+Router(config-if)# ^Z
+Router#
+@end group
+@end example
+
+'?' is very useful for looking up commands.
+
+
+
+@node  VTY Modes, VTY CLI Commands, VTY Overview, Virtual Terminal Interfaces
+@comment  node-name,  next,  previous,  up
+@subsection VTY Modes
+
+
+There are three basic VTY modes:
+
+@menu
+* VTY View Mode::               Mode for read-only interaction               
+* VTY Enable Mode::             Mode for read-write interaction
+* VTY Other Modes::             Special modes (tftp, etc)
+@end menu
+
+There are commands that may be restricted to specific VTY modes. 
+
+
+
+@node VTY View Mode, VTY Enable Mode, VTY Modes, VTY Modes
+@comment  node-name,  next,  previous,  up
+@subsubsection VTY View Mode
+@c to be written (gpoul)
+
+
+This mode is for read-only access to the CLI. One may exit the mode by
+leaving the system, or by entering @code{enable} mode.
+
+
+
+@node VTY Enable Mode, VTY Other Modes, VTY View Mode, VTY Modes
+@comment  node-name,  next,  previous,  up
+@subsubsection VTY Enable Mode
+
+
+@c to be written (gpoul)
+This mode is for read-write access to the CLI. One may exit the mode by
+leaving the system, or by escaping to view mode.
+
+
+
+@node VTY Other Modes,  , VTY Enable Mode, VTY Modes
+@comment  node-name,  next,  previous,  up
+@subsubsection VTY Other Modes
+
+
+@c to be written (gpoul)
+This page is for describing other modes.
+
+@node VTY CLI Commands,  , VTY Modes, Virtual Terminal Interfaces
+@comment  node-name,  next,  previous,  up
+@subsection VTY CLI Commands
+
+
+Commands that you may use at the command-line are described in the following three subsubsections.
+
+@menu
+* CLI Movement Commands::       Commands for moving the cursor about
+* CLI Editing Commands::        Commands for changing text
+* CLI Advanced Commands::       Other commands, session management and so on
+@end menu
+
+
+
+@node CLI Movement Commands, CLI Editing Commands, VTY CLI Commands, VTY CLI Commands
+@comment  node-name,  next,  previous,  up
+@subsubsection CLI Movement Commands
+
+
+These commands are used for moving the CLI cursor. The @key{C} character
+means press the Control Key.
+
+@table @kbd
+
+@item C-f
+@itemx @key{RIGHT}
+@kindex C-f
+@kindex @key{RIGHT}
+Move forward one character.
+
+@item C-b
+@itemx @key{LEFT}
+@kindex C-b
+@kindex @key{LEFT}
+Move backward one character.
+
+@item M-f
+@kindex M-f
+Move forward one word.
+
+@item M-b
+@kindex M-b
+Move backward one word.
+
+@item C-a
+@kindex C-a
+Move to the beginning of the line.
+
+@item C-e
+@kindex C-e
+Move to the end of the line.
+
+@end table
+
+
+
+@node CLI Editing Commands, CLI Advanced Commands, CLI Movement Commands, VTY CLI Commands
+@comment  node-name,  next,  previous,  up
+@subsubsection CLI Editing Commands
+
+
+These commands are used for editing text on a line. The @key{C}
+character means press the Control Key.
+
+@table @kbd
+
+@item C-h
+@itemx @key{DEL}
+@kindex C-h
+@kindex @key{DEL}
+Delete the character before point.
+
+@item C-d
+@kindex C-d
+Delete the character after point.
+
+@item M-d
+@kindex M-d
+Forward kill word.
+
+@item C-w
+@kindex C-w
+Backward kill word.
+
+@item C-k
+@kindex C-k
+Kill to the end of the line.
+
+@item C-u
+@kindex C-u
+Kill line from the beginning, erasing input.
+
+@item C-t
+@kindex C-t
+Transpose character.
+
+@end table
+
+
+
+@node CLI Advanced Commands,  , CLI Editing Commands, VTY CLI Commands
+@comment  node-name,  next,  previous,  up
+@subsubsection CLI Advanced Commands
+
+
+There are several additional CLI commands for command line completions,
+insta-help, and VTY session management.
+
+@table @kbd
+
+@item C-c
+@kindex C-c
+Interrupt current input and moves to the next line.
+
+@item C-z
+@kindex C-z
+End current configuration session and move to top node.
+
+
+@item C-n
+@itemx @key{DOWN}
+@kindex C-n
+@kindex @key{DOWN}
+Move down to next line in the history buffer.
+
+@item C-p
+@itemx @key{UP}
+@kindex C-p
+@kindex @key{UP}
+Move up to previous line in the history buffer.
+
+@item TAB
+@kindex @key{TAB}
+Use command line completion by typing @key{TAB}.
+
+@item
+@kindex ?
+You can use command line help by typing @code{help} at the beginning of
+the line.  Typing @kbd{?} at any point in the line will show possible
+completions.
+
+@end table
diff --git a/doc/bgpd.8 b/doc/bgpd.8
new file mode 100644 (file)
index 0000000..cba3bda
--- /dev/null
@@ -0,0 +1,169 @@
+.TH BGPD 8 "July 2000" "Zebra Beast - BGPD" "Version 0.88"
+
+.SH NAME
+bgpd \- a BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra
+
+.SH SYNOPSIS
+.B bgpd
+[
+.B \-dhpPv
+]
+[
+.B \-f config-file
+]
+[
+.B \-i pid-file
+]
+[
+.B \-p bgp-port-number
+]
+[
+.B \--bgp_port=port-number
+]
+[
+.B \-P vty-port-number
+]
+
+.SH DESCRIPTION
+.B bgpd 
+is a routing component that works with the 
+.B zebra
+routing engine.
+
+
+.SH OPTIONS
+
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR 
+Specifies the config file to use for startup. If not specified this
+option will likely default to \fB\fI/usr/local/etc/bgpd.conf\fR.
+
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When bgpd starts its process idenifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart bgpd.  The likely default is \fB\fI/var/run/bgpd.pid\fR.
+
+.TP
+\fB\-p\fR, \fB\-\-bgp_port=\fR\fIport\fR
+Set the port that bgpd will listen to for bgp data.  
+
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the bgpd VTY will listen on. This defaults to
+2605, as specified in \fI/etc/services\fR.
+
+.TP
+\fB\-r\fR, \fB\-\-retain\fR 
+When the program terminates, retain routes added by \fBbgpd\fR.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+
+
+.SH COMMANDS
+
+\fB router zebra \fR -- (Move routes into kernel table)
+\fB router bgp [AS-NUMBER] \fR
+
+\fB bgp router-id [BGP-ROUTER-ID] \fR
+
+\fB network [NETWORK] area [BGP-AREA-ID] \fR
+\fB no network [NETWORK] \fR
+
+\fB aggregate-address [NETWORK] \fR
+
+\fB neighbor [PEER-IP-ADDRESS] remote-as [REMOTE-AS] \fR
+\fB neighbor [PEER-IP-ADDRESS] version [ 4 | 4+ | 4- ] \fR
+
+\fB neighbor [PEER-IP-ADDRESS] description \fR
+\fB no neighbor [PEER-IP-ADDRESS] description \fR
+
+\fB neighbor [PEER-IP-ADDRESS] route-map [in | out] \fR
+\fB neighbor [PEER-IP-ADDRESS] distribute-list [in | out] \fR
+\fB neighbor [PEER-IP-ADDRESS] next-hop-self \fR
+\fB neighbor [PEER-IP-ADDRESS] weight [WEIGHT] \fR
+\fB neighbor [PEER-IP-ADDRESS] default-originate \fR
+\fB neighbor [PEER-IP-ADDRESS] ebgp-multihop \fR
+
+\fB neighbor [PEER-IP-ADDRESS] shutdown \fR
+\fB no neighbor [PEER-IP-ADDRESS] shutdown \fR
+
+\fB clear ip bgp [PEER-IP-ADDRESS] \fR
+
+\fB show ip bgp [NETWORK] \fR
+\fB show ip bgp reg-exp [AS-REGEXP] \fR
+\fB show ip bgp summary \fR
+\fB show ip bgp neighbor [PEER-IP-ADDRESS] \fR
+\fB show ip bgp route \fR
+
+\fB show debug \fR
+
+\fB debug bgp \fR
+\fB debug event \fR
+\fB debug update \fR
+\fB debug keepalive \fR
+
+\fB no debug event \fR
+\fB no debug update \fR
+\fB no debug keepalive \fR
+
+
+.SH FILES
+
+.TP
+.BI /usr/local/sbin/bgpd
+The default location of the 
+.B bgpd
+binary.
+
+.TP
+.BI /usr/local/etc/bgpd.conf
+The default location of the 
+.B bgpd
+config file.
+
+.TP
+.BI $(PWD)/bgpd.log 
+If the 
+.B bgpd
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBbgpd\fR.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line
+options, and for config file commands. The definitive document is the
+Info file \fBzebra\fR.
+
+
+.SH DIAGNOSTICS
+The bgpd process may log to standard output, to a VTY, to a log
+file, or through syslog to the system logs. \fBbgpd\fR supports many
+debugging options, see the Info file, or the source for details.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+ripd(8), ripngd(8), ospfd(8), ospf6d(8), zebra(8), vtysh(1)
+
+
+.SH BUGS
+.B bgpd
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/bgpd.texi b/doc/bgpd.texi
new file mode 100644 (file)
index 0000000..c10fba9
--- /dev/null
@@ -0,0 +1,1288 @@
+@c -*-texinfo-*-
+@c This is part of the GNU Zebra Manual.
+@c Copyright (C) 1999, 2000, 2001 2002 Kunihiro Ishiguro <kunihiro@zebra.org>
+@c See file zebra.texi for copying conditions.
+@node BGP
+@comment  node-name,  next,  previous,  up
+@chapter BGP
+
+  BGP stands for a Border Gateway Protocol.  The lastest BGP version
+is 4.  It is referred as BGP-4.  BGP-4 is one of the Exterior Gateway
+Protocols and de-fact standard of Inter Domain routing protocol.
+BGP-4 is described in @code{RFC1771} - @cite{A Border Gateway Protocol
+4 (BGP-4)}.
+
+  Many extentions are added to @code{RFC1771}.  @code{RFC2858} -
+@cite{Multiprotocol Extensions for BGP-4} provide multiprotocol
+support to BGP-4.
+
+@menu
+* Starting BGP::                
+* BGP router::                  
+* BGP network::                 
+* BGP Peer::                    
+* BGP Peer Group::              
+* BGP Address Family::          
+* Autonomous System::           
+* BGP Communities Attribute::   
+* BGP Extended Communities Attribute::  
+* Displaying BGP routes::       
+* Capability Negotiation::      
+* Route Reflector::             
+* Route Server::                
+* How to set up a 6-Bone connection::  
+* Dump BGP packets and table::  
+@end menu
+
+@node Starting BGP, BGP router, BGP, BGP
+@comment  node-name,  next,  previous,  up
+@section Starting BGP
+
+Default configuration file of @command{bgpd} is @file{bgpd.conf}.
+@command{bgpd} searches the current directory first then
+@value{INSTALL_PREFIX_ETC}/bgpd.conf.  All of bgpd's command must be
+configured in @file{bgpd.conf}.
+
+@command{bgpd} specific invocation options are described below.  Common
+options may also be specified (@pxref{Common Invocation Options}).
+
+@table @samp
+@item -p @var{PORT}
+@itemx --bgp_port=@var{PORT}
+Set the bgp protocol's port number.
+
+@item -r
+@itemx --retain
+When program terminates, retain BGP routes added by zebra.
+@end table
+
+@node BGP router, BGP network, Starting BGP, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP router
+
+  First of all you must configure BGP router with @command{router bgp}
+command.  To configure BGP router, you need AS number.  AS number is an
+identification of autonomous system.  BGP protocol uses the AS number
+for detecting whether the BGP connection is internal one or external one.
+
+@deffn Command {router bgp @var{asn}} {}
+Enable a BGP protocol process with the specified @var{asn}.  After
+this statement you can input any @code{BGP Commands}.  You can not
+create different BGP process under different @var{asn} without
+specifying @code{multiple-instance} (@pxref{Multiple instance}).
+@end deffn
+
+@deffn Command {no router bgp @var{asn}} {}
+Destroy a BGP protocol process with the specified @var{asn}.
+@end deffn
+
+@deffn {BGP} {bgp router-id @var{A.B.C.D}} {}
+This command specifies the router-ID.  If @command{bgpd} connects to @command{zebra} it gets
+interface and address information.  In that case default router ID value
+is selected as the largest IP Address of the interfaces.  When
+@code{router zebra} is not enabled @command{bgpd} can't get interface information
+so @code{router-id} is set to 0.0.0.0.  So please set router-id by hand.
+@end deffn
+
+@menu
+* BGP distance::                
+* BGP decision process::        
+@end menu
+
+@node BGP distance, BGP decision process, BGP router, BGP router
+@comment  node-name,  next,  previous,  up
+@subsection BGP distance
+
+@deffn {BGP} {distance bgp <1-255> <1-255> <1-255>} {}
+This command change distance value of BGP.  Each argument is distance
+value for external routes, internal routes and local routes.
+@end deffn
+
+@deffn {BGP} {distance <1-255> @var{A.B.C.D/M}} {}
+@deffnx {BGP} {distance <1-255> @var{A.B.C.D/M} @var{word}} {}
+This command set distance value to 
+@end deffn
+
+@node BGP decision process,  , BGP distance, BGP router
+@comment  node-name,  next,  previous,  up
+@subsection BGP decision process
+
+@table @asis
+@item 1. Weight check
+  
+@item 2. Local preference check.
+
+@item 3. Local route check.
+
+@item 4. AS path length check.
+
+@item 5. Origin check.
+
+@item 6. MED check.
+@end table
+
+@node BGP network, BGP Peer, BGP router, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP network
+
+@menu
+* BGP route::                   
+* Route Aggregation::           
+* Redistribute to BGP::         
+@end menu
+
+@node BGP route, Route Aggregation, BGP network, BGP network
+@comment  node-name,  next,  previous,  up
+@subsection BGP route
+
+@deffn {BGP} {network @var{A.B.C.D/M}} {}
+This command adds the announcement network.
+@example
+@group
+router bgp 1
+ network 10.0.0.0/8
+@end group
+@end example
+This configuration example says that network 10.0.0.0/8 will be
+announced to all neighbors.  Some vendors' routers don't advertise
+routes if they aren't present in their IGP routing tables; @code{bgp}
+doesn't care about IGP routes when announcing its routes.
+@end deffn
+
+@deffn {BGP} {no network @var{A.B.C.D/M}} {}
+@end deffn
+
+@node Route Aggregation, Redistribute to BGP, BGP route, BGP network
+@comment  node-name,  next,  previous,  up
+@subsection Route Aggregation
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M}} {}
+This command specifies an aggregate address.
+@end deffn
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {}
+This command specifies an aggregate address.  Resulting routes inlucde
+AS set.
+@end deffn
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {}
+This command specifies an aggregate address.  Aggreated routes will
+not be announce.
+@end deffn
+
+@deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {}
+@end deffn
+
+@node Redistribute to BGP,  , Route Aggregation, BGP network
+@comment  node-name,  next,  previous,  up
+@subsection Redistribute to BGP
+
+@deffn {BGP} {redistribute kernel} {}
+Redistribute kernel route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute static} {}
+Redistribute static route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute connected} {}
+Redistribute connected route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute rip} {}
+Redistribute RIP route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute ospf} {}
+Redistribute OSPF route to BGP process.
+@end deffn
+
+@node BGP Peer, BGP Peer Group, BGP network, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP Peer
+
+@menu
+* Defining Peer::               
+* BGP Peer commands::           
+* Peer filtering::              
+@end menu
+
+@node Defining Peer, BGP Peer commands, BGP Peer, BGP Peer
+@comment  node-name,  next,  previous,  up
+@subsection Defining Peer
+
+@deffn {BGP} {neighbor @var{peer} remote-as @var{asn}} {}
+Creates a new neighbor whose remote-as is @var{asn}.  @var{peer}
+can be an IPv4 address or an IPv6 address.
+@example
+@group
+router bgp 1
+ neighbor 10.0.0.1 remote-as 2
+@end group
+@end example
+In this case my router, in AS-1, is trying to peer with AS-2 at
+10.0.0.1.
+
+This command must be the first command used when configuring a neighbor.
+If the remote-as is not specified, @command{bgpd} will complain like this:
+@example
+can't find neighbor 10.0.0.1
+@end example
+@end deffn
+
+@node BGP Peer commands, Peer filtering, Defining Peer, BGP Peer
+@comment  node-name,  next,  previous,  up
+@subsection BGP Peer commands
+
+In a @code{router bgp} clause there are neighbor specific configurations
+required.
+
+@deffn {BGP} {neighbor @var{peer} shutdown} {}
+@deffnx {BGP} {no neighbor @var{peer} shutdown} {}
+Shutdown the peer.  We can delete the neighbor's configuration by
+@code{no neighbor @var{peer} remote-as @var{as-number}} but all
+configuration of the neighbor will be deleted.  When you want to
+preserve the configuration, but want to drop the BGP peer, use this
+syntax.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} ebgp-multihop} {}
+@deffnx {BGP} {no neighbor @var{peer} ebgp-multihop} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} description ...} {}
+@deffnx {BGP} {no neighbor @var{peer} description ...} {}
+Set description of the peer.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} version @var{version}} {}
+Set up the neighbor's BGP version.  @var{version} can be @var{4},
+@var{4+} or @var{4-}.  BGP version @var{4} is the default value used for
+BGP peering.  BGP version @var{4+} means that the neighbor supports
+Multiprotocol Extensions for BGP-4.  BGP version @var{4-} is similar but
+the neighbor speaks the old Internet-Draft revision 00's Multiprotocol
+Extensions for BGP-4.  Some routing software is still using this
+version.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} interface @var{ifname}} {}
+@deffnx {BGP} {no neighbor @var{peer} interface @var{ifname}} {}
+When you connect to a BGP peer over an IPv6 link-local address, you have
+to specify the @var{ifname} of the interface used for the connection.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} next-hop-self} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {}
+This command specifies an announced route's nexthop as being equivalent
+to the address of the bgp router.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} update-source} {}
+@deffnx {BGP} {no neighbor @var{peer} update-source} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} default-originate} {}
+@deffnx {BGP} {no neighbor @var{peer} default-originate} {}
+@command{bgpd}'s default is to not announce the default route (0.0.0.0/0) even it
+is in routing table.  When you want to announce default routes to the
+peer, use this command.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} port @var{port}} {}
+@deffnx {BGP} {neighbor @var{peer} port @var{port}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} send-community} {}
+@deffnx {BGP} {neighbor @var{peer} send-community} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} weight @var{weight}} {}
+@deffnx {BGP} {no neighbor @var{peer} weight @var{weight}} {}
+This command specifies a default @var{weight} value for the neighbor's
+routes.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} maximum-prefix @var{number}} {}
+@deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {}
+@end deffn
+
+@node Peer filtering,  , BGP Peer commands, BGP Peer
+@comment  node-name,  next,  previous,  up
+@subsection Peer filtering
+
+@deffn {BGP} {neighbor @var{peer} distribute-list @var{name} [in|out]} {}
+This command specifies a distribute-list for the peer.  @var{direct} is
+@samp{in} or @samp{out}.
+@end deffn
+
+@deffn {BGP command} {neighbor @var{peer} prefix-list @var{name} [in|out]} {}
+@end deffn
+
+@deffn {BGP command} {neighbor @var{peer} filter-list @var{name} [in|out]} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} route-map @var{name} [in|out]} {}
+Apply a route-map on the neighbor.  @var{direct} must be @code{in} or
+@code{out}.
+@end deffn
+
+@c -----------------------------------------------------------------------
+@node BGP Peer Group, BGP Address Family, BGP Peer, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP Peer Group
+
+@deffn {BGP} {neighbor @var{word} peer-group} {}
+This command defines a new peer group.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} peer-group @var{word}} {}
+This command bind specific peer to peer group @var{word}.
+@end deffn
+
+@node BGP Address Family, Autonomous System, BGP Peer Group, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP Address Family
+
+
+
+@page
+@c -----------------------------------------------------------------------
+@node Autonomous System, BGP Communities Attribute, BGP Address Family, BGP
+@comment  node-name,  next,  previous,  up
+@section Autonomous System
+
+  AS (Autonomous System) is one of the essential element of BGP.  BGP
+is a distance vector routing protocol.  AS framework provides distance
+vector metric and loop detection to BGP.  @code{RFC1930} -
+@cite{Guidelines for creation, selection, and registration of an
+Autonomous System (AS)} describes how to use AS.
+
+  AS number is tow octet digita value.  So the value range is from 1
+to 65535.  AS numbers 64512 through 65535 are defined as private AS
+numbers.  Private AS numbers must not to be advertised in the global
+Internet.
+
+@menu
+* AS Path Regular Expression::  
+* Display BGP Routes by AS Path::  
+* AS Path Access List::         
+* Using AS Path in Route Map::  
+* Private AS Numbers::          
+@end menu
+
+@node AS Path Regular Expression, Display BGP Routes by AS Path, Autonomous System, Autonomous System
+@comment  node-name,  next,  previous,  up
+@subsection AS Path Regular Expression
+
+  AS path regular expression can be used for displaying BGP routes and
+AS path access list.  AS path regular expression is based on
+@code{POSIX 1003.2} regular expressions.  Following description is
+just a subset of @code{POSIX} regular expression.  User can use full
+@code{POSIX} regular expression.  Adding to that special character '_'
+is added for AS path regular expression.
+
+@table @code
+@item .
+Matches any single character.
+@item *
+Matches 0 or more occurrences of pattern.
+@item +
+Matches 1 or more occurrences of pattern.
+@item ?
+Match 0 or 1 occurrences of pattern.
+@item ^
+Matches the beginning of the line.
+@item $
+Matches the end of the line.
+@item _
+Character @code{_} has special meanings in AS path regular expression.
+It matches to space and comma , and AS set delimiter @{ and @} and AS
+confederation delimiter @code{(} and @code{)}.  And it also matches to
+the beginning of the line and the end of the line.  So @code{_} can be
+used for AS value boundaries match.  @code{show ip bgp regexp _7675_}
+matches to all of BGP routes which as AS number include @var{7675}.
+@end table
+
+@node Display BGP Routes by AS Path, AS Path Access List, AS Path Regular Expression, Autonomous System
+@comment  node-name,  next,  previous,  up
+@subsection Display BGP Routes by AS Path
+
+  To show BGP routes which has specific AS path information @code{show
+ip bgp} command can be used.  
+
+@deffn Command {show ip bgp regexp @var{line}} {}
+This commands display BGP routes that matches AS path regular
+expression @var{line}.
+@end deffn
+
+@node AS Path Access List, Using AS Path in Route Map, Display BGP Routes by AS Path, Autonomous System
+@comment  node-name,  next,  previous,  up
+@subsection AS Path Access List
+
+  AS path access list is user defined AS path.
+
+@deffn {Command} {ip as-path access-list @var{word} @{permit|deny@} @var{line}} {}
+This command defines a new AS path access list.
+@end deffn
+
+@deffn {Command} {no ip as-path access-list @var{word}} {}
+@deffnx {Command} {no ip as-path access-list @var{word} @{permit|deny@} @var{line}} {}
+@end deffn
+
+@node Using AS Path in Route Map, Private AS Numbers, AS Path Access List, Autonomous System
+@comment  node-name,  next,  previous,  up
+@subsection Using AS Path in Route Map
+
+@deffn {Route Map} {match as-path @var{word}} {}
+@end deffn
+
+@deffn {Route Map} {set as-path prepend @var{as-path}} {}
+@end deffn
+
+@node Private AS Numbers,  , Using AS Path in Route Map, Autonomous System
+@comment  node-name,  next,  previous,  up
+@subsection Private AS Numbers
+
+@page
+@c -----------------------------------------------------------------------
+@node BGP Communities Attribute, BGP Extended Communities Attribute, Autonomous System, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP Communities Attribute
+
+  BGP communities attribute is widely used for implementing policy
+routing.  Network operators can manipulate BGP communities attribute
+based on their network policy.  BGP communities attribute is defined
+in @code{RFC1997} - @cite{BGP Communities Attribute} and
+@code{RFC1998} - @cite{An Application of the BGP Community Attribute
+in Multi-home Routing}.  It is an optional transitive attribute,
+therefore local policy can travel through different autonomous system.
+
+  Communities attribute is a set of communities values.  Each
+communities value is 4 octet long.  The following format is used to
+define communities value.
+
+@table @code
+@item AS:VAL
+This format represents 4 octet communities value.  @code{AS} is high
+order 2 octet in digit format.  @code{VAL} is low order 2 octet in
+digit format.  This format is useful to define AS oriented policy
+value.  For example, @code{7675:80} can be used when AS 7675 wants to
+pass local policy value 80 to neighboring peer.
+@item internet
+@code{internet} represents well-known communities value 0.
+@item no-export
+@code{no-export} represents well-known communities value @code{NO_EXPORT}@*
+@r{(0xFFFFFF01)}.  All routes carry this value must not be advertised
+to outside a BGP confederation boundary.  If neighboring BGP peer is
+part of BGP confederation, the peer is considered as inside a BGP
+confederation boundary, so the route will be announced to the peer.
+@item no-advertise
+@code{no-advertise} represents well-known communities value
+@code{NO_ADVERTISE}@*@r{(0xFFFFFF02)}.  All routes carry this value
+must not be advertise to other BGP peers.
+@item local-AS
+@code{local-AS} represents well-known communities value
+@code{NO_EXPORT_SUBCONFED} @r{(0xFFFFFF03)}.  All routes carry this
+value must not be advertised to external BGP peers.  Even if the
+neighboring router is part of confederation, it is considered as
+external BGP peer, so the route will not be announced to the peer.
+@end table
+
+  When BGP communities attribute is received, duplicated communities
+value in the communities attribute is ignored and each communities
+values are sorted in numerical order.
+  
+@menu
+* BGP Community Lists::         
+* Numbered BGP Community Lists::  
+* BGP Community in Route Map::  
+* Display BGP Routes by Community::  
+* Using BGP Communities Attribute::  
+@end menu
+
+@node BGP Community Lists, Numbered BGP Community Lists, BGP Communities Attribute, BGP Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection BGP Community Lists
+
+  BGP community list is a user defined BGP communites attribute list.
+BGP community list can be used for matching or manipulating BGP
+communities attribute in updates.
+
+  There are two types of community list.  One is standard community
+list and another is expanded community list.  Standard community list
+defines communities attribute.  Expanded community list defines
+communities attribute string with regular expression.  Standard
+community list is compiled into binary format when user define it.
+Standard community list will be directly compared to BGP communities
+attribute in BGP updates.  Therefore the comparison is faster than
+expanded community list.
+
+@deffn Command {ip community-list standard @var{name} @{permit|deny@} @var{community}} {}
+This command defines a new standard community list.  @var{community}
+is communities value.  The @var{community} is compiled into community
+structure.  We can define multiple community list under same name.  In
+that case match will happen user defined order.  Once the
+community list matches to communities attribute in BGP updates it
+return permit or deny by the community list definition.  When there is
+no matched entry, deny will be returned.  When @var{community} is
+empty it matches to any routes.
+@end deffn
+
+@deffn Command {ip community-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded community list.  @var{line} is a
+string expression of communities attribute.  @var{line} can include
+regular expression to match communities attribute in BGP updates.
+@end deffn
+
+@deffn Command {no ip community-list @var{name}} {}
+@deffnx Command {no ip community-list standard @var{name}} {}
+@deffnx Command {no ip community-list expanded @var{name}} {}
+These commands delete community lists specified by @var{name}.  All of
+community lists shares a single name space.  So community lists can be
+removed simpley specifying community lists name.
+@end deffn
+
+@deffn {Command} {show ip community-list} {}
+@deffnx {Command} {show ip community-list @var{name}} {}
+This command display current community list information.  When
+@var{name} is specified the specified community list's information is
+shown.
+
+@example
+# show ip community-list 
+Named Community standard list CLIST
+    permit 7675:80 7675:100 no-export
+    deny internet
+Named Community expanded list EXPAND
+    permit :
+
+# show ip community-list CLIST
+Named Community standard list CLIST
+    permit 7675:80 7675:100 no-export
+    deny internet
+@end example
+@end deffn
+
+@node Numbered BGP Community Lists, BGP Community in Route Map, BGP Community Lists, BGP Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection Numbered BGP Community Lists
+
+  When number is used for BGP community list name, the number has
+special meanings.  Community list number in the range from 1 and 99 is
+standard community list.  Community list number in the range from 100
+to 199 is expanded community list.  These community lists are called
+as numbered community lists.  On the other hand normal community lists
+is called as named community lists.
+
+@deffn Command {ip community-list <1-99> @{permit|deny@} @var{community}} {}
+This command defines a new community list.  <1-99> is standard
+community list number.  Community list name within this range defines
+standard community list.  When @var{community} is empty it matches to
+any routes.
+@end deffn
+
+@deffn Command {ip community-list <100-199> @{permit|deny@} @var{community}} {}
+This command defines a new community list.  <100-199> is expanded
+community list number.  Community list name within this range defines
+expanded community list.
+@end deffn
+
+@deffn Command {ip community-list @var{name} @{permit|deny@} @var{community}} {}
+When community list type is not specifed, the community list type is
+automatically detected.  If @var{community} can be compiled into
+communities attribute, the community list is defined as a standard
+community list.  Otherwise it is defined as an expanded community
+list.  This feature is left for backward compability.  Use of this
+feature is not recommended.
+@end deffn
+
+@node BGP Community in Route Map, Display BGP Routes by Community, Numbered BGP Community Lists, BGP Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection BGP Community in Route Map
+
+  In Route Map (@pxref{Route Map}), we can match or set BGP
+communities attribute.  Using this feature network operator can
+implement their network policy based on BGP communities attribute.
+
+  Following commands can be used in Route Map.
+
+@deffn {Route Map} {match community @var{word}} {}
+@deffnx {Route Map} {match community @var{word} exact-match} {}
+This command perform match to BGP updates using community list
+@var{word}.  When the one of BGP communities value match to the one of
+communities value in community list, it is match.  When
+@code{exact-match} keyword is spcified, match happen only when BGP
+updates have completely same communities value specified in the
+community list.
+@end deffn
+
+@deffn {Route Map} {set community none} {}
+@deffnx {Route Map} {set community @var{community}} {}
+@deffnx {Route Map} {set community @var{community} additive} {}
+This command manipulate communities value in BGP updates.  When
+@code{none} is specified as communities value, it removes entire
+communities attribute from BGP updates.  When @var{community} is not
+@code{none}, specified communities value is set to BGP updates.  If
+BGP updates already has BGP communities value, the existing BGP
+communities value is replaced with specified @var{community} value.
+When @code{additive} keyword is specified, @var{community} is appended
+to the existing communities value.
+@end deffn
+
+@deffn {Route Map} {set comm-list @var{word} delete} {}
+This command remove communities value from BGP communities attribute.
+The @var{word} is community list name.  When BGP route's communities
+value matches to the community list @var{word}, the communities value
+is removed.  When all of communities value is removed eventually, the
+BGP update's communities attribute is completely removed.
+@end deffn
+
+@node Display BGP Routes by Community, Using BGP Communities Attribute, BGP Community in Route Map, BGP Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection Display BGP Routes by Community
+
+  To show BGP routes which has specific BGP communities attribute,
+@code{show ip bgp} command can be used.  The @var{community} value and
+community list can be used for @code{show ip bgp} command.
+
+@deffn Command {show ip bgp community} {}
+@deffnx Command {show ip bgp community @var{community}} {}
+@deffnx Command {show ip bgp community @var{community} exact-match} {}
+@code{show ip bgp community} displays BGP routes which has communities
+attribute.  When @var{community} is specified, BGP routes that matches
+@var{community} value is displayed.  For this command, @code{internet}
+keyword can't be used for @var{community} value.  When
+@code{exact-match} is specified, it display only routes that have an
+exact match.
+@end deffn
+
+@deffn Command {show ip bgp community-list @var{word}} {}
+@deffnx Command {show ip bgp community-list @var{word} exact-match} {}
+This commands display BGP routes that matches community list
+@var{word}.  When @code{exact-match} is specified, display only routes
+that have an exact match.
+@end deffn
+
+@node Using BGP Communities Attribute,  , Display BGP Routes by Community, BGP Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection Using BGP Communities Attribute
+
+  Following configuration is the most typical usage of BGP communities
+attribute.  AS 7675 provides upstream Internet connection to AS 100.
+When following configuration exists in AS 7675, AS 100 networks
+operator can set local preference in AS 7675 network by setting BGP
+communities attribute to the updates.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list 70 permit 7675:70
+ip community-list 70 deny
+ip community-list 80 permit 7675:80
+ip community-list 80 deny
+ip community-list 90 permit 7675:90
+ip community-list 90 deny
+!
+route-map RMAP permit 10
+ match community 70
+ set local-preference 70
+!
+route-map RMAP permit 20
+ match community 80
+ set local-preference 80
+!
+route-map RMAP permit 30
+ match community 90
+ set local-preference 90
+@end example
+
+  Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675.
+The route has communities value 7675:80 so when above configuration
+exists in AS 7675, announced route's local preference will be set to
+value 80.
+
+@example
+router bgp 100
+ network 10.0.0.0/8
+ neighbor 192.168.0.2 remote-as 7675
+ neighbor 192.168.0.2 route-map RMAP out
+!
+ip prefix-list PLIST permit 10.0.0.0/8
+!
+route-map RMAP permit 10
+ match ip address prefix-list PLIST
+ set community 7675:80
+@end example
+
+  Following configuration is an example of BGP route filtering using
+communities attribute.  This configuration only permit BGP routes
+which has BGP communities value 0:80 or 0:90.  Network operator can
+put special internal communities value at BGP border router, then
+limit the BGP routes announcement into the internal network.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list 1 permit 0:80 0:90
+!
+route-map RMAP permit in
+ match community 1
+@end example
+
+  Following exmaple filter BGP routes which has communities value 1:1.
+When there is no match community-list returns deny.  To avoid
+filtering all of routes, we need to define permit any at last.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list standard FILTER deny 1:1
+ip community-list standard FILTER permit
+!
+route-map RMAP permit 10
+ match community FILTER
+@end example
+
+  Communities value keyword @code{internet} has special meanings in
+standard community lists.  In below example @code{internet} act as
+match any.  It matches all of BGP routes even if the route does not
+have communities attribute at all.  So community list @code{INTERNET}
+is same as above example's @code{FILTER}.
+
+@example
+ip community-list standard INTERNET deny 1:1
+ip community-list standard INTERNET permit internet
+@end example
+
+  Following configuration is an example of communities value deletion.
+With this configuration communities value 100:1 and 100:2 is removed
+from BGP updates.  For communities value deletion, only @code{permit}
+community-list is used.  @code{deny} community-list is ignored.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ neighbor 192.168.0.1 route-map RMAP in
+!
+ip community-list standard DEL permit 100:1 100:2
+!
+route-map RMAP permit 10
+ set comm-list DEL delete
+@end example
+
+@c -----------------------------------------------------------------------
+@node BGP Extended Communities Attribute, Displaying BGP routes, BGP Communities Attribute, BGP
+@comment  node-name,  next,  previous,  up
+@section BGP Extended Communities Attribute
+
+  BGP extended communities attribute is introduced with MPLS VPN/BGP
+technology.  MPLS VPN/BGP expands capability of network infrastructure
+to provide VPN functionality.  At the same time it requires a new
+framework for policy routing.  With BGP Extended Communities Attribute
+we can use Route Target or Site of Origin for implementing network
+policy for MPLS VPN/BGP.
+
+  BGP Extended Communities Attribute is similar to BGP Communities
+Attribute.  It is an optional transitive attribute.  BGP Extended
+Communities Attribute can carry multiple Extended Community value.
+Each Extended Community value is eight octet length.
+
+  BGP Extended Communities Attribute provides an extended range
+compared with BGP Communities Attribute.  Adding to that there is a
+type field in each value to provides community space structure.
+
+  There are two format to define Extended Community value.  One is AS
+based format the other is IP address based format.
+
+@table @code
+@item AS:VAL
+This is a format to define AS based Extended Community value.
+@code{AS} part is 2 octets Global Administrator subfield in Extended
+Community value.  @code{VAL} part is 4 octets Local Administrator
+subfield.  @code{7675:100} represents AS 7675 policy value 100.
+@item IP-Address:VAL
+This is a format to define IP address based Extended Community value.
+@code{IP-Address} part is 4 octets Global Administrator subfield.
+@code{VAL} part is 2 octets Local Administrator subfield.
+@code{10.0.0.1:100} represents 
+@end table
+
+@menu
+* BGP Extended Community Lists::  
+* BGP Extended Communities in Route Map::  
+@end menu
+
+@node BGP Extended Community Lists, BGP Extended Communities in Route Map, BGP Extended Communities Attribute, BGP Extended Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection BGP Extended Community Lists
+
+  Expanded Community Lists is a user defined BGP Expanded Community
+Lists.
+
+@deffn Command {ip extcommunity-list standard @var{name} @{permit|deny@} @var{extcommunity}} {}
+This command defines a new standard extcommunity-list.
+@var{extcommunity} is extended communities value.  The
+@var{extcommunity} is compiled into extended community structure.  We
+can define multiple extcommunity-list under same name.  In that case
+match will happen user defined order.  Once the extcommunity-list
+matches to extended communities attribute in BGP updates it return
+permit or deny based upon the extcommunity-list definition.  When
+there is no matched entry, deny will be returned.  When
+@var{extcommunity} is empty it matches to any routes.
+@end deffn
+
+@deffn Command {ip extcommunity-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded extcommunity-list.  @var{line} is
+a string expression of extended communities attribute.  @var{line} can
+include regular expression to match extended communities attribute in
+BGP updates.
+@end deffn
+
+@deffn Command {no ip extcommunity-list @var{name}} {}
+@deffnx Command {no ip extcommunity-list standard @var{name}} {}
+@deffnx Command {no ip extcommunity-list expanded @var{name}} {}
+These commands delete extended community lists specified by
+@var{name}.  All of extended community lists shares a single name
+space.  So extended community lists can be removed simpley specifying
+the name.
+@end deffn
+
+@deffn {Command} {show ip extcommunity-list} {}
+@deffnx {Command} {show ip extcommunity-list @var{name}} {}
+This command display current extcommunity-list information.  When
+@var{name} is specified the community list's information is shown.
+
+@example
+# show ip extcommunity-list 
+@end example
+@end deffn
+
+@node BGP Extended Communities in Route Map,  , BGP Extended Community Lists, BGP Extended Communities Attribute
+@comment  node-name,  next,  previous,  up
+@subsection BGP Extended Communities in Route Map
+
+@deffn {Route Map} {match extcommunity @var{word}} {}
+@end deffn
+
+@deffn {Route Map} {set extcommunity rt @var{extcommunity}} {}
+This command set Route Target value.
+@end deffn
+
+@deffn {Route Map} {set extcommunity soo @var{extcommunity}} {}
+This command set Site of Origin value.
+@end deffn
+
+@c -----------------------------------------------------------------------
+@node Displaying BGP routes, Capability Negotiation, BGP Extended Communities Attribute, BGP
+@comment  node-name,  next,  previous,  up
+@section Displaying BGP Routes
+
+@menu
+* Show IP BGP::                 
+* More Show IP BGP::            
+@end menu
+
+@node Show IP BGP, More Show IP BGP, Displaying BGP routes, Displaying BGP routes
+@comment  node-name,  next,  previous,  up
+@subsection Show IP BGP
+
+@deffn {Command} {show ip bgp} {}
+@deffnx {Command} {show ip bgp @var{A.B.C.D}} {}
+@deffnx {Command} {show ip bgp @var{X:X::X:X}} {}
+This command displays BGP routes.  When no route is specified it
+display all of IPv4 BGP routes.
+@end deffn
+
+@example
+BGP table version is 0, local router ID is 10.1.1.1
+Status codes: s suppressed, d damped, h history, * valid, > best, i - internal
+Origin codes: i - IGP, e - EGP, ? - incomplete
+
+   Network          Next Hop            Metric LocPrf Weight Path
+*> 1.1.1.1/32       0.0.0.0                  0         32768 i
+
+Total number of prefixes 1
+@end example
+
+@node More Show IP BGP,  , Show IP BGP, Displaying BGP routes
+@comment  node-name,  next,  previous,  up
+@subsection More Show IP BGP
+
+@deffn {Command} {show ip bgp regexp @var{line}} {}
+This command display BGP routes using AS path regular expression (@pxref{Display BGP Routes by AS Path}).
+@end deffn
+
+@deffn Command {show ip bgp community @var{community}} {}
+@deffnx Command {show ip bgp community @var{community} exact-match} {}
+This command display BGP routes using @var{community} (@pxref{Display
+BGP Routes by Community}).
+@end deffn
+
+@deffn Command {show ip bgp community-list @var{word}} {}
+@deffnx Command {show ip bgp community-list @var{word} exact-match} {}
+This command display BGP routes using community list (@pxref{Display
+BGP Routes by Community}).
+@end deffn
+
+@deffn {Command} {show ip bgp summary} {}
+@end deffn
+
+@deffn {Command} {show ip bgp neighbor [@var{peer}]} {}
+@end deffn
+
+@deffn {Command} {clear ip bgp @var{peer}} {}
+Clear peers which have addresses of X.X.X.X
+@end deffn
+
+@deffn {Command} {clear ip bgp @var{peer} soft in} {}
+Clear peer using soft reconfiguration.
+@end deffn
+
+@deffn {Command} {show debug} {}
+@end deffn
+
+@deffn {Command} {debug event} {}
+@end deffn
+
+@deffn {Command} {debug update} {}
+@end deffn
+
+@deffn {Command} {debug keepalive} {}
+@end deffn
+
+@deffn {Command} {no debug event} {}
+@end deffn
+
+@deffn {Command} {no debug update} {}
+@end deffn
+
+@deffn {Command} {no debug keepalive} {}
+@end deffn
+
+@node Capability Negotiation, Route Reflector, Displaying BGP routes, BGP
+@comment  node-name,  next,  previous,  up
+@section Capability Negotiation
+
+  When adding IPv6 routing information exchange feature to BGP.  There
+were some proposals.  @acronym{IETF} @acronym{IDR} working group finally
+take a proposal called Multiprotocol Extension for BGP.  The
+specification is described in RFC2283.  The protocol does not define new
+protocols.  It defines new attributes to existing BGP.  When it is used
+exchanging IPv6 routing information it is called BGP-4+.  When it is
+used for exchanging multicast routing information it is called MBGP.
+
+  @command{bgpd} supports Multiprotocol Extension for BGP.  So if remote peer
+supports the protocol, @command{bgpd} can exchange IPv6 and/or multicast routing
+information.
+
+  Traditional BGP does not have the feature to detect remote peer's
+capability whether it can handle other than IPv4 unicast routes.  This
+is a big problem using Multiprotocol Extension for BGP to operational
+network.  @cite{draft-ietf-idr-bgp4-cap-neg-04.txt} is proposing a
+feature called Capability Negotiation.  @command{bgpd} use this Capability
+Negotiation to detect remote peer's capabilities.  If the peer is only
+configured as IPv4 unicast neighbor, @command{bgpd} does not send these Capability
+Negotiation packets.
+
+  By default, Zebra will bring up peering with minimal common capability
+for the both sides.  For example, local router has unicast and multicast 
+capabilitie and remote router has unicast capability.  In this case,
+the local router will establish the connection with unicast only capability.
+When there are no common capabilities, Zebra sends Unsupported Capability
+error and then resets the connection.
+
+  If you want to completely match capabilities with remote peer.  Please
+use @command{strict-capability-match} command.
+  
+@deffn {BGP} {neighbor @var{peer} strict-capability-match} {}
+@deffnx {BGP} {no neighbor @var{peer} strict-capability-match} {}
+Strictly compares remote capabilities and local capabilities.  If capabilities
+are different, send Unsupported Capability error then reset connection.
+@end deffn
+
+  You may want to disable sending Capability Negotiation OPEN message
+optional parameter to the peer when remote peer does not implement
+Capability Negotiation.  Please use @command{dont-capability-negotiate}
+command to disable the feature.
+
+@deffn {BGP} {neighbor @var{peer} dont-capability-negotiate} {}
+@deffnx {BGP} {no neighbor @var{peer} dont-capability-negotiate} {}
+Suppress sending Capability Negotiation as OPEN message optional
+parameter to the peer.  This command only affects the peer is configured
+other than IPv4 unicast configuration.
+@end deffn
+
+  When remote peer does not have capability negotiation feature, remote
+peer will not send any capabilities at all.  In that case, bgp configures
+the peer with configured capabilities.
+
+  You may prefer locally configured capabilities more than the negotiated
+capabilities even though remote peer sends capabilities.  If the peer is
+configured by @command{override-capability}, @command{bgpd} ignores received
+capabilities then override negotiated capabilities with configured values.
+
+@deffn {BGP} {neighbor @var{peer} override-capability} {}
+@deffnx {BGP} {no neighbor @var{peer} override-capability} {}
+Override the result of Capability Negotiation with local configuration.
+Ignore remote peer's capability value.
+@end deffn
+
+@node Route Reflector, Route Server, Capability Negotiation, BGP
+@comment  node-name,  next,  previous,  up
+@section Route Reflector
+
+@deffn {BGP} {bgp cluster-id @var{a.b.c.d}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} route-reflector-client} {}
+@deffnx {BGP} {no neighbor @var{peer} route-reflector-client} {}
+@end deffn
+
+@node Route Server, How to set up a 6-Bone connection, Route Reflector, BGP
+@comment  node-name,  next,  previous,  up
+@section Route Server
+
+At an Internet Exchange point, many ISPs are connected to each other by
+external BGP peering.  Normally these external BGP connection are done by
+@code{full mesh} method.  As with internal BGP full mesh formation,
+this method has a scaling problem.
+
+This scaling problem is well known.  Route Server is a method to resolve
+the problem.  Each ISP's BGP router only peers to Route Server.  Route
+Server serves as BGP information exchange to other BGP routers.  By
+applying this method, numbers of BGP connections is reduced from
+O(n*(n-1)/2) to O(n).
+
+Unlike normal BGP router, Route Server must have several routing tables
+for managing different routing policies for each BGP speaker.  We call the
+routing tables as different @code{view}s.  @command{bgpd} can work as
+normal BGP router or Route Server or both at the same time.
+
+@menu
+* Multiple instance::           
+* BGP instance and view::       
+* Routing policy::              
+* Viewing the view::            
+@end menu
+
+@node Multiple instance, BGP instance and view, Route Server, Route Server
+@comment  node-name,  next,  previous,  up
+@subsection Multiple instance
+
+To enable multiple view function of @code{bgpd}, you must turn on
+multiple instance feature beforehand.
+
+@deffn {Command} {bgp multiple-instance} {}
+Enable BGP multiple instance feature.  After this feature is enabled,
+you can make multiple BGP instances or multiple BGP views.
+@end deffn
+
+@deffn {Command} {no bgp multiple-instance} {}
+Disable BGP multiple instance feature.  You can not disable this feature
+when BGP multiple instances or views exist.
+@end deffn
+
+When you want to make configuration more Cisco like one, 
+
+@deffn {Command} {bgp config-type cisco} {}
+Cisco compatible BGP configuration output.
+@end deffn
+
+When bgp config-type cisco is specified, 
+
+``no synchronization'' is displayed.
+``no auto-summary'' is desplayed.
+
+``network'' and ``aggregate-address'' argument is displayed as
+``A.B.C.D M.M.M.M''
+
+Zebra: network 10.0.0.0/8
+Cisco: network 10.0.0.0
+
+Zebra: aggregate-address 192.168.0.0/24
+Cisco: aggregate-address 192.168.0.0 255.255.255.0
+
+Community attribute handling is also different.  If there is no
+configuration is specified community attribute and extended community
+attribute are sent to neighbor.  When user manually disable the
+feature community attribute is not sent to the neighbor.  In case of
+``bgp config-type cisco'' is specified, community attribute is not
+sent to the neighbor by default.  To send community attribute user has
+to specify ``neighbor A.B.C.D send-community'' command.
+
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 1
+ no neighbor 10.0.0.1 send-community
+!
+
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 1
+ neighbor 10.0.0.1 send-community
+!
+
+@deffn {Command} {bgp config-type zebra} {}
+Zebra style BGP configuration.  This is default.
+@end deffn
+
+@node BGP instance and view, Routing policy, Multiple instance, Route Server
+@comment  node-name,  next,  previous,  up
+@subsection BGP instance and view
+
+BGP instance is a normal BGP process.  The result of route selection
+goes to the kernel routing table.  You can setup different AS at the
+same time when BGP multiple instance feature is enabled.
+
+@deffn {Command} {router bgp @var{as-number}} {}
+Make a new BGP instance.  You can use arbitrary word for the @var{name}.
+@end deffn
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.2 remote-as 3
+!
+router bgp 2
+ neighbor 10.0.0.3 remote-as 4
+ neighbor 10.0.0.4 remote-as 5
+@end group
+@end example
+
+BGP view is almost same as normal BGP process. The result of
+route selection does not go to the kernel routing table.  BGP view is
+only for exchanging BGP routing information.
+
+@deffn {Command} {router bgp @var{as-number} view @var{name}} {}
+Make a new BGP view.  You can use arbitrary word for the @var{name}.  This
+view's route selection result does not go to the kernel routing table.
+@end deffn
+
+With this command, you can setup Route Server like below.
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1 view 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.2 remote-as 3
+!
+router bgp 2 view 2
+ neighbor 10.0.0.3 remote-as 4
+ neighbor 10.0.0.4 remote-as 5
+@end group
+@end example
+
+@node Routing policy, Viewing the view, BGP instance and view, Route Server
+@comment  node-name,  next,  previous,  up
+@subsection Routing policy
+
+You can set different routing policy for a peer.  For example, you can
+set different filter for a peer.
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1 view 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.1 distribute-list 1 in
+!
+router bgp 1 view 2
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.1 distribute-list 2 in
+@end group
+@end example
+
+This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view
+2.  When the update is inserted into view 1, distribute-list 1 is
+applied.  On the other hand, when the update is inserted into view 2,
+distribute-list 2 is applied.
+
+@node Viewing the view,  , Routing policy, Route Server
+@comment  node-name,  next,  previous,  up
+@subsection Viewing the view
+
+To display routing table of BGP view, you must specify view name.
+
+@deffn {Command} {show ip bgp view @var{name}} {}
+Display routing table of BGP view @var{name}.
+@end deffn
+
+@node How to set up a 6-Bone connection, Dump BGP packets and table, Route Server, BGP
+@comment  node-name,  next,  previous,  up
+@section How to set up a 6-Bone connection
+
+@example
+@group
+zebra configuration 
+=================== 
+!  
+! Actually there is no need to configure zebra 
+!
+
+bgpd configuration
+==================
+!
+! This means that routes go through zebra and into the kernel.
+!
+router zebra
+!
+! MP-BGP configuration
+!
+router bgp 7675
+ bgp router-id 10.0.0.1
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as @var{as-number}
+!
+ address-family ipv6
+ network 3ffe:506::/32
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out
+ neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as @var{as-number}
+ neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out
+ exit-address-family
+!
+ipv6 access-list all permit any
+!
+! Set output nexthop address.
+!
+route-map set-nexthop permit 10
+ match ipv6 address all
+ set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225
+ set ipv6 nexthop local fe80::2c0:4fff:fe68:a225
+!
+! logfile FILENAME is obsolete.  Please use log file FILENAME
+!
+log file bgpd.log
+!
+@end group
+@end example
+
+@node Dump BGP packets and table,  , How to set up a 6-Bone connection, BGP
+@comment  node-name,  next,  previous,  up
+@section Dump BGP packets and table
+
+@deffn Command {dump bgp all @var{path}} {}
+@deffnx Command {dump bgp all @var{path} @var{interval}} {}
+Dump all BGP packet and events to @var{path} file.
+@end deffn 
+
+@deffn Command {dump bgp updates @var{path}} {}
+@deffnx Command {dump bgp updates @var{path} @var{interval}} {}
+Dump BGP updates to @var{path} file.
+@end deffn
+
+@deffn Command {dump bgp routes @var{path}} {}
+@deffnx Command {dump bgp routes @var{path}} {}
+Dump whole BGP routing table to @var{path}.  This is heavy process.
+@end deffn
diff --git a/doc/draft-zebra-00.ms b/doc/draft-zebra-00.ms
new file mode 100644 (file)
index 0000000..2599472
--- /dev/null
@@ -0,0 +1,209 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Ishiguro
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH RFC DRAFT
+.ds RH March 1998
+.ds CH
+.hy 0
+.ad l
+Network Working Group                                        K. Ishiguro
+Request for Comments: DRAFT                     Digital Magic Labs, Inc.
+                                                              March 1998
+.sp 2
+.ce
+Zebra Protocol Draft
+.sp 2
+.fi
+.ne 4
+Status of this Memo
+.sp
+.in 3
+This draft is very eary beta version.
+.sp
+.in 0
+.ne 4
+Introduction
+.sp
+.in 3
+The zebra protocol is a communication protocol between kernel
+routing table manager and routing protocol daemon. It is built over
+TCP/IP protocol suite.
+.sp
+.in 0
+.ne 4
+Request message formats
+.sp
+.in 3
+zebra is TCP-based protocol.
+.sp
+Below is request packet format.
+.sp
+.in 0
+.DS
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|           Length (2)          |   Command (1) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Length is total packet length.
+.sp
+Here is summary of command list.
+.sp
+.in 0
+.DS
+1 - ZEBRA_IPV4_ROUTE_ADD
+2 - ZEBRA_IPV4_ROUTE_DELETE
+3 - ZEBRA_IPV6_ROUTE_ADD
+4 - ZEBRA_IPV6_ROUTE_DELETE
+5 - ZEBRA_GET_ONE_INTERFACE
+6 - ZEBRA_GET_ALL_INTERFACE
+7 - ZEBRA_GET_HOSTINFO
+.DE
+.sp
+.in 0
+.ne 4
+IPv4 reply message formats
+.sp
+.in 0
+.DS
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+
+|    Type (1)   |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                            Gateway (4)                        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Type field specify route's origin type.
+.sp
+.in 0
+.DS
+1 - ZEBRA_ROUTE_RESERVE
+2 - ZEBRA_ROUTE_CONNECT
+3 - ZEBRA_ROUTE_STATIC
+4 - ZEBRA_ROUTE_RIP
+5 - ZEBRA_ROUTE_RIPNG
+6 - ZEBRA_ROUTE_BGP
+7 - ZEBRA_ROUTE_RADIX
+.DE
+.sp
+.in 3
+After above message there can be variale length IPv4 prefix data.
+Each IPv4 prefix is encoded as a two tuple of the form <masklength,
+prefix>
+.sp
+.in 0
+.DS
++----------------------+
+|Subnet mask (1 octet) |
++----------------------+
+|IPv4 prefix (variable)|
++----------------------+
+.DE
+.sp
+.in 0
+.ne 4
+IPv6 reply message formats
+.sp
+.in 0
+.DS
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+
+|    Type (1)   |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                           Gateway (16)                        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Type field specify route's origin type.
+.sp
+.in 0
+.DS
+1 - ZEBRA_ROUTE_RESERVE
+2 - ZEBRA_ROUTE_CONNECT
+3 - ZEBRA_ROUTE_STATIC
+4 - ZEBRA_ROUTE_RIP
+5 - ZEBRA_ROUTE_RIPNG
+6 - ZEBRA_ROUTE_BGP
+7 - ZEBRA_ROUTE_RADIX
+.DE
+.sp
+.in 0
+.DS
++----------------------+
+|  ifindex   (4 octet) |
++----------------------+
+|  prefixlen  (1 octet)|
++----------------------+
+|IPv6 prefix (variable)|
++----------------------+
+.DE
+.sp
+.in 3
+I am not sure but it seems some operation systems IPv6
+implementation may need interface index when add and delete
+linklocal routes.
+.sp
+I have added ifindex field to specify IPv6 routes interface
+index. If this index is value zero, it will ignored.
+.sp
+.in 0
+.ne 4
+Interface information message format.
+.sp
+.in 0
+.DS
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                      Interface name (20)                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Index (1)   |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                       Inteface flag (4)                       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                      Inteface metric (4)                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Inteface MTU (4)                       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                    Inteface Address count (4)                 |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Address message format.
+.sp
+.in 0
+.ne 4
+Host inforamtion message format.
+.sp
+.in 0
+.DS
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|IPv4 forwarding|IPv6 forwarding|
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.DE
+.sp
+.in 3
+Host information contain IPv4/IPv6 forwarding information.
diff --git a/doc/filter.texi b/doc/filter.texi
new file mode 100644 (file)
index 0000000..1bc70cd
--- /dev/null
@@ -0,0 +1,192 @@
+@node Filtering
+@comment  node-name,  next,  previous,  up
+@chapter Filtering
+
+Zebra provides many very flexible filtering features.  Filtering is used
+for both input and output of the routing information.  Once filtering is
+defined, it can be applied in any direction.
+
+@menu
+* IP Access List::              
+* IP Prefix List::              
+@end menu
+
+@node IP Access List, IP Prefix List, Filtering, Filtering
+@comment  node-name,  next,  previous,  up
+@subsection IP Access List
+
+@deffn {Command} {access-list @var{name} permit @var{ipv4-network}} {}
+@deffnx {Command} {access-list @var{name} deny @var{ipv4-network}} {}
+@end deffn
+
+Basic filtering is done by @code{access-list} as shown in the
+following example.
+
+@example
+access-list filter deny 10.0.0.0/9
+access-list filter permit 10.0.0.0/8
+@end example
+
+@node IP Prefix List,  , IP Access List, Filtering
+@comment  node-name,  next,  previous,  up
+@subsection IP Prefix List
+
+@command{ip prefix-list} provides the most powerful prefix based
+filtering mechanism.  In addition to @command{access-list} functionality,
+@command{ip prefix-list} has prefix length range specification and
+sequential number specification.  You can add or delete prefix based
+filters to arbitrary points of prefix-list using sequential number specification.
+
+If no ip prefix-list is specified, it acts as permit.  If @command{ip prefix-list} 
+is defined, and no match is found, default deny is applied.
+
+@c @deffn {Command} {ip prefix-list @var{name} [seq @var{number}] permit|deny [le @var{prefixlen}] [ge @var{prefixlen}]} {}
+@deffn {Command} {ip prefix-list @var{name} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {}
+@deffnx {Command} {ip prefix-list @var{name} seq @var{number} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {}
+
+You can create @command{ip prefix-list} using above commands.
+
+@table @asis
+
+@item @asis{seq}
+seq @var{number} can be set either automatically or manually.  In the
+case that sequential numbers are set manually, the user may pick any
+number less than 4294967295.  In the case that sequential number are set
+automatically, the sequential number will increase by a unit of five (5)
+per list.  If a list with no specified sequential number is created
+after a list with a specified sequential number, the list will
+automatically pick the next multiple of five (5) as the list number.
+For example, if a list with number 2 already exists and a new list with
+no specified number is created, the next list will be numbered 5.  If
+lists 2 and 7 already exist and a new list with no specified number is
+created, the new list will be numbered 10.
+
+@item @asis{le}
+@command{le} command specifies prefix length.  The prefix list will be 
+applied if the prefix length is less than or equal to the le prefix length.
+
+@item @asis{ge}
+@command{ge} command specifies prefix length.  The prefix list will be 
+applied if the prefix length is greater than or equal to the ge prefix length.
+
+@end table
+
+@end deffn
+
+Less than or equal to prefix numbers and greater than or equal to
+prefix numbers can be used together.  The order of the le and ge
+commands does not matter.
+
+If a prefix list with a different sequential number but with the exact
+same rules as a previous list is created, an error will result.
+However, in the case that the sequential number and the rules are
+exactly similar, no error will result.
+
+If a list with the same sequential number as a previous list is created,
+the new list will overwrite the old list.
+
+Matching of IP Prefix is performed from the smaller sequential number to the
+larger.  The matching will stop once any rule has been applied.
+
+In the case of no le or ge command, 
+
+Version 0.85: the matching rule will apply to all prefix lengths that
+matched the prefix list.
+
+Version 0.86 or later: In the case of no le or ge command, the prefix
+length must match exactly the length specified in the prefix list.
+
+
+@deffn {Command} {no ip prefix-list @var{name}} {}
+@end deffn
+
+@menu
+* ip prefix-list description::  
+* ip prefix-list sequential number control::  
+* Showing ip prefix-list::      
+* Clear counter of ip prefix-list::  
+@end menu
+
+@node ip prefix-list description, ip prefix-list sequential number control, IP Prefix List, IP Prefix List
+@comment  node-name,  next,  previous,  up
+@subsubsection ip prefix-list description
+
+@deffn {Command} {ip prefix-list @var{name} description @var{desc}} {}
+Descriptions may be added to prefix lists.  This command adds a
+description to the prefix list.
+@end deffn
+
+@deffn {Command} {no ip prefix-list @var{name} description [@var{desc}]} {}
+Deletes the description from a prefix list.  It is possible to use the
+command without the full description.
+@end deffn
+
+@node  ip prefix-list sequential number control, Showing ip prefix-list, ip prefix-list description, IP Prefix List
+@comment  node-name,  next,  previous,  up
+@subsubsection ip prefix-list sequential number control
+
+@deffn {Command} {ip prefix-list sequence-number} {}
+With this command, the IP prefix list sequential number is displayed.
+This is the default behavior.
+@end deffn
+
+@deffn {Command} {no ip prefix-list sequence-number} {}
+With this command, the IP prefix list sequential number is not
+displayed.
+@end deffn
+
+@node  Showing ip prefix-list, Clear counter of ip prefix-list, ip prefix-list sequential number control, IP Prefix List
+@comment  node-name,  next,  previous,  up
+@subsubsection Showing ip prefix-list
+
+@deffn {Command} {show ip prefix-list} {}
+Display all IP prefix lists.
+@end deffn
+
+@deffn {Command} {show ip prefix-list @var{name}} {}
+Show IP prefix list can be used with a prefix list name.
+@end deffn
+
+@deffn {Command} {show ip prefix-list @var{name} seq @var{num}} {}
+Show IP prefix list can be used with a prefix list name and sequential
+number.
+@end deffn
+
+@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m}} {}
+If the command longer is used, all prefix lists with prefix lengths equal to
+or longer than the specified length will be displayed.
+If the command first match is used, the first prefix length match will be
+displayed.
+@end deffn
+
+@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} longer} {}
+@end deffn
+
+@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} first-match} {}
+@end deffn
+
+@deffn {Command} {show ip prefix-list summary} {}
+@end deffn
+@deffn {Command} {show ip prefix-list summary @var{name}} {}
+@end deffn
+
+@deffn {Command} {show ip prefix-list detail} {}
+@end deffn
+@deffn {Command} {show ip prefix-list detail @var{name}} {}
+@end deffn
+
+@node  Clear counter of ip prefix-list,  , Showing ip prefix-list, IP Prefix List
+@comment  node-name,  next,  previous,  up
+@subsubsection Clear counter of ip prefix-list
+
+@deffn {Command} {clear ip prefix-list} {}
+Clears the counters of all IP prefix lists.  Clear IP Prefix List can be
+used with a specified name and prefix.
+@end deffn
+
+@deffn {Command} {clear ip prefix-list @var{name}} {}
+@end deffn
+
+@deffn {Command} {clear ip prefix-list @var{name} @var{a.b.c.d/m}} {}
+@end deffn
+
diff --git a/doc/install.texi b/doc/install.texi
new file mode 100644 (file)
index 0000000..72c826d
--- /dev/null
@@ -0,0 +1,218 @@
+@node  Installation, Basic commands, Overview, Top
+@comment  node-name,  next,  previous,  up
+@chapter Installation
+
+@cindex How to install Zebra
+@cindex Installation
+@cindex Installing Zebra
+@cindex Building the system
+@cindex Making Zebra
+
+  There are three steps for installing the software: configuration,
+compilation, and installation.
+
+@menu
+* Configure the Software::      
+* Build the Software::          
+* Install the Software::        
+@end menu
+
+  The easiest way to get Zebra running is to issue the following
+commands:
+
+@example
+% configure
+% make
+% make install
+@end example
+
+@node Configure the Software, Build the Software, Installation, Installation
+@comment  node-name,  next,  previous,  up
+@section Configure the Software
+
+@cindex Configuration options
+@cindex Options for configuring
+@cindex Build options
+@cindex Distribution configuration
+@cindex Options to @code{./configure}
+  Zebra has an excellent configure script which
+automatically detects most host configurations.  There are several
+additional configure options you can use to turn off IPv6 support, to
+disable the compilation of specific daemons, and to enable SNMP support.
+
+@table @option
+@item --enable-guile
+Turn on compilation of the zebra-guile interpreter.  You will need the
+guile library to make this.  zebra-guile implementation is not yet
+finished.  So this option is only useful for zebra-guile developers.
+@item --disable-ipv6
+Turn off IPv6 related features and daemons.  Zebra configure script
+automatically detects IPv6 stack.  But sometimes you might want to
+disable IPv6 support of Zebra.
+@item --disable-zebra
+Do not build zebra daemon.
+@item --disable-ripd
+Do not build ripd.
+@item --disable-ripngd
+Do not build ripngd.
+@item --disable-ospfd
+Do not build ospfd.
+@item --disable-ospf6d
+Do not build ospf6d.
+@item --disable-bgpd
+Do not build bgpd.
+@item --disable-bgp-announce
+Make @command{bgpd} which does not make bgp announcements at all.  This
+feature is good for using @command{bgpd} as a BGP announcement listener.
+@item --enable-netlink
+Force to enable @sc{gnu}/Linux netlink interface.  Zebra configure
+script detects netlink interface by checking a header file.  When the header
+file does not match to the current running kernel, configure script will
+not turn on netlink support.
+@item --enable-snmp
+Enable SNMP support.  By default, SNMP support is disabled.
+@end table
+
+You may specify any combination of the above options to the configure
+script.  By default, the executables are placed in @file{/usr/local/sbin} 
+and the configuration files in @file{/usr/local/etc}. The @file{/usr/local/}
+installation prefix and other directories may be changed using the following 
+options to the configuration script.
+
+@table @option
+@item --prefix=@var{prefix}
+Install architecture-independent files in @var{prefix} [/usr/local].
+@item --sysconfdir=@var{dir}
+Read-only sample configuration file in @var{dir} [@var{prefix}/etc].
+@end table
+
+@example
+% ./configure --disable-ipv6
+@end example
+
+This command will configure zebra and the routing daemons.
+
+@cindex Configuring Zebra
+@cindex Configuration the software build
+@cindex Building on Linux boxes
+@cindex Linux configurations
+
+There are several options available only to @sc{gnu}/Linux systems:
+@footnote{GNU/Linux has very flexible kernel configuration features.  If
+you use GNU/Linux, make sure that the current kernel configuration is
+what you want.  Zebra will run with any kernel configuration but some
+recommendations do exist.
+
+@table @var
+
+@item CONFIG_NETLINK
+Kernel/User netlink socket.  
+This is a brand new feature which enables
+an advanced interface between the Linux kernel and Zebra (@pxref{Kernel Interface}).
+
+@item CONFIG_RTNETLINK
+Routing messages.
+This makes it possible to receive netlink routing messages.  If you
+specify this option, @command{zebra} can detect routing information
+updates directly from the kernel (@pxref{Kernel Interface}).
+
+@item CONFIG_IP_MULTICAST
+IP: multicasting.  
+This option should be specified when you use @command{ripd} or
+@command{ospfd} because these protocols use multicast.
+
+@end table
+
+IPv6 support has been added in @sc{gnu}/Linux kernel version 2.2.  If you
+try to use the Zebra IPv6 feature on a @sc{gnu}/Linux kernel, please
+make sure the following libraries have been installed.  Please note that
+these libraries will not be needed when you uses @sc{gnu} C library 2.1
+or upper.
+
+@table @code
+
+@item inet6-apps
+The @code{inet6-apps} package includes basic IPv6 related libraries such
+as @code{inet_ntop} and @code{inet_pton}.  Some basic IPv6 programs such
+as @command{ping}, @command{ftp}, and @command{inetd} are also
+included. The @code{inet-apps} can be found at
+@url{ftp://ftp.inner.net/pub/ipv6/}.
+
+@item net-tools
+The @code{net-tools} package provides an IPv6 enabled interface and
+routing utility.  It contains @command{ifconfig}, @command{route},
+@command{netstat}, and other tools.  @code{net-tools} may be found at
+@url{http://www.tazenda.demon.co.uk/phil/net-tools/}.
+
+@end table
+@c A - end of footnote 
+}.
+
+@node Build the Software, Install the Software, Configure the Software, Installation
+@comment  node-name,  next,  previous,  up
+@section Build the Software
+
+After configuring the software, you will need to compile it for your
+system. Simply issue the command @command{make} in the root of the source
+directory and the software will be compiled. If you have *any* problems
+at this stage, be certain to send a bug report @xref{Bug Reports}.
+
+@example
+% ./configure
+.
+.
+.
+./configure output
+.
+.
+.
+% make
+@end example
+@c A - End of node, Building the Software
+
+
+@node Install the Software,  , Build the Software, Installation
+@comment  node-name,  next,  previous,  up
+@section Install the Software
+
+Installing the software to your system consists of copying the compiled
+programs and supporting files to a standard location. After the
+installation process has completed, these files have been copied
+from your work directory to @file{/usr/local/bin}, and @file{/usr/local/etc}.
+
+To install the Zebra suite, issue the following command at your shell
+prompt: @command{make install}.
+
+@example
+%
+% make install
+%
+@end example
+
+@c A - removed this section and placed it with Install the Software
+@c @node Additional Notes,  , Install the Software, Installation
+@comment  node-name,  next,  previous,  up
+@c @section Additional Notes
+
+Zebra daemons have their own terminal interface or VTY.  After
+installation, you have to setup each beast's port number to connect to
+them.  Please add the following entries to @file{/etc/services}.
+
+@example
+zebrasrv      2600/tcp           # zebra service
+zebra         2601/tcp           # zebra vty
+ripd          2602/tcp           # RIPd vty
+ripngd        2603/tcp           # RIPngd vty
+ospfd         2604/tcp           # OSPFd vty
+bgpd          2605/tcp           # BGPd vty
+ospf6d        2606/tcp           # OSPF6d vty
+@end example
+
+If you use a FreeBSD newer than 2.2.8, the above entries are already
+added to @file{/etc/services} so there is no need to add it. If you
+specify a port number when starting the daemon, these entries may not be
+needed.
+
+You may need to make changes to the config files in
+@file{@value{INSTALL_PREFIX_ETC}/*.conf}. @xref{Config Commands}.
diff --git a/doc/ipv6.texi b/doc/ipv6.texi
new file mode 100644 (file)
index 0000000..c24d145
--- /dev/null
@@ -0,0 +1,32 @@
+@node IPv6 Support, Kernel Interface, Route Map, Top
+@comment  node-name,  next,  previous,  up
+@chapter IPv6 Support
+
+Zebra fully supports IPv6 routing.  As described so far, Zebra supports
+RIPng, OSPFv3 and BGP-4+.  You can give IPv6 addresses to an interface
+and configure static IPv6 routing information.  Zebra-IPv6 also provides
+automatic address configuration via a feature called @code{address
+auto configuration}.  To do it, the router must send router advertisement
+messages to the all nodes that exist on the network.
+
+@menu
+* Router Advertisement::        
+@end menu
+
+@node Router Advertisement,  , IPv6 Support, IPv6 Support
+@comment  node-name,  next,  previous,  up
+@section Router Advertisement
+
+@deffn {Interface Command} {ipv6 nd send-ra} {}
+@end deffn
+
+@deffn {Interface Command} {ipv6 nd prefix-advertisement @var{ipv6prefix}} {}
+@end deffn
+
+@example
+@group
+interface eth0
+ ipv6 nd send-ra
+ ipv6 nd prefix-advertisement 3ffe:506:5009::/64
+@end group
+@end example
diff --git a/doc/kernel.texi b/doc/kernel.texi
new file mode 100644 (file)
index 0000000..b863a1f
--- /dev/null
@@ -0,0 +1,48 @@
+@node Kernel Interface, SNMP Support, IPv6 Support, Top
+@comment  node-name,  next,  previous,  up
+@chapter Kernel Interface
+
+There are several different methods for reading kernel routing table
+information, updating kernel routing tables, and for looking up
+interfaces.
+
+@table @samp
+
+@item ioctl
+The @samp{ioctl} method is a very traditional way for reading or writing
+kernel information.  @samp{ioctl} can be used for looking up interfaces
+and for modifying interface addresses, flags, mtu settings and other
+types of information.  Also, @samp{ioctl} can insert and delete kernel
+routing table entries.  It will soon be available on almost any platform
+which zebra supports, but it is a little bit ugly thus far, so if a
+better method is supported by the kernel, zebra will use that.
+
+@item sysctl
+@samp{sysctl} can lookup kernel information using MIB (Management
+Information Base) syntax.  Normally, it only provides a way of getting
+information from the kernel.  So one would usually want to change kernel
+information using another method such as @samp{ioctl}.
+
+@item proc filesystem
+@samp{proc filesystem} provides an easy way of getting kernel
+information.
+
+@item routing socket
+
+@item netlink
+On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user
+communication support called @code{netlink}.  It makes asynchronous
+communication between kernel and Zebra possible, similar to a routing
+socket on BSD systems.
+
+Before you use this feature, be sure to select (in kernel configuration) 
+the kernel/netlink support option 'Kernel/User network link driver' and 
+'Routing messages'.
+
+Today, the /dev/route special device file is obsolete.  Netlink
+communication is done by reading/writing over netlink socket.
+
+After the kernel configuration, please reconfigure and rebuild Zebra.
+You can use netlink as a dynamic routing update channel between Zebra
+and the kernel.
+@end table
diff --git a/doc/main.texi b/doc/main.texi
new file mode 100644 (file)
index 0000000..7043bf1
--- /dev/null
@@ -0,0 +1,186 @@
+@node Zebra
+@comment  node-name,  next,  previous,  up
+@chapter Zebra
+
+@c SYNOPSIS
+@command{zebra} is an IP routing manager.  It provides kernel routing
+table updates, interface lookups, and redistribution of routes between
+different routing protocols.
+
+@menu
+* Invoking zebra::              Running the program
+* Interface Commands::          Commands for zebra interfaces
+* Static Route Commands::       Commands for adding static routes
+* zebra Terminal Mode Commands::  Commands for zebra's VTY
+@end menu
+
+
+@node Invoking zebra, Interface Commands, Zebra, Zebra
+@comment  node-name,  next,  previous,  up
+@section Invoking zebra
+
+Besides the common invocation options (@pxref{Common Invocation Options}), the
+@command{zebra} specific invocation options are listed below.
+
+@table @samp
+@item -b
+@itemx --batch
+Runs in batch mode.  @command{zebra} parses configuration file and terminates
+immediately.
+
+@item -k
+@itemx --keep_kernel
+When zebra starts up, don't delete old self inserted routes.
+
+@item -l
+@itemx --log_mode
+Set verbose logging on.
+
+@item -r
+@itemx --retain
+When program terminates, retain routes added by zebra.
+
+@end table
+
+@node Interface Commands, Static Route Commands, Invoking zebra, Zebra
+@comment  node-name,  next,  previous,  up
+@section Interface Commands
+
+@deffn Command {interface @var{ifname}} {}
+@end deffn
+
+@deffn {Interface Command} {shutdown} {}
+@deffnx {Interface Command} {no shutdown} {}
+Up or down the current interface.
+@end deffn
+
+@deffn {Interface Command} {ip address @var{address}} {}
+Set ip address for the interface.
+@end deffn
+
+@deffn {Interface Command} {description @var{description} ...} {}
+Set description for the interface.
+@end deffn
+
+@deffn {Interface Command} {multicast} {}
+@deffnx {Interface Command} {no multicast} {}
+Enable or disables multicast flag for the interface.
+@end deffn
+
+@deffn {Interface Command} {bandwidth <1-10000000>} {}
+@deffnx {Interface Command} {no bandwidth <1-10000000>} {}
+Set bandwidth value to the interface.  This is for calculating OSPF
+cost.  This command does not affect the actual device configuration.
+@end deffn
+
+@node Static Route Commands, zebra Terminal Mode Commands, Interface Commands, Zebra
+@comment  node-name,  next,  previous,  up
+@section Static Route Commands
+
+Static routing is a very fundamental feature of routing technology.  It
+defines static prefix and gateway.
+
+@deffn Command {ip route @var{network} @var{gateway}} {}
+@var{network} is destination prefix with format of A.B.C.D/M.
+@var{gateway} is gateway for the prefix.  When @var{gateway} is
+A.B.C.D format.  It is taken as a IPv4 address gateway.  Otherwise it
+is treated as an interface name.
+
+@example
+ip route 10.0.0.0/8 10.0.0.2
+ip route 10.0.0.0/8 ppp0
+@end example
+
+First example defines 10.0.0.0/8 static route with gateway 10.0.0.2.
+Second one defines the same prefix but with gateway to interface ppp0.
+@end deffn
+
+@deffn Command {ip route @var{network} @var{netmask} @var{gateway}} {}
+This is alternate version of above command.  When @var{network} is
+A.B.C.D format, user must define @var{netmask} value with A.B.C.D
+format.  @var{gateway} is same option as above command
+
+@example
+ip route 10.0.0.0 255.255.255.0 10.0.0.2
+ip route 10.0.0.0 255.255.255.0 ppp0
+@end example
+
+This is a same setting using this statement.
+@end deffn
+
+@deffn Command {ip route @var{network} @var{gateway} @var{distance}} {}
+
+@end deffn
+
+Multiple nexthop static route
+
+@example
+ip route 10.0.0.1/32 10.0.0.2
+ip route 10.0.0.1/32 10.0.0.3
+ip route 10.0.0.1/32 eth0
+@end example
+
+If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0
+is reachable, then the last route is installed into the kernel.
+
+@example
+zebra> show ip route
+S>  10.0.0.1/32 [1/0] via 10.0.0.2 inactive
+                      via 10.0.0.3 inactive
+  *                   is directly connected, eth0
+@end example
+
+Floating static route
+
+@deffn Command {ipv6 route @var{network} @var{gateway}} {}
+
+@end deffn
+
+@deffn Command {ipv6 route @var{network} @var{gateway} @var{distance}} {}
+
+@end deffn
+
+
+@deffn Command {table @var{tableno}} {}
+Select the primary kernel routing table to be used.  This only works
+for kernels supporting multiple routing tables (like GNU/Linux 2.2.x
+and later).  After setting @var{tableno} with this command, 
+static routes defined after this are added to the specified table.
+@end deffn
+
+@node zebra Terminal Mode Commands,  , Static Route Commands, Zebra
+@comment  node-name,  next,  previous,  up
+@section zebra Terminal Mode Commands
+
+@deffn Command {show ip route} {}
+Display current routes which zebra holds in its database.
+
+@example
+@group
+Router# show ip route 
+Codes: K - kernel route, C - connected, S - static, R - RIP, 
+       B - BGP * - FIB route.
+
+K* 0.0.0.0/0              203.181.89.241
+S  0.0.0.0/0              203.181.89.1
+C* 127.0.0.0/8            lo
+C* 203.181.89.240/28      eth0
+@end group
+@end example
+@end deffn
+
+@deffn Command {show ipv6 route} {}
+@end deffn
+
+@deffn Command {show interface} {}
+@end deffn
+
+@deffn Command {show ipforward} {}
+Display whether the host's IP forwarding function is enabled or not.
+Almost any UNIX kernel can be configured with IP forwarding disabled.
+If so, the box can't work as a router.
+@end deffn
+
+@deffn Command {show ipv6forward} {}
+Display whether the host's IP v6 forwarding is enabled or not.
+@end deffn
diff --git a/doc/ospf6d.8 b/doc/ospf6d.8
new file mode 100644 (file)
index 0000000..1882c10
--- /dev/null
@@ -0,0 +1,127 @@
+.TH OSPF6D 8 "July 2000" "Zebra Beast - OSPF6D" "Version 0.88"
+
+.SH NAME
+ospf6d \- an OSPF routing engine for use with Zebra and IPv6
+
+.SH SYNOPSIS
+.B ospf6d
+[
+.B \-dhv
+]
+[
+.B \-f config-file
+]
+[
+.B \-i pid-file
+]
+[
+.B \-P port-number
+]
+
+.SH DESCRIPTION
+.B ospf6d 
+is a routing component that works with the 
+.B zebra
+routing engine.
+\fBospf6d\fR. 
+
+
+.SH OPTIONS
+
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR 
+Specifies the config file to use for startup. If not specified this
+option will likely default to \fB\fI/usr/local/etc/ospf6d.conf\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When ospf6d starts its process idenifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart ospf6d.  The likely default is \fB\fI/var/run/ospf6d.pid\fR.
+
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the ospf6d VTY will listen on. This defaults to
+2606, as specified in \fB\fI/etc/services\fR.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+
+
+.SH COMMANDS
+
+\fB router ospf6 \fR
+\fB router zebra \fR -- (Move routes into kernel table)
+
+\fB network [NETWORK] area [OSPF6-AREA-ID] \fR
+\fB no network [NETWORK] \fR
+
+\fB show ip ospf6 interface \fR
+\fB show ip ospf6 neighbor \fR
+\fB show ip ospf6 database \fR
+\fB show ip ospf6 route \fR
+
+\fB debug ospf6 ism \fR
+\fB debug ospf6 packet \fR
+\fB debug ospf6 nsm \fR
+
+
+
+.SH FILES
+
+.TP
+.BI /usr/local/sbin/ospf6d
+The default location of the 
+.B ospf6d
+binary.
+
+.TP
+.BI /usr/local/etc/ospf6d.conf
+The default location of the 
+.B ospf6d
+config file.
+
+.TP
+.BI $(PWD)/ospf6d.log 
+If the 
+.B ospf6d
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBospf6d\fR.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line
+options, and for config file commands. The definitive document is the
+Info file \fBzebra\fR.
+
+
+.SH DIAGNOSTICS
+The ospf6d process may log to standard output, to a VTY, to a log
+file, or through syslog to the system logs. \fBospf6d\fR supports many
+debugging options, see the Info file, or the source for details.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+ripd(8), ripngd(8), ospfd(8), bgpd(8), zebra(8), vtysh(1)
+
+
+.SH BUGS
+.B ospf6d
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi
new file mode 100644 (file)
index 0000000..e3ac3d2
--- /dev/null
@@ -0,0 +1,102 @@
+@node OSPFv3, BGP, OSPFv2, Top
+@comment  node-name,  next,  previous,  up
+@chapter OSPFv3
+
+@command{ospf6d} is a daemon support OSPF version 3 for IPv6 network.
+OSPF for IPv6 is described in RFC2740.
+
+@menu
+* OSPF6 router::                
+* OSPF6 area::                  
+* OSPF6 interface::             
+* Redistribute routes to OSPF6::  
+* Showing OSPF6 information::   
+@end menu
+
+@node OSPF6 router, OSPF6 area, OSPFv3, OSPFv3
+@comment  node-name,  next,  previous,  up
+@section OSPF6 router
+
+@deffn {Command} {router ospf6} {}
+@end deffn
+
+@deffn {OSPF6 Command} {router-id @var{a.b.c.d}} {}
+Set router's Router-ID.
+@end deffn
+
+@deffn {OSPF6 Command} {interface @var{ifname} area @var{area}} {}
+Bind interface to specified area, and start sending OSPF packets.  @var{area} can
+be specified as 0.
+@end deffn
+
+@node OSPF6 area, OSPF6 interface, OSPF6 router, OSPFv3
+@comment  node-name,  next,  previous,  up
+@section OSPF6 area
+
+Area support for OSPFv3 is not yet implemented.
+
+@node OSPF6 interface, Redistribute routes to OSPF6, OSPF6 area, OSPFv3
+@comment  node-name,  next,  previous,  up
+@section OSPF6 interface
+
+@deffn {Interface Command} {ipv6 ospf6 cost COST} {}
+Sets interface's output cost.  Default value is 1.
+@end deffn
+
+@deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {}
+Sets interface's Hello Interval.  Default 40
+@end deffn
+
+@deffn {Interface Command} {ipv6 ospf6 dead-interval DEADINTERVAL} {}
+Sets interface's Router Dead Interval.  Default value is 40.
+@end deffn
+
+@deffn {Interface Command} {ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL} {}
+Sets interface's Rxmt Interval.  Default value is 5.
+@end deffn
+
+@deffn {Interface Command} {ipv6 ospf6 priority PRIORITY} {}
+Sets interface's Router Priority.  Default value is 1.
+@end deffn
+
+@deffn {Interface Command} {ipv6 ospf6 transmit-delay TRANSMITDELAY} {}
+Sets interface's Inf-Trans-Delay.  Default value is 1.
+@end deffn
+
+@node Redistribute routes to OSPF6, Showing OSPF6 information, OSPF6 interface, OSPFv3
+@comment  node-name,  next,  previous,  up
+@section Redistribute routes to OSPF6
+
+@deffn {OSPF6 Command} {redistribute static} {}
+@deffnx {OSPF6 Command} {redistribute connected} {}
+@deffnx {OSPF6 Command} {redistribute ripng} {}
+@end deffn
+
+@node Showing OSPF6 information,  , Redistribute routes to OSPF6, OSPFv3
+@comment  node-name,  next,  previous,  up
+@section Showing OSPF6 information
+
+@deffn {Command} {show ipv6 ospf6 [INSTANCE_ID]} {}
+INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF
+instance ID, simply type "show ipv6 ospf6 <cr>".
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 database} {}
+This command shows LSA database summary.  You can specify the type of LSA.
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 interface} {}
+To see OSPF interface configuration like costs.
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 neighbor} {}
+Shows state and chosen (Backup) DR of neighbor.
+@end deffn
+
+@deffn {Command} {show ipv6 ospf6 request-list A.B.C.D} {}
+Shows requestlist of neighbor.
+@end deffn
+
+@deffn {Command} {show ipv6 route ospf6} {}
+This command shows internal routing table.
+@end deffn
diff --git a/doc/ospfd.8 b/doc/ospfd.8
new file mode 100644 (file)
index 0000000..0fbfce4
--- /dev/null
@@ -0,0 +1,131 @@
+.TH OSPFD 8 "July 2000" "Zebra Beast - OSPFD" "Version 0.88"
+
+.SH NAME
+ospfd \- an OSPF v2 routing engine for use with Zebra
+
+.SH SYNOPSIS
+.B ospfd
+[
+.B \-dhlv
+]
+[
+.B \-f config-file
+]
+[
+.B \-i pid-file
+]
+[
+.B \-P port-number
+]
+
+.SH DESCRIPTION
+.B ospfd 
+is a routing component that works with the 
+.B zebra
+routing engine.
+
+
+.SH OPTIONS
+
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR 
+Specifies the config file to use for startup. If not specified this
+option will likely default to \fB\fI/usr/local/etc/ospfd.conf\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When ospfd starts its process idenifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart ospfd.  The likely default is \fB\fI/var/run/ospfd.pid\fR.
+
+.TP
+\fB\-l\fR, \fB\-\-log_mode\fR
+Turn verbose logging on.
+
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the ospfd VTY will listen on. This defaults to
+2604, as specified in \fB\fI/etc/services\fR.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+
+
+.SH COMMANDS
+
+\fB router ospf \fR
+\fB router zebra \fR -- (Move routes into kernel table)
+
+\fB network [NETWORK] area [OSPF-AREA-ID] \fR
+\fB no network [NETWORK] \fR
+
+\fB show ip ospf interface \fR
+\fB show ip ospf neighbor \fR
+\fB show ip ospf database \fR
+\fB show ip ospf route \fR
+
+
+\fB debug ospf ism \fR
+\fB debug ospf packet \fR
+\fB debug ospf nsm \fR
+
+
+
+.SH FILES
+
+.TP
+.BI /usr/local/sbin/ospfd
+The default location of the 
+.B ospfd
+binary.
+
+.TP
+.BI /usr/local/etc/ospfd.conf
+The default location of the 
+.B ospfd
+config file.
+
+.TP
+.BI $(PWD)/ospfd.log 
+If the 
+.B ospfd
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBospfd\fR.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line
+options, and for config file commands. The definitive document is the
+Info file \fBzebra\fR.
+
+
+.SH DIAGNOSTICS
+The ospfd process may log to standard output, to a VTY, to a log
+file, or through syslog to the system logs. \fBospfd\fR supports many
+debugging options, see the Info file, or the source for details.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+ripd(8), ripngd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1)
+
+
+.SH BUGS
+.B ospfd
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/ospfd.texi b/doc/ospfd.texi
new file mode 100644 (file)
index 0000000..5952c05
--- /dev/null
@@ -0,0 +1,345 @@
+@node OSPFv2, OSPFv3, RIPng, Top
+@comment  node-name,  next,  previous,  up
+@chapter OSPFv2
+
+  OSPF version 2 is a routing protocol which described in
+@asis{RFC2328} - @cite{OSPF Version 2}.  OSPF is IGP (Interior Gateway
+Protocols).  Compared with RIP, OSPF can provide scalable network
+support and faster convergence time.  OSPF is widely used in large
+networks such as ISP backbone and enterprise networks.
+
+@menu
+* Configuring ospfd::           
+* OSPF router::                 
+* OSPF area::                   
+* OSPF interface::              
+* Redistribute routes to OSPF::  
+* Showing OSPF information::    
+* Debugging OSPF::              
+@end menu
+
+@node Configuring ospfd, OSPF router, OSPFv2, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section Configuring ospfd
+
+There is no @command{ospfd} specific options.  Common options can be
+specified (@pxref{Common Invocation Options}) to @command{ospfd}.
+@command{ospfd} needs interface information from @command{zebra}.  So
+please make it sure @command{zebra} is running before invoking
+@command{ospfd}.
+
+Like other daemons, @command{ospfd} configuration is done in OSPF
+specific configuration file @file{ospfd.conf}.
+
+@node OSPF router, OSPF area, Configuring ospfd, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section OSPF router
+
+To start OSPF process you have to specify the OSPF router.  As of this
+writing, @command{ospfd} does not support multiple OSPF processes.
+
+@deffn Command {router ospf} {}
+@deffnx Command {no router ospf} {}
+Enable or disable the OSPF process.  @command{ospfd} does not yet
+support multiple OSPF processes.  So you can not specify an OSPF process
+number.
+@end deffn
+
+@deffn {OSPF Command} {ospf router-id @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no ospf router-id} {}
+@end deffn
+
+@deffn {OSPF Command} {ospf abr-type @var{type}} {}
+@deffnx {OSPF Command} {no ospf abr-type @var{type}} {}
+@var{type} can be cisco|ibm|shortcut|standard
+@end deffn
+
+@deffn {OSPF Command} {ospf rfc1583compatibility} {}
+@deffnx {OSPF Command} {no ospf rfc1583compatibility} {}
+@end deffn
+
+@deffn {OSPF Command} {passive interface @var{interface}} {}
+@deffnx {OSPF Command} {no passive interface @var{interface}} {}
+@end deffn
+
+@deffn {OSPF Command} {timers spf <0-4294967295> <0-4294967295>} {}
+@deffnx {OSPF Command} {no timers spf} {}
+@end deffn
+
+@deffn {OSPF Command} {refresh group-limit <0-10000>} {}
+@deffnx {OSPF Command} {refresh per-slice <0-10000>} {}
+@deffnx {OSPF Command} {refresh age-diff <0-10000>} {}
+@end deffn
+
+@deffn {OSPF Command} {auto-cost refrence-bandwidth <1-4294967>} {}
+@deffnx {OSPF Command} {no auto-cost refrence-bandwidth} {}
+@end deffn
+
+@deffn {OSPF Command} {network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
+@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
+This command specifies the OSPF enabled interface.  If the interface has
+an address of 10.0.0.1/8 then the command below provides network
+information to the ospf routers
+@example
+@group
+router ospf
+ network 10.0.0.0/8 area 0
+@end group
+@end example
+the network command's mask length should be the same as the interface
+address's mask.
+@end deffn
+
+@node OSPF area, OSPF interface, OSPF router, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section OSPF area
+
+@deffn {OSPF Command} {area @var{a.b.c.d} range @var{a.b.c.d/m}} {}
+@deffnx {OSPF Command} {area <0-4294967295> range @var{a.b.c.d/m}} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} range @var{a.b.c.d/m}} {}
+@deffnx {OSPF Command} {no area <0-4294967295> range @var{a.b.c.d/m}} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX suppress} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX suppress} {}
+@deffnx {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {area <0-4294967295> virtual-link @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no area <0-4294967295> virtual-link @var{a.b.c.d}} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} shortcut} {}
+@deffnx {OSPF Command} {area <0-4294967295> shortcut} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} shortcut} {}
+@deffnx {OSPF Command} {no area <0-4294967295> shortcut} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} stub} {}
+@deffnx {OSPF Command} {area <0-4294967295> stub} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} stub} {}
+@deffnx {OSPF Command} {no area <0-4294967295> stub} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} stub no-summary} {}
+@deffnx {OSPF Command} {area <0-4294967295> stub no-summary} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} stub no-summary} {}
+@deffnx {OSPF Command} {no area <0-4294967295> stub no-summary} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} default-cost <0-16777215>} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} default-cost <0-16777215>} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} export-list NAME} {}
+@deffnx {OSPF Command} {area <0-4294967295> export-list NAME} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} export-list NAME} {}
+@deffnx {OSPF Command} {no area <0-4294967295> export-list NAME} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} import-list NAME} {}
+@deffnx {OSPF Command} {area <0-4294967295> import-list NAME} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} import-list NAME} {}
+@deffnx {OSPF Command} {no area <0-4294967295> import-list NAME} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} authentication} {}
+@deffnx {OSPF Command} {area <0-4294967295> authentication} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} authentication} {}
+@deffnx {OSPF Command} {no area <0-4294967295> authentication} {}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} authentication message-digest} {}
+@deffnx {OSPF Command} {area <0-4294967295> authentication message-digest} {}
+@end deffn
+
+@node OSPF interface, Redistribute routes to OSPF, OSPF area, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section OSPF interface
+
+@deffn {Interface Command} {ip ospf authentication-key AUTH_KEY} {}
+@deffnx {Interface Command} {no ip ospf authentication-key} {}
+Set OSPF authentication key to a simple password.  After setting @var{AUTH_KEY},
+all OSPF packets are authenticated. @var{AUTH_KEY} has length up to 8 chars.
+@end deffn
+
+@deffn {Interface Command} {ip ospf message-digest-key KEYID md5 KEY} {}
+@deffnx {Interface Command} {no ip ospf message-digest-key} {}
+Set OSPF authentication key to a cryptographic password.  The cryptographic
+algorithm is MD5.  KEYID identifies secret key used to create the message
+digest.  KEY is the actual message digest key up to 16 chars.
+@end deffn
+
+@deffn {Interface Command} {ip ospf cost <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf cost} {}
+Set link cost for the specified interface.  The cost value is set to router-LSA's
+metric field and used for SPF calculation.
+@end deffn
+
+@deffn {Interface Command} {ip ospf dead-interval <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf dead-interval} {}
+Set number of seconds for RouterDeadInterval timer value used for Wait Timer
+and Inactivity Timer.  This value must be the same for all routers attached
+to a common network.  The default value is 40 seconds.
+@end deffn
+
+@deffn {Interface Command} {ip ospf hello-interval <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf hello-interval} {}
+Set number of seconds for HelloInterval timer value.  Setting this value,
+Hello packet will be sent every timer value seconds on the specified interface.
+This value must be the same for all routers attached to a common network.
+The default value is 10 seconds.
+@end deffn
+
+@deffn {Interface Command} {ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)} {}
+@deffnx {Interface Command} {no ip ospf network} {}
+Set explicitly network type for specifed interface.
+@end deffn
+
+@deffn {Interface Command} {ip ospf priority <0-255>} {}
+@deffnx {Interface Command} {no ip ospf priority} {}
+Set RouterPriority integer value.  Setting higher value, router will be more
+eligible to become Designated Router.  Setting the value to 0, router is no
+longer eligible to Designated Router.
+The default value is 1.
+@end deffn
+
+@deffn {Interface Command} {ip ospf retransmit-interval <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf retransmit interval} {}
+Set number of seconds for RxmtInterval timer value.  This value is used
+when retransmitting Database Description and Link State Request packets.
+The default value is 5 seconds.
+@end deffn
+
+@deffn {Interface Command} {ip ospf transmit-delay} {}
+@deffnx {Interface Command} {no ip ospf transmit-delay} {}
+Set number of seconds for InfTransDelay value.  LSAs' age should be 
+incremented by this value when transmitting.
+The default value is 1 seconds.
+@end deffn
+
+@node Redistribute routes to OSPF, Showing OSPF information, OSPF interface, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section Redistribute routes to OSPF
+
+@deffn {OSPF Command} {redistribute (kernel|connected|static|rip|bgp)} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) @var{route-map}} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map @var{word}} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map @var{word}} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map @var{word}} {}
+@deffnx {OSPF Command} {no redistribute (kernel|connected|static|rip|bgp)} {}
+@end deffn
+
+@deffn {OSPF Command} {default-information originate} {}
+@deffnx {OSPF Command} {default-information originate metric <0-16777214>} {}
+@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2)} {}
+@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2) route-map @var{word}} {}
+@deffnx {OSPF Command} {default-information originate always} {}
+@deffnx {OSPF Command} {default-information originate always metric <0-16777214>} {}
+@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2)} {}
+@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2) route-map @var{word}} {}
+@deffnx {OSPF Command} {no default-information originate} {}
+@end deffn
+
+@deffn {OSPF Command} {distribute-list NAME out (kernel|connected|static|rip|ospf} {}
+@deffnx {OSPF Command} {no distribute-list NAME out (kernel|connected|static|rip|ospf} {}
+@end deffn
+
+@deffn {OSPF Command} {default-metric <0-16777214>} {}
+@deffnx {OSPF Command} {no default-metric} {}
+@end deffn
+
+@deffn {OSPF Command} {distance <1-255>} {}
+@deffnx {OSPF Command} {no distance <1-255>} {}
+@end deffn
+
+@deffn {OSPF Command} {distance ospf (intra-area|inter-area|external) <1-255>} {}
+@deffnx {OSPF Command} {no distance ospf} {}
+@end deffn
+
+@deffn {Command} {router zebra} {}
+@deffnx {Command} {no router zebra} {}
+@end deffn
+
+@node Showing OSPF information, Debugging OSPF, Redistribute routes to OSPF, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section Showing OSPF information
+
+@deffn {Command} {show ip ospf} {}
+@end deffn
+
+@deffn {Command} {show ip ospf interface [INTERFACE]} {}
+@end deffn
+
+@deffn {Command} {show ip ospf neighbor} {}
+@deffnx {Command} {show ip ospf neighbor INTERFACE} {}
+@deffnx {Command} {show ip ospf neighbor detail} {}
+@deffnx {Command} {show ip ospf neighbor INTERFACE detail} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database max-age} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database self-originate} {}
+@end deffn
+
+@deffn {Command} {show ip ospf refresher} {}
+@end deffn
+
+@deffn {Command} {show ip ospf route} {}
+@end deffn
+
+@node Debugging OSPF,  , Showing OSPF information, OSPFv2
+@comment  node-name,  next,  previous,  up
+@section Debugging OSPF
+
+@deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {}
+@deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {}
+@end deffn
+
+@deffn {Command} {debug ospf ism} {}
+@deffnx {Command} {debug ospf ism (status|events|timers)} {}
+@deffnx {Command} {no debug ospf ism} {}
+@deffnx {Command} {no debug ospf ism (status|events|timers)} {}
+@end deffn
+
+@deffn {Command} {debug ospf nsm} {}
+@deffnx {Command} {debug ospf nsm (status|events|timers)} {}
+@deffnx {Command} {no debug ospf nsm} {}
+@deffnx {Command} {no debug ospf nsm (status|events|timers)} {}
+@end deffn
+
+@deffn {Command} {debug ospf lsa} {}
+@deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {}
+@deffnx {Command} {no debug ospf lsa} {}
+@deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {}
+@end deffn
+
+@deffn {Command} {debug ospf zebra} {}
+@deffnx {Command} {debug ospf zebra (interface|redistribute)} {}
+@deffnx {Command} {no debug ospf zebra} {}
+@deffnx {Command} {no debug ospf zebra (interface|redistribute)} {}
+@end deffn
+
+@deffn {Command} {show debugging ospf} {}
+@end deffn
+
diff --git a/doc/overview.texi b/doc/overview.texi
new file mode 100644 (file)
index 0000000..68e6e39
--- /dev/null
@@ -0,0 +1,352 @@
+@node Overview, Installation, Top, Top
+@comment  node-name,  next,  previous,  up
+@chapter Overview
+@cindex Overview
+
+  Zebra is a routing software package that provides TCP/IP based
+routing services with routing protocols support such as RIPv1, RIPv2,
+RIPng, OSPFv2, OSPFv3, BGP-4, and BGP-4+ (@pxref{Supported RFC}).
+Zebra also supports special BGP Route Reflector and Route Server
+behavior.  In addition to traditional IPv4 routing protocols, Zebra
+also supports IPv6 routing protocols.  With SNMP daemon which supports
+SMUX protocol, Zebra provides routing protocol MIBs (@pxref{SNMP
+Support}).
+
+  Zebra uses an advanced software architecture to provide you with a
+high quality, multi server routing engine.  Zebra has an interactive
+user interface for each routing protocol and supports common client
+commands.  Due to this design, you can add new protocol daemons to Zebra
+easily.  You can use Zebra library as your program's client user
+interface.
+
+  Zebra is an official @sc{gnu} software and distributed under the
+@sc{gnu} General Public License.
+
+@menu
+* About Zebra::                 Basic information about Zebra
+* System Architecture::         The Zebra system architecture
+* Supported Platforms::         Supported platforms and future plans
+* Supported RFC::               Supported RFCs
+* How to get Zebra::            
+* Mailing List::                Mailing list information
+* Bug Reports::                 Mail address for bug data
+@end menu
+
+@node About Zebra, System Architecture, Overview, Overview
+@comment  node-name,  next,  previous,  up
+@section About Zebra
+@cindex About Zebra
+
+  Today, TCP/IP networks are covering all of the world.  The Internet
+has been deployed in many countries, companies, and to the home.  When
+you connect to the Internet your packet will pass many routers which
+have TCP/IP routing functionality.
+
+  A system with Zebra installed acts as a dedicated router.  With Zebra,
+your machine exchanges routing information with other routers using
+routing protocols.  Zebra uses this information to update the kernel
+routing table so that the right data goes to the right place.  You can
+dynamically change the configuration and you may view routing table
+information from the Zebra terminal interface.
+
+  Adding to routing protocol support, Zebra can setup interface's flags,
+interface's address, static routes and so on.  If you have a small
+network, or a stub network, or xDSL connection, configuring the Zebra
+routing software is very easy.  The only thing you have to do is to set
+up the interfaces and put a few commands about static routes and/or
+default routes.  If the network is rather large, or if the network
+structure changes frequently, you will want to take advantage of Zebra's
+dynamic routing protocol support for protocols such as RIP, OSPF or BGP.
+Zebra is with you.
+
+  Traditionally, UNIX based router configuration is done by
+@command{ifconfig} and @command{route} commands.  Status of routing
+table is displayed by @command{netstat} utility.  Almost of these
+commands work only if the user has root privileges.  Zebra has a different
+system administration method.  There are two user modes in Zebra.  One is
+normal mode, the other is enable mode.  Normal mode user can only view
+system status, enable mode user can change system configuration.  This
+UNIX account independent feature will be great help to the router
+administrator.
+
+  Currently, Zebra supports common unicast routing protocols.  Multicast
+routing protocols such as BGMP, PIM-SM, PIM-DM will be supported in
+Zebra 2.0.  MPLS support is going on.  In the future, TCP/IP filtering
+control, QoS control, diffserv configuration will be added to Zebra.
+Zebra project's final goal is making a productive, quality free TCP/IP
+routing software.
+
+@node System Architecture, Supported Platforms, About Zebra, Overview
+@comment  node-name,  next,  previous,  up
+@section System Architecture
+@cindex System architecture
+@cindex Software architecture
+@cindex Software internals
+
+  Traditional routing software is made as a one process program which
+provides all of the routing protocol functionalities.  Zebra takes a
+different approach.  It is made from a collection of several daemons
+that work together to build the routing table.  There may be several
+protocol-specific routing daemons and zebra the kernel routing manager.
+
+  The @command{ripd} daemon handles the RIP protocol, while
+@command{ospfd} is a daemon which supports OSPF version 2.
+@command{bgpd} supports the BGP-4 protocol.  For changing the kernel
+routing table and for redistribution of routes between different routing
+protocols, there is a kernel routing table manager @command{zebra}
+daemon.  It is easy to add a new routing protocol daemons to the entire
+routing system without affecting any other software.  You need to run only
+the protocol daemon associated with routing protocols in use.  Thus,
+user may run a specific daemon and send routing reports to a central
+routing console.
+
+  There is no need for these daemons to be running on the same machine.
+You can even run several same protocol daemons on the same machine.  This
+architecture creates new possibilities for the routing system.
+
+@example
+@group
++----+  +----+  +-----+  +-----+
+|bgpd|  |ripd|  |ospfd|  |zebra|
++----+  +----+  +-----+  +-----+
+                            |
++---------------------------|--+
+|                           v  |
+|  UNIX Kernel  routing table  |
+|                              |
++------------------------------+
+
+    Zebra System Architecture
+@end group
+@end example
+
+  Multi-process architecture brings extensibility, modularity and
+maintainability.  At the same time it also brings many configuration
+files and terminal interfaces.  Each daemon has it's own configuration
+file and terminal interface.  When you configure a static route, it must
+be done in @command{zebra} configuration file.  When you configure BGP
+network it must be done in @command{bgpd} configuration file.  This can be a
+very annoying thing.  To resolve the problem, Zebra provides integrated
+user interface shell called @command{vtysh}.  @command{vtysh} connects to
+each daemon with UNIX domain socket and then works as a proxy for user input.
+
+  Zebra was planned to use multi-threaded mechanism when it runs with a
+kernel that supports multi-threads.  But at the moment, the thread
+library which comes with @sc{gnu}/Linux or FreeBSD has some problems with
+running reliable services such as routing software, so we don't use
+threads at all.  Instead we use the @command{select(2)} system call for
+multiplexing the events.
+
+  When @command{zebra} runs under a @sc{gnu} Hurd kernel it will act as a
+kernel routing table itself.  Under @sc{gnu} Hurd, all TCP/IP services are
+provided by user processes called @command{pfinet}.  Zebra will provide
+all the routing selection mechanisms for the process.  This feature will
+be implemented when @sc{gnu} Hurd becomes stable.
+
+@node Supported Platforms, Supported RFC, System Architecture, Overview
+@comment  node-name,  next,  previous,  up
+@section Supported Platforms
+
+@cindex Supported platforms
+@cindex Zebra on other systems
+@cindex Compatibility with other systems
+@cindex Operating systems that support Zebra
+
+  Currently Zebra supports @sc{gnu}/Linux, BSD and Solaris.  Below is a list
+of OS versions on which Zebra runs.  Porting Zebra to other platforms is
+not so too difficult.  Platform dependent codes exist only in
+@command{zebra} daemon.  Protocol daemons are platform independent.
+Please let us know when you find out Zebra runs on a platform which is not
+listed below.
+
+@sp 1
+@itemize @bullet
+@item
+GNU/Linux 2.0.37
+@item
+GNU/Linux 2.2.x
+@item
+GNU/Linux 2.3.x
+@item
+FreeBSD 2.2.8
+@item
+FreeBSD 3.x
+@item
+FreeBSD 4.x
+@item
+NetBSD 1.4
+@item
+OpenBSD 2.5
+@item
+Solaris 2.6
+@item
+Solaris 7
+@end itemize
+
+@sp 1
+  Some IPv6 stacks are in development.  Zebra supports following IPv6
+stacks.  For BSD, we recommend KAME IPv6 stack.  Solaris IPv6 stack is
+not yet supported.
+@sp 1
+@itemize @bullet
+@item
+Linux IPv6 stack for GNU/Linux 2.2.x and higher.
+@item
+KAME IPv6 stack for BSD.
+@item
+INRIA IPv6 stack for BSD.
+@end itemize
+
+@node Supported RFC, How to get Zebra, Supported Platforms, Overview
+@comment  node-name,  next,  previous,  up
+@section Supported RFC
+
+  Below is the list of currently supported RFC's.
+
+@table @asis
+@item @asis{RFC1058}
+@cite{Routing Information Protocol. C.L. Hedrick. Jun-01-1988.}
+
+@item @asis{RF2082}
+@cite{RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.}
+
+@item @asis{RFC2453}
+@cite{RIP Version 2. G. Malkin. November 1998.}
+
+@item @asis{RFC2080}
+@cite{RIPng for IPv6. G. Malkin, R. Minnear. January 1997.}
+
+@item @asis{RFC2328}
+@cite{OSPF Version 2. J. Moy. April 1998.}
+
+@item @asis{RFC2740}
+@cite{OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.}
+
+@item @asis{RFC1771} 
+@cite{A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.}
+
+@item @asis{RFC1965}
+@cite{Autonomous System Confederations for BGP. P. Traina. June 1996.}
+
+@item @asis{RFC1997}
+@cite{BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.}
+
+@item @asis{RFC2545}
+@cite{Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.}
+
+@item @asis{RFC2796}
+@cite{BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.}
+
+@item @asis{RFC2858}
+@cite{Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.}
+
+@item @asis{RFC2842}
+@cite{Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.}
+
+@end table
+
+  When SNMP support is enabled, below RFC is also supported.
+
+@table @asis
+
+@item @asis{RFC1227}
+@cite{SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.}
+
+@item @asis{RFC1657}
+@cite{Definitions of Managed Objects for the Fourth Version of the
+Border Gateway Protocol (BGP-4) using SMIv2. S. Willis, J. Burruss,
+J. Chu, Editor. July 1994.}
+
+@item @asis{RFC1724}
+@cite{RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.}
+
+@item @asis{RFC1850}
+@cite{OSPF Version 2 Management Information Base. F. Baker, R. Coltun.
+November 1995.}
+
+@end table
+
+@node How to get Zebra, Mailing List, Supported RFC, Overview
+@comment  node-name,  next,  previous,  up
+@section How to get Zebra
+
+  Zebra is still beta software and there is no officially
+released version.  So currently Zebra is distributed from Zebra beta ftp
+site located at:
+
+@url{ftp://ftp.zebra.org/pub/zebra}
+
+  Once Zebra is released you can get it from @sc{gnu} FTP site and
+its mirror sites.  We are planning Zebra-1.0 as the first released
+version.
+
+  Zebra's official web page is located at:
+
+@url{http://www.gnu.org/software/zebra/zebra.html}.
+
+  There is a Zebra beta tester web page at: 
+
+@url{http://www.zebra.org/}.
+
+  You can get the latest beta software information from this page.
+
+@node Mailing List, Bug Reports, How to get Zebra, Overview
+@comment  node-name,  next,  previous,  up
+@section Mailing List
+@cindex How to get in touch with Zebra
+@cindex Mailing Zebra
+@cindex Contact information
+@cindex Mailing lists
+
+  There is a mailing list for discussions about Zebra.  If you have any
+comments or suggestions to Zebra, please send mail to
+@email{zebra@@zebra.org}.  New snapshot announcements, improvement
+notes, and patches are sent to the list.
+
+  To subscribe to the @email{zebra@@zebra.org, Zebra mailing list},
+please send a mail to @email{majordomo@@zebra.org} with a message body
+that includes only:
+
+@quotation
+subscribe zebra
+@end quotation
+
+  To unsubscribe from the list, please send a mail to
+@email{majordomo@@zebra.org} with a message body that includes only:
+
+@quotation
+unsubscribe zebra
+@end quotation
+
+@node Bug Reports,  , Mailing List, Overview
+@comment  node-name,  next,  previous,  up
+@section Bug Reports
+
+@cindex Bug Reports
+@cindex Bug hunting
+@cindex Found a bug?
+@cindex Reporting bugs
+@cindex Reporting software errors
+@cindex Errors in the software
+
+  If you think you have found a bug, please send a bug report to
+@email{bug-zebra@@gnu.org}.  When you send a bug report, please be
+careful about the points below.
+
+@itemize @bullet
+@item 
+Please note what kind of OS you are using.  If you use the IPv6 stack
+please note that as well.
+@item
+Please show us the results of @code{netstat -rn} and @code{ifconfig -a}.
+Information from zebra's VTY command @code{show ip route} will also be
+helpful.
+@item
+Please send your configuration file with the report.  If you specify
+arguments to the configure script please note that too.
+@end itemize
+
+  Bug reports are very important for us to improve the quality of Zebra.
+Zebra is still in the development stage, but please don't hesitate to
+send a bug report to @email{bug-zebra@@gnu.org}.
+
diff --git a/doc/protocol.texi b/doc/protocol.texi
new file mode 100644 (file)
index 0000000..7cae9c9
--- /dev/null
@@ -0,0 +1,52 @@
+@node  Zebra Protocol, Packet Binary Dump Format, SNMP Support, Top
+@comment  node-name,  next,  previous,  up
+@appendix Zebra Protocol
+
+Zebra Protocol is a protocol which is used between protocol daemon and
+zebra.  Each protocol daemon sends selected routes to zebra daemon.  Then
+zebra manages which route is installed into the forwarding table.
+
+Zebra Protocol is a TCP-based protocol.  Below is common header of Zebra
+Protocol.
+
+@example
+@group
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|           Length (2)          |   Command (1) |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
+
+Length is total packet length including this header length.  So minimum
+length is three.  Command is Zebra Protocol command.
+
+@example
+ZEBRA_INTERFACE_ADD                1
+ZEBRA_INTERFACE_DELETE             2
+ZEBRA_INTERFACE_ADDRESS_ADD        3
+ZEBRA_INTERFACE_ADDRESS_DELETE     4
+ZEBRA_INTERFACE_UP                 5
+ZEBRA_INTERFACE_DOWN               6
+ZEBRA_IPV4_ROUTE_ADD               7
+ZEBRA_IPV4_ROUTE_DELETE            8
+ZEBRA_IPV6_ROUTE_ADD               9
+ZEBRA_IPV6_ROUTE_DELETE           10
+ZEBRA_REDISTRIBUTE_ADD            11
+ZEBRA_REDISTRIBUTE_DELETE         12
+ZEBRA_REDISTRIBUTE_DEFAULT_ADD    13
+ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14
+ZEBRA_IPV4_NEXTHOP_LOOKUP         15
+ZEBRA_IPV6_NEXTHOP_LOOKUP         16
+@end example
+
+@example
+@group
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|             Type              |             Flags             |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+@end group
+@end example
diff --git a/doc/ripd.8 b/doc/ripd.8
new file mode 100644 (file)
index 0000000..e15989f
--- /dev/null
@@ -0,0 +1,212 @@
+.TH RIPD 8 "July 2000" "Zebra" "Version 0.88"
+
+.SH NAME
+ripd \- a RIP routing engine for use with Zebra
+
+.SH SYNOPSIS
+.B ripd
+[
+.B \-dhrv
+]
+[
+.B \-f config-file
+]
+[
+.B \-i pid-file
+]
+[
+.B \-P port-number
+]
+
+.SH DESCRIPTION
+.B ripd 
+is a routing component that supports the 
+.B zebra
+route engine.
+.B ripd 
+supports RIPv1, RIPv2, and so forth.
+
+
+.SH OPTIONS
+
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
+Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ripd.conf\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When ripd starts its process idenifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart ripd.  The likely default is \fB\fI/var/run/ripd.pid\fR.
+
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the ripd VTY will listen on. This defaults to
+2602, as specified in \fB\fI/etc/services\fR.
+
+.TP
+\fB\-r\fR, \fB\-\-retain\fR 
+When the program terminates, retain routes added by \fBripd\fR.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+
+
+.SH COMMANDS
+
+\fB router rip \fR
+\fB no router rip \fR
+
+\fB rip version [1|2] \fR
+\fB no rip version [1|2] \fR
+
+\fB network [A.B.C.D/M] \fR
+\fB no network [A.B.C.D/M] \fR
+
+\fB network [IFNAME] \fR
+\fB no network [IFNAME] \fR
+
+\fB neighbor [A.B.C.D] \fR
+\fB no neighbor [A.B.C.D] \fR
+
+\fB redistribute kernel \fR
+\fB redistribute kernel metric [METRIC]\fR
+\fB redistribute kernel route-map [ROUTE-MAP]\fR
+\fB no redistribute kernel \fR
+
+\fB redistribute static \fR
+\fB redistribute static metric [METRIC]\fR
+\fB redistribute static route-map [ROUTE-MAP]\fR
+\fB no redistribute static \fR
+
+\fB redistribute connected \fR
+\fB redistribute connected metric [METRIC]\fR
+\fB redistribute connected route-map [ROUTE-MAP]\fR
+\fB no redistribute connected \fR
+
+\fB redistribute ospf \fR
+\fB redistribute ospf metric [METRIC]\fR
+\fB redistribute ospf route-map [ROUTE-MAP]\fR
+\fB no redistribute ospf \fR
+
+\fB redistribute bgp \fR
+\fB redistribute bgp metric [METRIC]\fR
+\fB redistribute bgp route-map [ROUTE-MAP]\fR
+\fB no redistribute bgp \fR
+
+\fB route [A.B.C.D/M] \fR
+\fB no route [A.B.C.D/M] \fR
+
+\fB default-information originate \fR
+\fB no default-information originate \fR
+
+\fB default-metric [METRIC] \fR
+\fB no default-metric [METRIC] \fR
+
+\fB passive-interface [IFNAME] \fR
+\fB no passive-interface [IFNAME] \fR
+
+\fB offset-list [ACCESS-LIST] [in|out]\fR
+\fB offset-list [ACCESS-LIST] [in|out] [IFNAME]\fR
+\fB no offset-list [ACCESS-LIST] [in|out]\fR
+
+\fB timers basic [UPDATE-INTERVAL] [INVALID] [TIMEOUT] [GARBAGE-COLLECT] \fR
+\fB no timers basic \fR
+
+\fB distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR
+\fB no distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR
+
+\fB distribute-list prefix [PREFIX-LIST] [in|out] [IFNAME] \fR
+\fB no distribute-list prefix [PREFIX-LIST] [in|out] [IFNAME] \fR
+
+\fB distance [DISTANCE] \fR
+\fB no distance [DISTANCE] \fR
+
+\fB distance [DISTANCE] [A.B.C.D/M] \fR
+\fB no distance [DISTANCE] [A.B.C.D/M] \fR
+
+\fB distance [DISTANCE] [A.B.C.D/M] [ACCESS-LIST]\fR
+\fB no distance [DISTANCE] [A.B.C.D/M] [ACCESS-LIST]\fR
+
+\fB ip rip send version [VERSION] \fR
+\fB no ip rip send version [VERSION] \fR
+\fB ip rip receive version [VERSION] \fR
+\fB no ip rip receive version [VERSION] \fR
+
+\fB ip rip authentication mode [md5|text]\fR
+\fB no ip rip authentication mode [md5|text]\fR
+
+\fB ip rip authentication key-chain [KEY-CHAIN]\fR
+\fB no ip rip authentication key-chain [KEY-CHAIN]\fR
+
+\fB ip rip authentication string [STRING]\fR
+\fB no ip rip authentication string [STRING]\fR
+
+\fB ip spli-horizon\fR
+\fB no ip spli-horizon\fR
+
+\fB show ip rip \fR
+\fB show ip protocols \fR
+\fB show debugging rip \fR
+
+\fB debug rip \fR
+\fB debug rip events \fR
+\fB debug rip packet \fR
+\fB debug rip zebra \fR
+
+.SH FILES
+
+.TP
+.BI /usr/local/sbin/ripd
+The default location of the 
+.B ripd
+binary.
+
+.TP
+.BI /usr/local/etc/ripd.conf
+The default location of the 
+.B ripd
+config file.
+
+.TP
+.BI $(PWD)/ripd.log 
+If the 
+.B ripd
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBripd\fR.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line options, and for config file commands. The definitive document is the Info file \fBzebra\fR.
+
+
+.SH DIAGNOSTICS
+The ripd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. 
+.B ripd
+supports many debugging options, see the Info file, or the source for details.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+ripngd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8)
+
+
+
+.SH BUGS
+.B ripd
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
diff --git a/doc/ripd.texi b/doc/ripd.texi
new file mode 100644 (file)
index 0000000..d598ca6
--- /dev/null
@@ -0,0 +1,584 @@
+@c -*-texinfo-*-
+@c This is part of the GNU Zebra Manual.
+@c Copyright (C) 1999, 2000 Kunihiro Ishiguro
+@c See file zebra.texi for copying conditions.
+@node RIP
+@comment  node-name,  next,  previous,  up
+@chapter RIP
+
+RIP -- Routing Information Protocol is widely deployed interior gateway
+protocol.  RIP was developed in the 1970s at Xerox Labs as part of the
+XNS routing protocol.  RIP is a @dfn{distance-vector} protocol and is
+based on the @dfn{Bellman-Ford} algorithms.  As a distance-vector
+protocol, RIP router send updates to its neighbors periodically, thus
+allowing the convergence to a known topology.  In each update, the
+distance to any given network will be broadcasted to its neighboring
+router.
+
+@command{ripd} supports RIP version 2 as described in RFC2453 and RIP
+version 1 as described in RFC1058.
+
+@menu
+* Starting and Stopping ripd::  
+* RIP Configuration::           
+* How to Announce RIP route::   
+* Filtering RIP Routes::        
+* RIP Metric Manipulation::     
+* RIP distance::                
+* RIP route-map::               
+* RIP Authentication::          
+* RIP Timers::                  
+* Show RIP Information::        
+* RIP Debug Commands::          
+@end menu
+
+@node Starting and Stopping ripd, RIP Configuration, RIP, RIP
+@comment  node-name,  next,  previous,  up
+@section Starting and Stopping ripd
+
+The default configuration file name of @command{ripd}'s is
+@file{ripd.conf}.  When invocation @command{ripd} searches directory
+@value{INSTALL_PREFIX_ETC}.  If @file{ripd.conf} is not there next
+search current directory.
+
+RIP uses UDP port 521 to send and receive RIP packets.  So the user must have
+the capability to bind the port, generally this means that the user must
+have superuser privileges.  RIP protocol requires interface information
+maintained by @command{zebra} daemon.  So running @command{zebra}
+is mandatory to run @command{ripd}.  Thus minimum sequence for running
+RIP is like below:
+
+@example
+@group
+# zebra -d
+# ripd -d
+@end group
+@end example
+
+Please note that @command{zebra} must be invoked before @command{ripd}.
+
+To stop @command{ripd}.  Please use @command{kill `cat
+/var/run/ripd.pid`}.  Certain signals have special meaningss to @command{ripd}.
+
+@table @samp
+@item SIGHUP
+Reload configuration file @file{ripd.conf}.  All configurations are
+reseted.  All routes learned so far are cleared and removed from routing
+table.
+@item SIGUSR1
+Rotate @command{ripd} logfile.
+@item SIGINT
+@itemx SIGTERM
+@command{ripd} sweeps all installed RIP routes then terminates properly.
+@end table
+
+@command{ripd} invocation options.  Common options that can be specified
+(@pxref{Common Invocation Options}).
+
+@table @samp
+@item -r
+@itemx --retain
+When the program terminates, retain routes added by @command{ripd}.
+@end table
+
+@menu
+* RIP netmask::                 
+@end menu
+
+@node RIP netmask,  , Starting and Stopping ripd, Starting and Stopping ripd
+@comment  node-name,  next,  previous,  up
+@subsection RIP netmask
+
+The netmask features of @command{ripd} support both version 1 and version 2 of
+RIP.  Version 1 of RIP originally contained no netmask information.  In
+RIP version 1, network classes were originally used to determine the
+size of the netmask.  Class A networks use 8 bits of mask, Class B
+networks use 16 bits of masks, while Class C networks use 24 bits of
+mask.  Today, the most widely used method of a network mask is assigned
+to the packet on the basis of the interface that received the packet.
+Version 2 of RIP supports a variable length subnet mask (VLSM).  By
+extending the subnet mask, the mask can be divided and reused.  Each
+subnet can be used for different purposes such as large to middle size
+LANs and WAN links.  Zebra @command{ripd} does not support the non-sequential
+netmasks that are included in RIP Version 2.
+
+In a case of similar information with the same prefix and metric, the
+old information will be suppressed.  Ripd does not currently support
+equal cost multipath routing.
+
+
+@node RIP Configuration, How to Announce RIP route, Starting and Stopping ripd, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP Configuration
+
+@deffn Command {router rip} {}
+The @code{router rip} command is necessary to enable RIP.  To disable
+RIP, use the @code{no router rip} command.  RIP must be enabled before
+carrying out any of the RIP commands.
+@end deffn
+
+@deffn Command {no rouer rip} {}
+Disable RIP.
+@end deffn
+
+RIP can be configured to process either Version 1 or Version 2 packets,
+the default mode is Version 2.  If no version is specified, then the RIP
+daemon will default to Version 2.  If RIP is set to Version
+1, the setting "Version 1" will be displayed, but the setting "Version
+2" will not be displayed whether or not Version 2 is set explicitly as
+the version of RIP being used.
+
+@deffn {RIP Command} {network @var{network}} {}
+@deffnx {RIP Command} {no network @var{network}} {}
+Set the RIP enable interface by @var{network}.  The interfaces which
+have addresses matching with @var{network} are enabled.
+
+This group of commands either enables or disables RIP interfaces between
+certain numbers of a specified network address.  For example, if the
+network for 10.0.0.0/24 is RIP enabled, this would result in all the
+addresses from 10.0.0.0 to 10.0.0.255 being enabled for RIP.  The @code{no
+network} command will disable RIP for the specified network.
+@end deffn
+
+@deffn {RIP Command} {network @var{ifname}} {}
+@deffnx {RIP Command} {no network @var{ifname}} {}
+Set a RIP enabled interface by @var{ifname}.  Both the sending and
+receiving of RIP packets will be enabled on the port specified in the
+@code{network ifname} command.  The @code{no network ifname} command will disable
+RIP on the specified interface.
+@end deffn
+
+@deffn {RIP Command} {neighbor @var{a.b.c.d}} {}
+@deffnx {RIP Command} {no neighbor @var{a.b.c.d}} {}
+Specify RIP neighbor.  When a neighbor doesn't understand multicast,
+this command is used to specify neighbors.  In some cases, not all
+routers will be able to understand multicasting, where packets are sent
+to a network or a group of addresses.  In a situation where a neighbor
+cannot process multicast packets, it is necessary to establish a direct
+link between routers.  The neighbor command allows the network
+administrator to specify a router as a RIP neighbor.  The @code{no
+neighbor a.b.c.d} command will disable the RIP neighbor.
+@end deffn
+
+Below is very simple RIP configuration.  Interface @code{eth0} and
+interface which address match to @code{10.0.0.0/8} are RIP enabled.
+
+@example
+@group
+!
+router rip
+ network 10.0.0.0/8
+ network eth0
+!
+@end group
+@end example
+
+Passive interface
+
+@deffn {RIP command} {passive-interface @var{IFNAME}} {}
+@deffnx {RIP command} {no passive-interface @var{IFNAME}} {}
+This command sets the specified interface to passive mode.  On passive mode
+interface, all receiving packets are processed as normal and ripd does
+not send either multicast or unicast RIP packets except to RIP neighbors
+specified with @code{neighbor} command.
+@end deffn
+
+RIP version handling
+
+@deffn {RIP Command} {version @var{version}} {}
+Set RIP process's version.  @var{version} can be ``1'' or ``2''.
+@end deffn
+
+@deffn {Interface command} {ip rip send version @var{version}} {}
+@var{version} can be `1', `2', `1 2'.  This configuration command
+overrides the router's rip version setting.  The command will enable the
+selected interface to send packets with RIP Version 1, RIP Version 2, or
+both.  In the case of '1 2', packets will be both broadcast and
+multicast.
+@end deffn
+
+@deffn {Interface command} {ip rip receive version @var{version}} {}
+Version setting for incoming RIP packets.  This command will enable the
+selected interface to receive packets in RIP Version 1, RIP Version 2,
+or both.
+@end deffn
+
+RIP split-horizon
+
+@deffn {Interface command} {ip split-horizon} {}
+@deffnx {Interface command} {no ip split-horizon} {}
+Control split-horizon on the interface.  Default is @code{ip
+split-horizon}.  If you don't perform split-horizon on the interface,
+please specify @code{no ip split-horizon}.
+@end deffn
+
+@node How to Announce RIP route, Filtering RIP Routes, RIP Configuration, RIP
+@comment  node-name,  next,  previous,  up
+@section How to Announce RIP route
+
+@deffn {RIP command} {redistribute kernel} {}
+@deffnx {RIP command} {redistribute kernel metric <0-16>} {}
+@deffnx {RIP command} {redistribute kernel route-map @var{route-map}} {}
+@deffnx {RIP command} {no redistribute kernel} {}
+@code{redistribute kernel} redistributes routing information from
+kernel route entries into the RIP tables. @code{no redistribute kernel}
+disables the routes.
+@end deffn
+
+@deffn {RIP command} {redistribute static} {}
+@deffnx {RIP command} {redistribute static metric <0-16>} {}
+@deffnx {RIP command} {redistribute static route-map @var{route-map}} {}
+@deffnx {RIP command} {no redistribute static} {}
+@code{redistribute static} redistributes routing information from
+static route entries into the RIP tables. @code{no redistribute static}
+disables the routes.
+@end deffn
+
+@deffn {RIP command} {redistribute connected} {}
+@deffnx {RIP command} {redistribute connected metric <0-16>} {}
+@deffnx {RIP command} {redistribute connected route-map @var{route-map}} {}
+@deffnx {RIP command} {no redistribute connected} {}
+Redistribute connected routes into the RIP tables.  @code{no
+redistribute connected} disables the connected routes in the RIP tables.
+This command redistribute connected of the interface which RIP disabled.
+The connected route on RIP enabled interface is announced by default.
+@end deffn
+
+@deffn {RIP command} {redistribute ospf} {}
+@deffnx {RIP command} {redistribute ospf metric <0-16>} {}
+@deffnx {RIP command} {redistribute ospf route-map @var{route-map}} {}
+@deffnx {RIP command} {no redistribute ospf} {}
+@code{redistribute ospf} redistributes routing information from
+ospf route entries into the RIP tables. @code{no redistribute ospf}
+disables the routes.
+@end deffn
+
+@deffn {RIP command} {redistribute bgp} {}
+@deffnx {RIP command} {redistribute bgp metric <0-16>} {}
+@deffnx {RIP command} {redistribute bgp route-map @var{route-map}} {}
+@deffnx {RIP command} {no redistribute bgp} {}
+@code{redistribute bgp} redistributes routing information from
+bgp route entries into the RIP tables. @code{no redistribute bgp}
+disables the routes.
+@end deffn
+
+If you want to specify RIP only static routes:
+
+@deffn {RIP command} {default-information originate} {}
+@end deffn
+
+@deffn {RIP command} {route @var{a.b.c.d/m}} {}
+@deffnx {RIP command} {no route @var{a.b.c.d/m}} {}
+This command is specific to Zebra.  The @code{route} command makes a static
+route only inside RIP. This command should be used only by advanced
+users who are particularly knowledgeable about the RIP protocol.  In
+most cases, we recommend creating a static route in Zebra and
+redistributing it in RIP using @code{redistribute static}.
+@end deffn
+
+
+@node  Filtering RIP Routes, RIP Metric Manipulation, How to Announce RIP route, RIP
+@comment  node-name,  next,  previous,  up
+@section Filtering RIP Routes
+
+RIP routes can be filtered by a distribute-list.
+
+@deffn Command {distribute-list @var{access_list} @var{direct} @var{ifname}} {}
+You can apply access lists to the interface with a @code{distribute-list}
+command.  @var{access_list} is the access list name.  @var{direct} is
+@samp{in} or @samp{out}.  If @var{direct} is @samp{in} the access list
+is applied to input packets.
+
+The @code{distribute-list} command can be used to filter the RIP path.
+@code{distribute-list} can apply access-lists to a chosen interface.
+First, one should specify the access-list.  Next, the name of the
+access-list is used in the distribute-list command.  For example, in the
+following configuration @samp{eth0} will permit only the paths that
+match the route 10.0.0.0/8
+
+@example
+@group
+!
+router rip
+ distribute-list private in eth0
+!
+access-list private permit 10 10.0.0.0/8
+access-list private deny any
+!
+@end group
+@end example
+@end deffn
+
+@code{distribute-list} can be applied to both incoming and outgoing data.
+
+@deffn Command {distribute-list prefix @var{prefix_list} (in|out) @var{ifname}} {}
+You can apply prefix lists to the interface with a
+@code{distribute-list} command.  @var{prefix_list} is the prefix list
+name.  Next is the direction of @samp{in} or @samp{out}.  If
+@var{direct} is @samp{in} the access list is applied to input packets.
+@end deffn
+
+@node RIP Metric Manipulation, RIP distance, Filtering RIP Routes, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP Metric Manipulation
+
+RIP metric is a value for distance for the network.  Usually
+@command{ripd} increment the metric when the network information is
+received.  Redistributed routes' metric is set to 1.
+
+@deffn {RIP command} {default-metric <1-16>} {}
+@deffnx {RIP command} {no default-metric <1-16>} {}
+This command modifies the default metric value for redistributed routes.  The
+default value is 1.  This command does not affect connected route
+even if it is redistributed by @command{redistribute connected}.  To modify
+connected route's metric value, please use @command{redistribute
+connected metric} or @command{route-map}.  @command{offset-list} also
+affects connected routes.
+@end deffn
+
+@deffn {RIP command} {offset-list @var{access-list} (in|out)} {}
+@deffnx {RIP command} {offset-list @var{access-list} (in|out) @var{ifname}} {}
+@end deffn
+
+@node RIP distance, RIP route-map, RIP Metric Manipulation, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP distance
+
+Distance value is used in zebra daemon.  Default RIP distance is 120.
+
+@deffn {RIP command} {distance <1-255>} {}
+@deffnx {RIP command} {no distance <1-255>} {}
+Set default RIP distance to specified value.
+@end deffn
+
+@deffn {RIP command} {distance <1-255> @var{A.B.C.D/M}} {}
+@deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M}} {}
+Set default RIP distance to specified value when the route's source IP
+address matches the specified prefix.
+@end deffn
+
+@deffn {RIP command} {distance <1-255> @var{A.B.C.D/M} @var{access-list}} {}
+@deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M} @var{access-list}} {}
+Set default RIP distance to specified value when the route's source IP
+address matches the specified prefix and the specified access-list.
+@end deffn
+
+@node RIP route-map, RIP Authentication, RIP distance, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP route-map
+
+Usage of @command{ripd}'s route-map support.
+
+Optional argument route-map MAP_NAME can be added to each @code{redistribute}
+statement.
+
+@example
+redistribute static [route-map MAP_NAME]
+redistribute connected [route-map MAP_NAME]
+.....
+@end example
+
+Cisco applies route-map _before_ routes will exported to rip route
+table.  In current Zebra's test implementation, @command{ripd} applies route-map
+after routes are listed in the route table and before routes will be announced
+to an interface (something like output filter). I think it is not so clear,
+but it is draft and it may be changed at future.
+
+Route-map statement (@pxref{Route Map}) is needed to use route-map
+functionality.
+
+@deffn {Route Map} {match interface @var{word}} {}
+This command match to incoming interface.  Notation of this match is
+different from Cisco. Cisco uses a list of interfaces - NAME1 NAME2
+... NAMEN.  Ripd allows only one name (maybe will change in the
+future).  Next - Cisco means interface which includes next-hop of
+routes (it is somewhat similar to "ip next-hop" statement).  Ripd
+means interface where this route will be sent. This difference is
+because "next-hop" of same routes which sends to different interfaces
+must be different. Maybe it'd be better to made new matches - say
+"match interface-out NAME" or something like that.
+@end deffn
+
+@deffn {Route Map} {match ip address @var{word}} {}
+@deffnx {Route Map} {match ip address prefix-list @var{word}} {}
+Match if route destination is permitted by access-list.
+@end deffn
+
+@deffn {Route Map} {match ip next-hop A.B.C.D} {}
+Cisco uses here <access-list>, @command{ripd} IPv4 address. Match if
+route has this next-hop (meaning next-hop listed in the rip route
+table - "show ip rip")
+@end deffn
+
+@deffn {Route Map} {match metric <0-4294967295>} {}
+This command match to the metric value of RIP updates.  For other
+protocol compatibility metric range is shown as <0-4294967295>.  But
+for RIP protocol only the value range <0-16> make sense.
+@end deffn
+
+@deffn {Route Map} {set ip next-hop A.B.C.D} {}
+This command set next hop value in RIPv2 protocol.  This command does
+not affect RIPv1 because there is no next hop field in the packet.
+@end deffn
+
+@deffn {Route Map} {set metric <0-4294967295>} {}
+Set a metric for matched route when sending announcement.  The metric
+value range is very large for compatibility with other protocols.  For
+RIP, valid metric values are from 1 to 16.
+@end deffn
+
+@node RIP Authentication, RIP Timers, RIP route-map, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP Authentication
+
+@deffn {Interface command} {ip rip authentication mode md5} {}
+@deffnx {Interface command} {no ip rip authentication mode md5} {}
+Set the interface with RIPv2 MD5 authentication.
+@end deffn
+
+@deffn {Interface command} {ip rip authentication mode text} {}
+@deffnx {Interface command} {no ip rip authentication mode text} {}
+Set the interface with RIPv2 simple password authentication.
+@end deffn
+
+@deffn {Interface command} {ip rip authentication string @var{string}} {}
+@deffnx {Interface command} {no ip rip authentication string @var{string}} {}
+RIP version 2 has simple text authentication.  This command sets
+authentication string.  The string must be shorter than 16 characters.
+@end deffn
+
+@deffn {Interface command} {ip rip authentication key-chain @var{key-chain}} {}
+@deffnx {Interface command} {no ip rip authentication key-chain @var{key-chain}} {}
+Specifiy Keyed MD5 chain.
+@end deffn
+
+@example
+!
+key chain test
+ key 1
+  key-string test
+!
+interface eth1
+ ip rip authentication mode md5
+ ip rip authentication key-chain test
+!
+@end example
+
+@node RIP Timers, Show RIP Information, RIP Authentication, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP Timers
+
+@deffn {RIP command} {timers basic @var{update} @var{timeout} @var{garbage}} {}
+
+RIP protocol has several timers.  User can configure those timers' values
+by @code{timers basic} command.
+
+The default settings for the timers are as follows: 
+
+@itemize @bullet 
+@item
+The update timer is 30 seconds. Every update timer seconds, the RIP
+process is awakened to send an unsolicited Response message containing
+the complete routing table to all neighboring RIP routers.
+
+@item
+The timeout timer is 180 seconds. Upon expiration of the timeout, the
+route is no longer valid; however, it is retained in the routing table
+for a short time so that neighbors can be notified that the route has
+been dropped.
+
+@item
+The garbage collect timer is 120 seconds.  Upon expiration of the
+garbage-collection timer, the route is finally removed from the routing
+table.
+
+@end itemize
+
+The @code{timers basic} command allows the the default values of the timers
+listed above to be changed.
+@end deffn
+
+@deffn {RIP command} {no timers basic} {}
+The @code{no timers basic} command will reset the timers to the default
+settings listed above.
+@end deffn
+
+@node Show RIP Information, RIP Debug Commands, RIP Timers, RIP
+@comment  node-name,  next,  previous,  up
+@section Show RIP Information
+
+To display RIP routes.
+
+@deffn Command {show ip rip} {}
+Show RIP routes.
+@end deffn
+
+The command displays all RIP routes. For routes that are received
+through RIP, this command will display the time the packet was sent and
+the tag information.  This command will also display this information
+for routes redistributed into RIP.
+
+@c Exmaple here.
+
+@deffn Command {show ip protocols} {}
+The command displays current RIP status.  It includes RIP timer,
+filtering, version, RIP enabled interface and RIP peer inforation.
+@end deffn
+
+@example
+@group
+ripd> @b{show ip protocols}
+Routing Protocol is "rip"
+  Sending updates every 30 seconds with +/-50%, next due in 35 seconds
+  Timeout after 180 seconds, garbage collect after 120 seconds
+  Outgoing update filter list for all interface is not set
+  Incoming update filter list for all interface is not set
+  Default redistribution metric is 1
+  Redistributing: kernel connected
+  Default version control: send version 2, receive version 2 
+    Interface        Send  Recv
+  Routing for Networks:
+    eth0
+    eth1
+    1.1.1.1
+    203.181.89.241
+  Routing Information Sources:
+    Gateway          BadPackets BadRoutes  Distance Last Update
+@end group
+@end example
+
+@node RIP Debug Commands,  , Show RIP Information, RIP
+@comment  node-name,  next,  previous,  up
+@section RIP Debug Commands
+
+Debug for RIP protocol.
+
+@deffn Command {debug rip events} {}
+Debug rip events.
+@end deffn
+
+@code{debug rip} will show RIP events.  Sending and receiving
+packets, timers, and changes in interfaces are events shown with @command{ripd}.
+
+@deffn Command {debug rip packet} {}
+Debug rip packet.
+@end deffn
+
+@code{debug rip packet} will display detailed information about the RIP
+packets.  The origin and port number of the packet as well as a packet
+dump is shown.
+
+@deffn Command {debug rip zebra} {}
+Debug rip between zebra communication.
+@end deffn
+
+This command will show the communication between @command{ripd} and @command{zebra}.  The
+main information will include addition and deletion of paths to the
+kernel and the sending and receiving of interface information.
+
+@deffn Command {show debugging rip} {}
+Display @command{ripd}'s debugging option.
+@end deffn
+
+@code{show debugging rip} will show all information currently set for ripd
+debug.
diff --git a/doc/ripngd.8 b/doc/ripngd.8
new file mode 100644 (file)
index 0000000..cff8abe
--- /dev/null
@@ -0,0 +1,143 @@
+.TH RIPNGD 8 "July 2000" "Zebra Beast - RIPNGD" "Version 0.88"
+
+.SH NAME
+ripngd \- a RIP routing engine for use with Zebra and IPv6
+
+.SH SYNOPSIS
+.B ripngd
+[
+.B \-dhlrv
+]
+[
+.B \-f config-file
+]
+[
+.B \-i pid-file
+]
+[
+.B \-P port-number
+]
+
+.SH DESCRIPTION
+.B ripngd 
+is a routing component that works with the 
+.B zebra
+routing engine.
+
+
+
+.SH OPTIONS
+
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR 
+Specifies the config file to use for startup. If not specified this
+option will likely default to \fB\fI/usr/local/etc/ripngd.conf\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When ripngd starts its process idenifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart ripngd.  The likely default is \fB\fI/var/run/ripngd.pid\fR.
+
+.TP
+\fB\-l\fR, \fB\-\-log_mode\fR 
+Turn verbose logging on.
+
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the ripngd VTY will listen on. This defaults to
+2603, as specified in \fB\fI/etc/services\fR.
+
+.TP
+\fB\-r\fR, \fB\-\-retain\fR 
+When the program terminates, retain routes added by \fBripd\fR.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+
+
+.SH COMMANDS
+
+\fB router ripng \fR
+\fB router zebra \fR -- (Move routes into kernel table)
+
+\fB network [NETWORK] \fR
+\fB no network [NETWORK] \fR
+
+\fB network [IFNAME] \fR
+\fB no network [IFNAME] \fR
+
+\fB route [NETWORK] \fR
+\fB no route [NETWORK] \fR
+
+\fB flush_timer [FLUSH] \fR
+
+\fB distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR
+
+\fB show ip ripng \fR
+\fB show debugging ripng \fR
+
+\fB debug ripng \fR
+\fB debug ripng events \fR
+\fB debug ripng packet \fR
+\fB debug ripng zebra \fR
+
+
+
+.SH FILES
+
+.TP
+.BI /usr/local/sbin/ripngd
+The default location of the 
+.B ripngd
+binary.
+
+.TP
+.BI /usr/local/etc/ripngd.conf
+The default location of the 
+.B ripngd
+config file.
+
+.TP
+.BI $(PWD)/ripngd.log 
+If the 
+.B ripngd
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBripngd\fR.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line
+options, and for config file commands. The definitive document is the
+Info file \fBzebra\fR.
+
+
+.SH DIAGNOSTICS
+The ripngd process may log to standard output, to a VTY, to a log
+file, or through syslog to the system logs. \fBripngd\fR supports many
+debugging options, see the Info file, or the source for details.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+ripd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1)
+
+.SH BUGS
+.B ripngd
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/ripngd.texi b/doc/ripngd.texi
new file mode 100644 (file)
index 0000000..b49f0bf
--- /dev/null
@@ -0,0 +1,85 @@
+@node RIPng, OSPFv2, RIP, Top
+@comment  node-name,  next,  previous,  up
+@chapter RIPng
+
+@command{ripngd} supports the RIPng protocol as described in RFC2080.  It's an
+IPv6 reincarnation of the RIP protocol.
+
+@menu
+* Invoking ripngd::             
+* ripngd Configuration::        
+* ripngd Terminal Mode Commands::  
+* ripngd Filtering Commands::   
+@end menu
+
+@node Invoking ripngd, ripngd Configuration, RIPng, RIPng
+@comment  node-name,  next,  previous,  up
+@section Invoking ripngd
+
+There are no @code{ripngd} specific invocation options.  Common options
+can be specified (@pxref{Common Invocation Options}).
+
+@node ripngd Configuration, ripngd Terminal Mode Commands, Invoking ripngd, RIPng
+@comment  node-name,  next,  previous,  up
+@section ripngd Configuration
+
+Currently ripngd supports the following commands:
+
+@deffn Command {router ripng} {}
+Enable RIPng.
+@end deffn
+
+@deffn {RIPng Command} {flush_timer @var{time}} {}
+Set flush timer.
+@end deffn
+
+@deffn {RIPng Command} {network @var{network}} {}
+Set RIPng enabled interface by @var{network}
+@end deffn
+
+@deffn {RIPng Command} {network @var{ifname}} {}
+Set RIPng enabled interface by @var{ifname}
+@end deffn
+
+@deffn {RIPng Command} {route @var{network}} {}
+Set RIPng static routing announcement of @var{network}.
+@end deffn
+
+@deffn Command {router zebra} {}
+This command is the default and does not appear in the configuration.
+With this statement, RIPng routes go to the @command{zebra} daemon.
+@end deffn
+
+@node ripngd Terminal Mode Commands, ripngd Filtering Commands, ripngd Configuration, RIPng
+@comment  node-name,  next,  previous,  up
+@section ripngd Terminal Mode Commands
+
+@deffn Command {show ip ripng} {}
+@end deffn
+
+@deffn Command {show debugging ripng} {}
+@end deffn
+
+@deffn Command {debug ripng events} {}
+@end deffn
+
+@deffn Command {debug ripng packet} {}
+@end deffn
+
+@deffn Command {debug ripng zebra} {}
+@end deffn
+
+@node ripngd Filtering Commands,  , ripngd Terminal Mode Commands, RIPng
+@comment  node-name,  next,  previous,  up
+@section ripngd Filtering Commands
+
+@deffn Command {distribute-list @var{access_list} (in|out) @var{ifname}} {}
+You can apply an access-list to the interface using the
+@code{distribute-list} command.  @var{access_list} is an access-list
+name.  @var{direct} is @samp{in} or @samp{out}.  If @var{direct} is
+@samp{in}, the access-list is applied only to incoming packets.
+
+@example
+distribute-list local-only out sit1
+@end example
+@end deffn
diff --git a/doc/routemap.texi b/doc/routemap.texi
new file mode 100644 (file)
index 0000000..478f462
--- /dev/null
@@ -0,0 +1,91 @@
+@node Route Map, IPv6 Support, Filtering, Top
+@comment  node-name,  next,  previous,  up
+@chapter Route Map
+
+Route map is a very useful function in zebra.  There is a match and set
+statement permitted in a route map.
+
+@example
+@group
+route-map test permit 10
+ match ip address 10
+ set local-preference 200
+@end group
+@end example
+
+This means that if a route matches ip access-list number 10 it's
+local-preference value is set to 200.
+
+@menu
+* Route Map Command::           
+* Route Map Match Command::     
+* Route Map Set Command::       
+@end menu
+
+@node Route Map Command, Route Map Match Command, Route Map, Route Map
+@comment  node-name,  next,  previous,  up
+@subsection Route Map Command
+
+@deffn {Command} {route-map @var{route-map-name} permit @var{priority}} {}
+@end deffn
+
+@node Route Map Match Command, Route Map Set Command, Route Map Command, Route Map
+@comment  node-name,  next,  previous,  up
+@subsection Route Map Match Command
+
+@deffn {Route-map Command} {match ip address @var{access_list}} {}
+Matches the specified @var{access_list}
+@end deffn
+
+@deffn {Route-map Command} {match ip next-hop @var{ipv4_addr}} {}
+Matches the specified @var{ipv4_addr}.
+@end deffn
+
+@deffn {Route-map Command} {match aspath @var{as_path}} {}
+Matches the specified @var{as_path}.
+@end deffn
+
+@deffn {Route-map Command} {match metric @var{metric}} {}
+Matches the specified @var{metric}.
+@end deffn
+
+@deffn {Route-map Command} {match community @var{community_list}} {}
+Matches the specified  @var{community_list}
+@end deffn
+
+@node Route Map Set Command,  , Route Map Match Command, Route Map
+@comment  node-name,  next,  previous,  up
+@subsection Route Map Set Command
+
+@deffn {Route-map Command} {set ip next-hop @var{ipv4_address}} {}
+Set the BGP nexthop address.
+@end deffn
+
+@deffn {Route-map Command} {set local-preference @var{local_pref}} {}
+Set the BGP local preference.
+@end deffn
+
+@deffn {Route-map Command} {set weight @var{weight}} {}
+Set the route's weight.
+@end deffn
+
+@deffn {Route-map Command} {set metric @var{metric}} {}
+Set the BGP attribute MED.
+@end deffn
+
+@deffn {Route-map Command} {set as-path prepend @var{as_path}} {}
+Set the BGP AS path to prepend.
+@end deffn
+
+@deffn {Route-map Command} {set community @var{community}} {}
+Set the BGP community attribute.
+@end deffn
+
+@deffn {Route-map Command} {set ipv6 next-hop global @var{ipv6_address}} {}
+Set the BGP-4+ global IPv6 nexthop address.
+@end deffn
+
+@deffn {Route-map Command} {set ipv6 next-hop local @var{ipv6_address}} {}
+Set the BGP-4+ link local IPv6 nexthop address.
+@end deffn
+
diff --git a/doc/snmp.texi b/doc/snmp.texi
new file mode 100644 (file)
index 0000000..315c91c
--- /dev/null
@@ -0,0 +1,68 @@
+@node SNMP Support, Zebra Protocol, Kernel Interface, Top
+@comment  node-name,  next,  previous,  up
+@chapter SNMP Support
+
+SNMP (Simple Network Managing Protocol) is widely implemented feature
+for collecting network information from router and/or host.  Zebra
+itself does not support SNMP agent functionality.  But conjuction with
+SNMP agent, Zebra provides routing protocol MIBs.
+
+Zebra uses SMUX protocol (RFC1227) for making communication with SNMP
+agent.  There are several SNMP agent which support SMUX.  We recommend
+to use the latest @command{ucd-snmp} software.  
+
+@menu
+* How to get ucd-snmp::         
+* SMUX configuration::          
+@end menu
+
+@node How to get ucd-snmp, SMUX configuration, SNMP Support, SNMP Support
+@comment  node-name,  next,  previous,  up
+@section How to get ucd-snmp
+
+ucd-snmp is a free software which distributed so called "as is" software
+license.  Please check the license which comes with distribution of
+@command{ucd-snmp}.  The authors of ucd-snmp are the University of
+California, the University of California at Davis, and the Electrical
+Engineering department at the University of California at Davis.
+
+You can get ucd-snmp from @url{ftp://ucd-snmp.ucdavis.edu/}.  As of this
+writing we are testing with @command{ucd-snmp-4.1.pre1.tar.gz}.
+
+To enable SMUX protocol support, please configure @command{ucd-snmp}
+like below.
+
+@example
+% configure --with-mib-modules=smux
+@end example
+
+After compile and install @command{ucd-snmp}, you will need to configure
+smuxpeer.  I'm now using configuration shown below.  This means SMUX client
+connects to MIB 1.3.6.1.6.3.1 with password test.
+  
+@example
+/usr/local/share/snmp/snmpd.conf
+================================
+smuxpeer 1.3.6.1.6.3.1 test
+@end example
+
+@node SMUX configuration,  , How to get ucd-snmp, SNMP Support
+@comment  node-name,  next,  previous,  up
+@section SMUX configuration
+
+To enable SNMP support of Zebra, you have to configure Zebra with
+@command{--enable-snmp} (@pxref{Configure the Software}).
+
+@deffn {Command} {smux peer @var{oid}} {}
+@deffnx {Command} {no smux peer @var{oid}} {}
+@end deffn
+
+@deffn {Command} {smux peer @var{oid} @var{password}} {}
+@deffnx {Command} {no smux peer @var{oid} @var{password}} {}
+@end deffn
+
+@example
+!
+smux peer .1.3.6.1.6.3.1 test
+!
+@end example
diff --git a/doc/texinfo.tex b/doc/texinfo.tex
new file mode 100644 (file)
index 0000000..332e392
--- /dev/null
@@ -0,0 +1,5625 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{1999-02-14.16}%
+%
+% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+% Free Software Foundation, Inc.
+%
+% This texinfo.tex file is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation; either version 2, or (at
+% your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this texinfo.tex file; see the file COPYING.  If not, write
+% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+% Boston, MA 02111-1307, USA.
+%
+% In other words, you are welcome to use, share and improve this program.
+% You are forbidden to forbid anyone else to use, share and improve
+% what you give them.   Help stamp out software-hoarding!
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   ftp://ftp.gnu.org/pub/gnu/texinfo.tex
+%   (and all GNU mirrors, see http://www.gnu.org/order/ftp.html)
+%   ftp://tug.org/tex/texinfo.tex
+%   ftp://ctan.org/macros/texinfo/texinfo.tex
+%   (and all CTAN mirrors, finger ctan@ctan.org for a list).
+%   /home/gd/gnu/doc/texinfo.tex on the GNU machines.
+% The texinfo.tex in any given Texinfo distribution could well be out
+% of date, so if that's what you're using, please check.
+% There is a small home page for Texinfo at http://texinfo.org/.
+%
+% Send bug reports to bug-texinfo@gnu.org.  Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem.  Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution.  For a simple
+% manual foo.texi, however, you can get away with this:
+%   tex foo.texi
+%   texindex foo.??
+%   tex foo.texi
+%   tex foo.texi
+%   dvips foo.dvi -o # or whatever, to process the dvi file; this makes foo.ps.
+% The extra runs of TeX get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages.  You can get
+% the existing language-specific files from ftp://ftp.gnu.org/gnu/texinfo/.
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+  \catcode`+=\active \catcode`\_=\active}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexi=\i
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexstar=\*
+\let\ptext=\t
+
+% We never want plain's outer \+ definition in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+
+\message{Basics,}
+\chardef\other=12
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined   \gdef\putwordChapter{Chapter}\fi
+\ifx\putwordfile\undefined      \gdef\putwordfile{file}\fi
+\ifx\putwordIndexIsEmpty\undefined     \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined      \gdef\putwordInfo{Info}\fi
+\ifx\putwordMethodon\undefined  \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined  \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined        \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined        \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined      \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined   \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined   \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined       \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined       \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined      \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined   \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined  \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefivar\undefined  \gdef\putwordDefivar{Instance Variable}\fi
+\ifx\putwordDefvar\undefined   \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined   \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeftypevar\undefined\gdef\putwordDeftypevar{Variable}\fi
+\ifx\putwordDeffunc\undefined  \gdef\putwordDeffunc{Function}\fi
+\ifx\putwordDeftypefun\undefined\gdef\putwordDeftypefun{Function}\fi
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+\hyphenation{white-space}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset
+\newdimen \normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\ifx\eTeXversion\undefined
+\def\loggingall{\tracingcommands2 \tracingstats2
+   \tracingpages1 \tracingoutput1 \tracinglostchars1
+   \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+   \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+\else
+\def\loggingall{\tracingcommands3 \tracingstats2
+   \tracingpages1 \tracingoutput1 \tracinglostchars1
+   \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+   \tracingscantokens1 \tracingassigns1 \tracingifs1
+   \tracinggroups1 \tracingnesting2
+   \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+\fi
+
+% For @cropmarks command.
+% Do @cropmarks to get crop marks.
+%
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong  \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Main output routine.
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions, but you have to call it yourself.
+\def\onepageout#1{%
+  \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}%
+  \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}%
+  %
+  {%
+    % Have to do this stuff outside the \shipout because we want it to
+    % take effect in \write's, yet the group defined by the \vbox ends
+    % before the \shipout runs.
+    %
+    \escapechar = `\\     % use backslash in output files.
+    \indexdummies         % don't expand commands in the output.
+    \normalturnoffactive  % \ in index entries must not stay \, e.g., if
+                   % the page break happens to be in the middle of an example.
+    \shipout\vbox{%
+      \ifcropmarks \vbox to \outervsize\bgroup
+        \hsize = \outerhsize
+        \vskip-\topandbottommargin
+        \vtop to0pt{%
+          \line{\ewtop\hfil\ewtop}%
+          \nointerlineskip
+          \line{%
+            \vbox{\moveleft\cornerthick\nstop}%
+            \hfill
+            \vbox{\moveright\cornerthick\nstop}%
+          }%
+          \vss}%
+        \vskip\topandbottommargin
+        \line\bgroup
+          \hfil % center the page within the outer (page) hsize.
+          \ifodd\pageno\hskip\bindingoffset\fi
+          \vbox\bgroup
+      \fi
+      %
+      \unvbox\headlinebox
+      \pagebody{#1}%
+      \ifdim\ht\footlinebox > 0pt
+        % Only leave this space if the footline is nonempty.
+        % (We lessened \vsize for it in \oddfootingxxx.)
+        % The \baselineskip=24pt in plain's \makefootline has no effect.
+        \vskip 2\baselineskip
+        \unvbox\footlinebox
+      \fi
+      %
+      \ifcropmarks
+          \egroup % end of \vbox\bgroup
+        \hfil\egroup % end of (centering) \line\bgroup
+        \vskip\topandbottommargin plus1fill minus1fill
+        \boxmaxdepth = \cornerthick
+        \vbox to0pt{\vss
+          \line{%
+            \vbox{\moveleft\cornerthick\nsbot}%
+            \hfill
+            \vbox{\moveright\cornerthick\nsbot}%
+          }%
+          \nointerlineskip
+          \line{\ewbot\hfil\ewbot}%
+        }%
+      \egroup % \vbox from first cropmarks clause
+      \fi
+    }% end of \shipout\vbox
+  }% end of group with \turnoffactive
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+  \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg#1{%
+  \let\next = #1%
+  \begingroup
+    \obeylines
+    \futurelet\temp\parseargx
+}
+
+% If the next token is an obeyed space (from an @example environment or
+% the like), remove it and recurse.  Otherwise, we're done.
+\def\parseargx{%
+  % \obeyedspace is defined far below, after the definition of \sepspaces.
+  \ifx\obeyedspace\temp
+    \expandafter\parseargdiscardspace
+  \else
+    \expandafter\parseargline
+  \fi
+}
+
+% Remove a single space (as the delimiter token to the macro call).
+{\obeyspaces %
+ \gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    %
+    % First remove any @c comment, then any @comment.
+    % Result of each macro is put in \toks0.
+    \argremovec #1\c\relax %
+    \expandafter\argremovecomment \the\toks0 \comment\relax %
+    %
+    % Call the caller's macro, saved as \next in \parsearg.
+    \expandafter\next\expandafter{\the\toks0}%
+  }%
+}
+
+% Since all \c{,omment} does is throw away the argument, we can let TeX
+% do that for us.  The \relax here is matched by the \relax in the call
+% in \parseargline; it could be more or less anything, its purpose is
+% just to delimit the argument to the \c.
+\def\argremovec#1\c#2\relax{\toks0 = {#1}}
+\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
+
+% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
+%    @end itemize  @c foo
+% will have two active spaces as part of the argument with the
+% `itemize'.  Here we remove all active spaces from #1, and assign the
+% result to \toks0.
+%
+% This loses if there are any *other* active characters besides spaces
+% in the argument -- _ ^ +, for example -- since they get expanded.
+% Fortunately, Texinfo does not define any such commands.  (If it ever
+% does, the catcode of the characters in questionwill have to be changed
+% here.)  But this means we cannot call \removeactivespaces as part of
+% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
+% that \parsearg gets might well have any character at all in it.
+%
+\def\removeactivespaces#1{%
+  \begingroup
+    \ignoreactivespaces
+    \edef\temp{#1}%
+    \global\toks0 = \expandafter{\temp}%
+  \endgroup
+}
+
+% Change the active space to expand to nothing.
+%
+\begingroup
+  \obeyspaces
+  \gdef\ignoreactivespaces{\obeyspaces\let =\empty}
+\endgroup
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment; press RETURN to continue}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo  is the same as @foo, for now.
+\newhelp\EMsimple{Press RETURN to continue.}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+% @end foo executes the definition of \Efoo.
+%
+\def\end{\parsearg\endxxx}
+\def\endxxx #1{%
+  \removeactivespaces{#1}%
+  \edef\endthing{\the\toks0}%
+  %
+  \expandafter\ifx\csname E\endthing\endcsname\relax
+    \expandafter\ifx\csname \endthing\endcsname\relax
+      % There's no \foo, i.e., no ``environment'' foo.
+      \errhelp = \EMsimple
+      \errmessage{Undefined command `@end \endthing'}%
+    \else
+      \unmatchedenderror\endthing
+    \fi
+  \else
+    % Everything's ok; the right environment has been started.
+    \csname E\endthing\endcsname
+  \fi
+}
+
+% There is an environment #1, but it hasn't been started.  Give an error.
+%
+\def\unmatchedenderror#1{%
+  \errhelp = \EMsimple
+  \errmessage{This `@end #1' doesn't have a matching `@#1'}%
+}
+
+% Define the control sequence \E#1 to give an unmatched @end error.
+%
+\def\defineunmatchedend#1{%
+  \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
+}
+
+
+% Single-spacing is done by various environments (specifically, in
+% \nonfillstart and \quotations).
+\newskip\singlespaceskip \singlespaceskip = 12.5pt
+\def\singlespace{%
+  % Why was this kern here?  It messes up equalizing space above and below
+  % environments.  --karl, 6may93
+  %{\advance \baselineskip by -\singlespaceskip
+  %\kern \baselineskip}%
+  \setleading \singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt\char64}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+\def\mylbrace {{\tt\char123}}
+\def\myrbrace {{\tt\char125}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+\begingroup
+  % Definitions to produce actual \{ & \} command in an index.
+  \catcode`\{ = 12 \catcode`\} = 12
+  \catcode`\[ = 1 \catcode`\] = 2
+  \catcode`\@ = 0 \catcode`\\ = 12
+  @gdef@lbracecmd[\{]%
+  @gdef@rbracecmd[\}]%
+@endgroup
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H.
+\let\, = \c
+\let\dotaccent = \.
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \t
+\let\ubaraccent = \b
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown
+% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+  \def\temp{#1}%
+  \ifx\temp\imacro \ptexi
+  \else\ifx\temp\jmacro \j
+  \else \errmessage{@dotless can be used only with i or j}%
+  \fi\fi
+}
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=3000 }
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=3000 }
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+\def\group{\begingroup
+  \ifnum\catcode13=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  %
+  % The \vtop we start below produces a box with normal height and large
+  % depth; thus, TeX puts \baselineskip glue before it, and (when the
+  % next line of text is done) \lineskip glue after it.  (See p.82 of
+  % the TeXbook.)  Thus, space below is not quite equal to space
+  % above.  But it's pretty close.
+  \def\Egroup{%
+    \egroup           % End the \vtop.
+    \endgroup         % End the \group.
+  }%
+  %
+  \vtop\bgroup
+    % We have to put a strut on the last line in case the @group is in
+    % the midst of an example, rather than completely enclosing it.
+    % Otherwise, the interline space between the last line of the group
+    % and the first line afterwards is too small.  But we can't put the
+    % strut in \Egroup, since there it would be on a line by itself.
+    % Hence this just inserts a strut at the beginning of each line.
+    \everypar = {\strut}%
+    %
+    % Since we have a strut on every line, we don't need any of TeX's
+    % normal interline spacing.
+    \offinterlineskip
+    %
+    % OK, but now we have to do something about blank
+    % lines in the input in @example-like environments, which normally
+    % just turn into \lisppar, which will insert no space now that we've
+    % turned off the interline space.  Simplest is to make them be an
+    % empty paragraph.
+    \ifx\par\lisppar
+      \edef\par{\leavevmode \par}%
+      %
+      % Reset ^^M's definition to new definition of \par.
+      \obeylines
+    \fi
+    %
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+% Old definition--didn't work.
+%\def\needx #1{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak
+%\prevdepth=-1000pt
+%}}
+
+\def\needx#1{%
+  % Go into vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % Don't add any leading before our big empty box, but allow a page
+  % break, since the best break might be right here.
+  \allowbreak
+  \nointerlineskip
+  \vtop to #1\mil{\vfil}%
+  %
+  % TeX does not even consider page breaks if a penalty added to the
+  % main vertical list is 10000 or more.  But in order to see if the
+  % empty box we just added fits on the page, we must make it consider
+  % page breaks.  On the other hand, we don't want to actually break the
+  % page after the empty box.  So we use a penalty of 9999.
+  %
+  % There is an extremely small chance that TeX will actually break the
+  % page at this \penalty, if there are no other feasible breakpoints in
+  % sight.  (If the user is using lots of big @group commands, which
+  % almost-but-not-quite fill up a page, TeX will have a hard time doing
+  % good page breaking, for example.)  However, I could not construct an
+  % example where a page broke at this \penalty; if it happens in a real
+  % document, then we can reconsider our strategy.
+  \penalty9999
+  %
+  % Back up by the size of the box, whether we did a page break or not.
+  \kern -#1\mil
+  %
+  % Do not allow a page break right after this kern.
+  \nobreak
+}
+
+% @br   forces paragraph break
+
+\let\br = \par
+
+% @dots{} output an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in a typewriter
+% font as three actual period characters.
+%
+\def\dots{%
+  \leavevmode
+  \hbox to 1.5em{%
+    \hskip 0pt plus 0.25fil minus 0.25fil
+    .\hss.\hss.%
+    \hskip 0pt plus 0.5fil minus 0.5fil
+  }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+  \leavevmode
+  \hbox to 2em{%
+    \hskip 0pt plus 0.25fil minus 0.25fil
+    .\hss.\hss.\hss.%
+    \hskip 0pt plus 0.5fil minus 0.5fil
+  }%
+  \spacefactor=3000
+}
+
+
+% @page    forces the start of a new page
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\def\exdent{\parsearg\exdentyyy}
+\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
+
+% This defn is used inside nofill environments such as @example.
+\def\nofillexdent{\parsearg\nofillexdentyyy}
+\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
+\leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph.
+
+\def\inmargin#1{%
+\strut\vadjust{\nobreak\kern-\strutdepth
+  \vtop to \strutdepth{\baselineskip\strutdepth\vss
+  \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}}
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+
+%\hbox{{\rm#1}}\hfil\break}}
+
+% @include file    insert text of that file as input.
+% Allow normal characters that  we make active in the argument (a file name).
+\def\include{\begingroup
+  \catcode`\\=12
+  \catcode`~=12
+  \catcode`^=12
+  \catcode`_=12
+  \catcode`|=12
+  \catcode`<=12
+  \catcode`>=12
+  \catcode`+=12
+  \parsearg\includezzz}
+% Restore active chars for included file.
+\def\includezzz#1{\endgroup\begingroup
+  % Read the included file in a group so nested @include's work.
+  \def\thisfile{#1}%
+  \input\thisfile
+\endgroup}
+
+\def\thisfile{}
+
+% @center line   outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n   outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\begingroup \catcode`\^^M=\other%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\commentxxx}
+{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}}
+
+\let\c=\comment
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% We cannot implement @paragraphindent asis, though.
+% 
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\def\paragraphindent{\parsearg\doparagraphindent}
+\def\doparagraphindent#1{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \defaultparindent = 0pt
+    \else
+      \defaultparindent = #1em
+    \fi
+  \fi
+  \parindent = \defaultparindent
+}
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written.  Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo).  So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{\implicitmath\ptexbullet\implicitmath}
+\def\minus{\implicitmath-\implicitmath}
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate (before @setfilename).
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+   \iflinks
+     \readauxfile
+   \fi % \openindices needs to do some work in any case.
+   \openindices
+   \fixbackslash  % Turn off hack to swallow `\input texinfo'.
+   \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+   %
+   % If texinfo.cnf is present on the system, read it.
+   % Useful for site-wide @afourpaper, etc.
+   % Just to be on the safe side, close the input stream before the \input.
+   \openin 1 texinfo.cnf
+   \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi
+   \closein1
+   \temp
+   %
+   \comment % Ignore the actual filename.
+}
+
+% Called from \setfilename.
+%
+\def\openindices{%
+  \newindex{cp}%
+  \newcodeindex{fn}%
+  \newcodeindex{vr}%
+  \newcodeindex{tp}%
+  \newcodeindex{ky}%
+  \newcodeindex{pg}%
+}
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{fonts,}
+% Font-change commands.
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this one.
+\def\ttsl{\tenttsl}
+
+% Use Computer Modern fonts at \magstephalf (11pt).
+\newcount\mainmagstep
+\mainmagstep=\magstephalf
+
+% Set the font macro #1 to the font named #2, adding on the
+% specified font prefix (normally `cm').
+% #3 is the font's design size, #4 is a scale factor
+\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4}
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\undefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx}               %where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\setfont\textrm\rmshape{12}{1000}
+\setfont\texttt\ttshape{12}{1000}
+\else
+\setfont\textrm\rmshape{10}{\mainmagstep}
+\setfont\texttt\ttshape{10}{\mainmagstep}
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\setfont\textbf\bfshape{10}{\mainmagstep}
+\setfont\textit\itshape{10}{\mainmagstep}
+\setfont\textsl\slshape{10}{\mainmagstep}
+\setfont\textsf\sfshape{10}{\mainmagstep}
+\setfont\textsc\scshape{10}{\mainmagstep}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun, etc.
+\setfont\defbf\bxshape{10}{\magstep1} %was 1314
+\setfont\deftt\ttshape{10}{\magstep1}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples (9pt).
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\setfont\ninett\ttshape{9}{1000}
+\setfont\ninettsl\ttslshape{10}{900}
+\setfont\indrm\rmshape{9}{1000}
+\setfont\indit\itshape{9}{1000}
+\setfont\indsl\slshape{9}{1000}
+\let\indtt=\ninett
+\let\indttsl=\ninettsl
+\let\indsf=\indrm
+\let\indbf=\indrm
+\setfont\indsc\scshape{10}{900}
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for title page:
+\setfont\titlerm\rmbshape{12}{\magstep3}
+\setfont\titleit\itbshape{10}{\magstep4}
+\setfont\titlesl\slbshape{10}{\magstep4}
+\setfont\titlett\ttbshape{12}{\magstep3}
+\setfont\titlettsl\ttslshape{10}{\magstep4}
+\setfont\titlesf\sfbshape{17}{\magstep1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\authorrm{\secrm}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\setfont\chaprm\rmbshape{12}{\magstep2}
+\setfont\chapit\itbshape{10}{\magstep3}
+\setfont\chapsl\slbshape{10}{\magstep3}
+\setfont\chaptt\ttbshape{12}{\magstep2}
+\setfont\chapttsl\ttslshape{10}{\magstep3}
+\setfont\chapsf\sfbshape{17}{1000}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+% Section fonts (14.4pt).
+\setfont\secrm\rmbshape{12}{\magstep1}
+\setfont\secit\itbshape{10}{\magstep2}
+\setfont\secsl\slbshape{10}{\magstep2}
+\setfont\sectt\ttbshape{12}{\magstep1}
+\setfont\secttsl\ttslshape{10}{\magstep2}
+\setfont\secsf\sfbshape{12}{\magstep1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \setfont\ssecrm\bxshape{10}{\magstep1}    % This size an font looked bad.
+% \setfont\ssecit\itshape{10}{\magstep1}    % The letters were too crowded.
+% \setfont\ssecsl\slshape{10}{\magstep1}
+% \setfont\ssectt\ttshape{10}{\magstep1}
+% \setfont\ssecsf\sfshape{10}{\magstep1}
+
+%\setfont\ssecrm\bfshape{10}{1315}      % Note the use of cmb rather than cmbx.
+%\setfont\ssecit\itshape{10}{1315}      % Also, the size is a little larger than
+%\setfont\ssecsl\slshape{10}{1315}      % being scaled magstep1.
+%\setfont\ssectt\ttshape{10}{1315}
+%\setfont\ssecsf\sfshape{10}{1315}
+
+%\let\ssecbf=\ssecrm
+
+% Subsection fonts (13.15pt).
+\setfont\ssecrm\rmbshape{12}{\magstephalf}
+\setfont\ssecit\itbshape{10}{1315}
+\setfont\ssecsl\slbshape{10}{1315}
+\setfont\ssectt\ttbshape{12}{\magstephalf}
+\setfont\ssecttsl\ttslshape{10}{1315}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{\magstep1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.  Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+  \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+  \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+  \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE.  We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current font.  Plain TeX does \def\bf{\fam=\bffam
+% \tenbf}, for example.  By redefining \tenbf, we obviate the need to
+% redefine \bf itself.
+\def\textfonts{%
+  \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+  \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+  \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl
+  \resetmathfonts}
+\def\titlefonts{%
+  \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+  \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+  \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+  \let\tenttsl=\titlettsl
+  \resetmathfonts \setleading{25pt}}
+\def\titlefont#1{{\titlefonts\rm #1}}
+\def\chapfonts{%
+  \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+  \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+  \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl
+  \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+  \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+  \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+  \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl
+  \resetmathfonts \setleading{16pt}}
+\def\subsecfonts{%
+  \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+  \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+  \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl
+  \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf?
+\def\indexfonts{%
+  \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+  \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+  \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl
+  \resetmathfonts \setleading{12pt}}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Define these so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}
+\setfont\shortcontbf\bxshape{12}{1000}
+\setfont\shortcontsl\slshape{12}{1000}
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx}
+\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+\let\cite=\smartslanted
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+\def\t#1{%
+  {\tt \rawbackslash \frenchspacing #1}%
+  \null
+}
+\let\ttfont=\t
+\def\samp#1{`\tclose{#1}'\null}
+\setfont\smallrm\rmshape{8}{1000}
+\font\smallsy=cmsy9
+\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{%
+  \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+    \vbox{\hrule\kern-0.4pt
+     \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+    \kern-0.4pt\hrule}%
+  \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+% The old definition, with no lozenge:
+%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @file, @option are the same as @samp.
+\let\file=\samp
+\let\option=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \rawbackslash
+    \frenchspacing
+    #1%
+  }%
+  \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in \code.
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash.
+%  -- rms.
+{
+  \catcode`\-=\active
+  \catcode`\_=\active
+  %
+  \global\def\code{\begingroup
+    \catcode`\-=\active \let-\codedash
+    \catcode`\_=\active \let_\codeunder
+    \codex
+  }
+  %
+  % If we end up with any active - characters when handling the index,
+  % just treat them as a normal -.
+  \global\def\indexbreaks{\catcode`\-=\active \let-\realdash}
+}
+
+\def\realdash{-}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}}
+\def\codex #1{\tclose{#1}\endgroup}
+
+%\let\exp=\tclose  %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+%   `example' (@kbd uses ttsl only inside of @example and friends),
+%   or `code' (@kbd uses normal tty font always).
+\def\kbdinputstyle{\parsearg\kbdinputstylexxx}
+\def\kbdinputstylexxx#1{%
+  \def\arg{#1}%
+  \ifx\arg\worddistinct
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+  \else\ifx\arg\wordexample
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+  \else\ifx\arg\wordcode
+    \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is kbdinputdistinct.  (Too much of a hassle to call the macro,
+% the catcodes are wrong for parsearg to work.)
+\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else{\tclose{\kbdfont\look}}\fi
+\else{\tclose{\kbdfont\look}}\fi}
+
+% For @url, @env, @command quotes seem unnecessary, so use \code.
+\let\url=\code
+\let\env=\code
+\let\command=\code
+
+% @uref (abbreviation for `urlref') takes an optional (comma-separated)
+% second argument specifying the text to display and an optional third
+% arg as text to display instead of (rather than in addition to) the url
+% itself.  First (mandatory) arg is the url.  Perhaps eventually put in
+% a hypertex \special here.
+%
+\def\uref#1{\douref #1,,,\finish}
+\def\douref#1,#2,#3,#4\finish{%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0 > 0pt
+      \unhbox0\ (\code{#1})% second arg given, show both it and url
+    \else
+      \code{#1}% only url given, so show it
+    \fi
+  \fi
+}
+
+% rms does not like the angle brackets --karl, 17may97.
+% So now @email is just like @uref.
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\let\email=\uref
+
+% Check if we are currently using a typewriter font.  Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+% @l was never documented to mean ``switch to the Lisp font'',
+% and it is not used as such in any manual I can find.  We need it for
+% Polish suppressed-l.  --karl, 22sep96.
+%\def\l#1{{\li #1}\null}
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}}              % roman font
+\def\sc#1{{\smallcaps#1}}       % smallcaps font
+\def\ii#1{{\it #1}}             % italic font
+
+% @acronym downcases the argument and prints in smallcaps.
+\def\acronym#1{{\smallcaps \lowercase{#1}}}
+
+% @pounds{} is a sterling sign.
+\def\pounds{{\it\$}}
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+%
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\def\shorttitlepage{\parsearg\shorttitlepagezzz}
+\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+        \endgroup\page\hbox{}\page}
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+   \let\subtitlerm=\tenrm
+   \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+   %
+   \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+   %
+   % Leave some space at the very top of the page.
+   \vglue\titlepagetopglue
+   %
+   % Now you can print the title using @title.
+   \def\title{\parsearg\titlezzz}%
+   \def\titlezzz##1{\leftline{\titlefonts\rm ##1}
+                    % print a rule at the page bottom also.
+                    \finishedtitlepagefalse
+                    \vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
+   % No rule at page bottom unless we print one at the top with @title.
+   \finishedtitlepagetrue
+   %
+   % Now you can put text using @subtitle.
+   \def\subtitle{\parsearg\subtitlezzz}%
+   \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+   %
+   % @author should come last, but may come many times.
+   \def\author{\parsearg\authorzzz}%
+   \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+      {\authorfont \leftline{##1}}}%
+   %
+   % Most title ``pages'' are actually two pages long, with space
+   % at the top of the second.  We don't want the ragged left on the second.
+   \let\oldpage = \page
+   \def\page{%
+      \iffinishedtitlepage\else
+         \finishtitlepage
+      \fi
+      \oldpage
+      \let\page = \oldpage
+      \hbox{}}%
+%   \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+   \iffinishedtitlepage\else
+      \finishtitlepage
+   \fi
+   % It is important to do the page break before ending the group,
+   % because the headline and footline are only empty inside the group.
+   % If we use the new definition of \page, we always get a blank page
+   % after the title page, which we certainly don't want.
+   \oldpage
+   \endgroup
+   %
+   % If they want short, they certainly want long too.
+   \ifsetshortcontentsaftertitlepage
+     \shortcontents
+     \contents
+     \global\let\shortcontents = \relax
+     \global\let\contents = \relax
+   \fi
+   %
+   \ifsetcontentsaftertitlepage
+     \contents
+     \global\let\contents = \relax
+     \global\let\shortcontents = \relax
+   \fi
+   %
+   \HEADINGSon
+}
+
+\def\finishtitlepage{%
+   \vskip4pt \hrule height 2pt width \hsize
+   \vskip\titlepagebottomglue
+   \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline    % headline on even pages
+\newtoks\oddheadline     % headline on odd pages
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+  \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  %
+  % Leave some space for the footline.  Hopefully ok to assume
+  % @evenfooting will not be used by itself.
+  \global\advance\pageheight by -\baselineskip
+  \global\advance\vsize by -\baselineskip
+}
+
+\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+%
+}% unbind the catcode of @.
+
+% @headings double      turns headings on for double-sided printing.
+% @headings single      turns headings on for single-sided printing.
+% @headings off         turns them off.
+% @headings on          same as @headings double, retained for compatibility.
+% @headings after       turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{%
+  \number\day\space
+  \ifcase\month
+  \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+  \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+  \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+  \fi
+  \space\number\year}
+
+% @settitle line...  specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @vtable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+                 \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+                 \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemfont{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  Unfortunately
+    % we can't prevent a possible page break at the following
+    % \baselineskip glue.
+    \nobreak
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.
+    \noindent
+    % Do this with kerns and \unhbox so that if there is a footnote in
+    % the item text, it can migrate to the main vertical list and
+    % eventually be printed.
+    \nobreak\kern-\tableindent
+    \dimen0 = \itemmax  \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+    \unhbox0
+    \nobreak\kern\dimen0
+    \endgroup
+    \itemxneedsnegativevskiptrue
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+% Contains a kludge to get @end[description] to work.
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+% @table, @ftable, @vtable.
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1        \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1        \endtabley
+\def\Eftable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
+{\obeylines\obeyspaces%
+\gdef\vtablex #1^^M{%
+\tabley\vritemindex#1        \endtabley
+\def\Evtable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+\def\vritemindex #1{\doind {vr}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Necessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\exdentamount=\tableindent
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\afterenvbreak\endgroup}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+  \begingroup % ended by the @end itemize
+  \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\exdentamount=\itemindent
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\afterenvbreak\endgroup}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+  \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  \begingroup % ended by the @end enumerate
+  %
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <number>.
+    %
+    \ifnum\lccode\expandafter`\thearg=0\relax
+      \numericenumerate % a number (we hope)
+    \else
+      % It's a letter.
+      \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+        \lowercaseenumerate % lowercase letter
+      \else
+        \uppercaseenumerate % uppercase letter
+      \fi
+    \fi
+  \else
+    % Multiple tokens in the argument.  We hope it's a number.
+    \numericenumerate
+  \fi
+}
+
+% An @enumerate whose labels are integers.  The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+  \itemno = \thearg
+  \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more lowercase letters in @enumerate; get a bigger
+                  alphabet}%
+    \fi
+    \char\lccode\itemno
+  }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more uppercase letters in @enumerate; get a bigger
+                  alphabet}
+    \fi
+    \char\uccode\itemno
+  }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments.  Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+  \advance\itemno by -1
+  \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{In hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble.  Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+%   @multitable @columnfractions .25 .3 .45
+%   @item ...
+%
+%   Numbers following @columnfractions are the percent of the total
+%   current hsize to be used for each column. You may use as many
+%   columns as desired.
+
+
+% Or use a template:
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item ...
+%   using the widest term desired in each column.
+%
+% For those who want to use more than one line's worth of words in
+% the preamble, break the line within one argument and it
+% will parse correctly, i.e.,
+%
+%     @multitable {Column 1 template} {Column 2 template} {Column 3
+%      template}
+% Not:
+%     @multitable {Column 1 template} {Column 2 template}
+%      {Column 3 template}
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab, @multitable or @end multitable do not need to be on their
+% own lines, but it will not hurt if they are.
+
+% Sample multitable:
+
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item first col stuff @tab second col stuff @tab third col
+%   @item
+%   first col stuff
+%   @tab
+%   second col stuff
+%   @tab
+%   third col
+%   @item first col stuff @tab second col stuff
+%   @tab Many paragraphs of text may be used in any column.
+%
+%         They will wrap at the width determined by the template.
+%   @item@tab@tab This will be in third column.
+%   @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+%                                                            to baseline.
+%   0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the part of the @columnfraction before the decimal point, which
+% is presumably either 0 or the empty string (but we don't check, we
+% just throw it away).  #2 is the decimal part, which we use as the
+% percent of \hsize for this column.
+\def\pickupwholefraction#1.#2 {%
+  \global\advance\colcount by 1
+  \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}%
+  \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+  \def\firstarg{#1}%
+  \ifx\firstarg\xendsetuptable
+    \let\go = \relax
+  \else
+    \ifx\firstarg\xcolumnfractions
+      \global\setpercenttrue
+    \else
+      \ifsetpercent
+         \let\go\pickupwholefraction
+      \else
+         \global\advance\colcount by 1
+         \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator;
+                            % typically that is always in the input, anyway.
+         \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+      \fi
+    \fi
+    \ifx\go\pickupwholefraction
+      % Put the argument back for the \pickupwholefraction call, so
+      % we'll always have a period there to be parsed.
+      \def\go{\pickupwholefraction#1}%
+    \else
+      \let\go = \setuptable
+    \fi%
+  \fi
+  \go
+}
+
+% multitable syntax
+\def\tab{&\hskip1sp\relax} % 2/2/96
+                           % tiny skip here makes sure this column space is
+                           % maintained, even if it is never used.
+
+% @multitable ... @end multitable definitions:
+%
+\def\multitable{\parsearg\dotable}
+\def\dotable#1{\bgroup
+  \vskip\parskip
+  \let\item\crcr
+  \tolerance=9500
+  \hbadness=9500
+  \setmultitablespacing
+  \parskip=\multitableparskip
+  \parindent=\multitableparindent
+  \overfullrule=0pt
+  \global\colcount=0
+  \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}%
+  %
+  % To parse everything between @multitable and @item:
+  \setuptable#1 \endsetuptable
+  %
+  % \everycr will reset column counter, \colcount, at the end of
+  % each line. Every column entry will cause \colcount to advance by one.
+  % The table preamble
+  % looks at the current \colcount to find the correct column width.
+  \everycr{\noalign{%
+  %
+  % \filbreak%% keeps underfull box messages off when table breaks over pages.
+  % Maybe so, but it also creates really weird page breaks when the table
+  % breaks over pages. Wouldn't \vfil be better?  Wait until the problem
+  % manifests itself, so it can be fixed for real --karl.
+    \global\colcount=0\relax}}%
+  %
+  % This preamble sets up a generic column definition, which will
+  % be used as many times as user calls for columns.
+  % \vtop will set a single line and will also let text wrap and
+  % continue for many paragraphs if desired.
+  \halign\bgroup&\global\advance\colcount by 1\relax
+    \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
+  %
+  % In order to keep entries from bumping into each other
+  % we will add a \leftskip of \multitablecolspace to all columns after
+  % the first one.
+  %
+  % If a template has been used, we will add \multitablecolspace
+  % to the width of each template entry.
+  %
+  % If the user has set preamble in terms of percent of \hsize we will
+  % use that dimension as the width of the column, and the \leftskip
+  % will keep entries from bumping into each other.  Table will start at
+  % left margin and final column will justify at right margin.
+  %
+  % Make sure we don't inherit \rightskip from the outer environment.
+  \rightskip=0pt
+  \ifnum\colcount=1
+    % The first column will be indented with the surrounding text.
+    \advance\hsize by\leftskip
+  \else
+    \ifsetpercent \else
+      % If user has not set preamble in terms of percent of \hsize
+      % we will advance \hsize by \multitablecolspace.
+      \advance\hsize by \multitablecolspace
+    \fi
+   % In either case we will make \leftskip=\multitablecolspace:
+  \leftskip=\multitablecolspace
+  \fi
+  % Ignoring space at the beginning and end avoids an occasional spurious
+  % blank line, when TeX decides to break the line at the space before the
+  % box from the multistrut, so the strut ends up on a line by itself.
+  % For example:
+  % @multitable @columnfractions .11 .89
+  % @item @code{#}
+  % @tab Legal holiday which is valid in major parts of the whole country.
+  % Is automatically provided with highlighting sequences respectively marking
+  % characters.
+  \noindent\ignorespaces##\unskip\multistrut}\cr
+}
+
+\def\setmultitablespacing{% test to see if user has set \multitablelinespace.
+% If so, do nothing. If not, give it an appropriate dimension based on
+% current baselineskip.
+\ifdim\multitablelinespace=0pt
+%% strut to put in table in case some entry doesn't have descenders,
+%% to keep lines equally spaced
+\let\multistrut = \strut
+%% Test to see if parskip is larger than space between lines of
+%% table. If not, do nothing.
+%%        If so, set to same dimension as multitablelinespace.
+\else
+\gdef\multistrut{\vrule height\multitablelinespace depth\dp0
+width0pt\relax} \fi
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+                                      %% than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+                                      %% than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+  \let\chapter=\relax
+  \let\unnumbered=\relax
+  \let\top=\relax
+  \let\unnumberedsec=\relax
+  \let\unnumberedsection=\relax
+  \let\unnumberedsubsec=\relax
+  \let\unnumberedsubsection=\relax
+  \let\unnumberedsubsubsec=\relax
+  \let\unnumberedsubsubsection=\relax
+  \let\section=\relax
+  \let\subsec=\relax
+  \let\subsubsec=\relax
+  \let\subsection=\relax
+  \let\subsubsection=\relax
+  \let\appendix=\relax
+  \let\appendixsec=\relax
+  \let\appendixsection=\relax
+  \let\appendixsubsec=\relax
+  \let\appendixsubsection=\relax
+  \let\appendixsubsubsec=\relax
+  \let\appendixsubsubsection=\relax
+  \let\contents=\relax
+  \let\smallbook=\relax
+  \let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+  \let\defcodeindex = \relax
+  \let\defcv = \relax
+  \let\deffn = \relax
+  \let\deffnx = \relax
+  \let\defindex = \relax
+  \let\defivar = \relax
+  \let\defmac = \relax
+  \let\defmethod = \relax
+  \let\defop = \relax
+  \let\defopt = \relax
+  \let\defspec = \relax
+  \let\deftp = \relax
+  \let\deftypefn = \relax
+  \let\deftypefun = \relax
+  \let\deftypevar = \relax
+  \let\deftypevr = \relax
+  \let\defun = \relax
+  \let\defvar = \relax
+  \let\defvr = \relax
+  \let\ref = \relax
+  \let\xref = \relax
+  \let\printindex = \relax
+  \let\pxref = \relax
+  \let\settitle = \relax
+  \let\setchapternewpage = \relax
+  \let\setchapterstyle = \relax
+  \let\everyheading = \relax
+  \let\evenheading = \relax
+  \let\oddheading = \relax
+  \let\everyfooting = \relax
+  \let\evenfooting = \relax
+  \let\oddfooting = \relax
+  \let\headings = \relax
+  \let\include = \relax
+  \let\lowersections = \relax
+  \let\down = \relax
+  \let\raisesections = \relax
+  \let\up = \relax
+  \let\set = \relax
+  \let\clear = \relax
+  \let\item = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\html{\doignore{html}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% @dircategory CATEGORY  -- specify a category of the dir file
+% which this file should belong to.  Ignore this in TeX.
+\let\dircategory = \comment
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+  % Don't complain about control sequences we have declared \outer.
+  \ignoresections
+  %
+  % Define a command to swallow text until we reach `@end #1'.
+  % This @ is a catcode 12 token (that is the normal catcode of @ in
+  % this texinfo.tex file).  We change the catcode of @ below to match.
+  \long\def\doignoretext##1@end #1{\enddoignore}%
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \catcode32 = 10
+  %
+  % Ignore braces, too, so mismatched braces don't cause trouble.
+  \catcode`\{ = 9
+  \catcode`\} = 9
+  %
+  % We must not have @c interpreted as a control sequence.
+  \catcode`\@ = 12
+  %
+  % Make the letter c a comment character so that the rest of the line
+  % will be ignored. This way, the document can have (for example)
+  %   @c @end ifinfo
+  % and the @end ifinfo will be properly ignored.
+  % (We've just changed @ to catcode 12.)
+  \catcode`\c = 14
+  %
+  % And now expand that command.
+  \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+  \ifwarnedobs\relax\else
+  % We need to warn folks that they may have trouble with TeX 3.0.
+  % This uses \immediate\write16 rather than \message to get newlines.
+    \immediate\write16{}
+    \immediate\write16{WARNING: for users of Unix TeX 3.0!}
+    \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+    \immediate\write16{If you are running another version of TeX, relax.}
+    \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+    \immediate\write16{  Then upgrade your TeX installation if you can.}
+    \immediate\write16{  (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)}
+    \immediate\write16{If you are stuck with version 3.0, run the}
+    \immediate\write16{  script ``tex3patch'' from the Texinfo distribution}
+    \immediate\write16{  to use a workaround.}
+    \immediate\write16{}
+    \global\warnedobstrue
+    \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex.  For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+  \obstexwarn
+  % We must actually expand the ignored text to look for the @end
+  % command, so that nested ignore constructs work.  Thus, we put the
+  % text into a \vbox and then do nothing with the result.  To minimize
+  % the change of memory overflow, we follow the approach outlined on
+  % page 401 of the TeXbook: make the current font be a dummy font.
+  %
+  \setbox0 = \vbox\bgroup
+    % Don't complain about control sequences we have declared \outer.
+    \ignoresections
+    %
+    % Define `@end #1' to end the box, which will in turn undefine the
+    % @end command again.
+    \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+    %
+    % We are going to be parsing Texinfo commands.  Most cause no
+    % trouble when they are used incorrectly, but some commands do
+    % complicated argument parsing or otherwise get confused, so we
+    % undefine them.
+    %
+    % We can't do anything about stray @-signs, unfortunately;
+    % they'll produce `undefined control sequence' errors.
+    \ignoremorecommands
+    %
+    % Set the current font to be \nullfont, a TeX primitive, and define
+    % all the font commands to also use \nullfont.  We don't use
+    % dummy.tfm, as suggested in the TeXbook, because not all sites
+    % might have that installed.  Therefore, math mode will still
+    % produce output, but that should be an extremely small amount of
+    % stuff compared to the main input.
+    %
+    \nullfont
+    \let\tenrm = \nullfont  \let\tenit = \nullfont  \let\tensl = \nullfont
+    \let\tenbf = \nullfont  \let\tentt = \nullfont  \let\smallcaps = \nullfont
+    \let\tensf = \nullfont
+    % Similarly for index fonts (mostly for their use in
+    % smallexample)
+    \let\indrm = \nullfont  \let\indit = \nullfont  \let\indsl = \nullfont
+    \let\indbf = \nullfont  \let\indtt = \nullfont  \let\indsc = \nullfont
+    \let\indsf = \nullfont
+    %
+    % Don't complain when characters are missing from the fonts.
+    \tracinglostchars = 0
+    %
+    % Don't bother to do space factor calculations.
+    \frenchspacing
+    %
+    % Don't report underfull hboxes.
+    \hbadness = 10000
+    %
+    % Do minimal line-breaking.
+    \pretolerance = 10000
+    %
+    % Do not execute instructions in @tex
+    \def\tex{\doignore{tex}}%
+    % Do not execute macro definitions.
+    % `c' is a comment character, so the word `macro' will get cut off.
+    \def\macro{\doignore{ma}}%
+}
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.  Make sure the catcode of space is correct to avoid
+% losing inside @example, for instance.
+%
+\def\set{\begingroup\catcode` =10
+  \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR.
+  \parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  \def\temp{#2}%
+  \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+  \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+  \fi
+  \endgroup
+}
+% Can't use \xdef to pre-expand #2 and save some time, since \temp or
+% \next or other control sequences that we've defined might get us into
+% an infinite loop. Consider `@set foo @cite{bar}'.
+\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+{
+  \catcode`\_ = \active
+  %
+  % We might end up with active _ or - characters in the argument if
+  % we're called from @code, as @code{@value{foo-bar_}}.  So \let any
+  % such active characters to their normal equivalents.
+  \gdef\value{\begingroup
+    \catcode`\-=12 \catcode`\_=12
+    \indexbreaks \let_\normalunderscore
+    \valuexxx}
+}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we \let\value to this in \indexdummies).  Ones
+% whose names contain - or _ still won't work, but we can't do anything
+% about that.  The command has to be fully expandable, since the result
+% winds up in the index file.  This means that if the variable's value
+% contains other Texinfo commands, it's almost certain it will fail
+% (although perhaps we could fix that with sufficient work to do a
+% one-level expansion on the result, instead of complete).
+%
+\def\expandablevalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    {[No value for ``#1'']}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \expandafter\ifsetfail
+  \else
+    \expandafter\ifsetsucceed
+  \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \expandafter\ifclearsucceed
+  \else
+    \expandafter\ifclearfail
+  \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text
+% following, through the first @end iftex (etc.).  Make `@end iftex'
+% (etc.) valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\def\ifnothtml{\conditionalsucceed{ifnothtml}}
+\def\ifnotinfo{\conditionalsucceed{ifnotinfo}}
+\defineunmatchedend{iftex}
+\defineunmatchedend{ifnothtml}
+\defineunmatchedend{ifnotinfo}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group).  So we must
+% define \Eiftex to redefine itself to be its previous value.  (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+  \edef\temp{%
+    % Remember the current value of \E#1.
+    \let\nece{prevE#1} = \nece{E#1}%
+    %
+    % At the `@end #1', redefine \E#1 to be its previous value.
+    \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+  }%
+  \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%     % Define @#1index
+    \noexpand\doindex{#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+% The \closeout helps reduce unnecessary open files; the limit on the
+% Acorn RISC OS is a mere 16 files.
+\def\synindex#1 #2 {%
+  \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+  \expandafter\closeout\csname#1indfile\endcsname
+  \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+  \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+    \noexpand\doindex{#2}}%
+}
+
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex#1 #2 {%
+  \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+  \expandafter\closeout\csname#1indfile\endcsname
+  \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+  \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+    \noexpand\docodeindex{#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\ { }%
+% Take care of the plain tex accent commands.
+\def\"{\realbackslash "}%
+\def\`{\realbackslash `}%
+\def\'{\realbackslash '}%
+\def\^{\realbackslash ^}%
+\def\~{\realbackslash ~}%
+\def\={\realbackslash =}%
+\def\b{\realbackslash b}%
+\def\c{\realbackslash c}%
+\def\d{\realbackslash d}%
+\def\u{\realbackslash u}%
+\def\v{\realbackslash v}%
+\def\H{\realbackslash H}%
+% Take care of the plain tex special European modified letters.
+\def\oe{\realbackslash oe}%
+\def\ae{\realbackslash ae}%
+\def\aa{\realbackslash aa}%
+\def\OE{\realbackslash OE}%
+\def\AE{\realbackslash AE}%
+\def\AA{\realbackslash AA}%
+\def\o{\realbackslash o}%
+\def\O{\realbackslash O}%
+\def\l{\realbackslash l}%
+\def\L{\realbackslash L}%
+\def\ss{\realbackslash ss}%
+% Take care of texinfo commands likely to appear in an index entry.
+% (Must be a way to avoid doing expansion at all, and thus not have to
+% laboriously list every single command here.)
+\def\@{@}% will be @@ when we switch to @ as escape char.
+% Need these in case \tex is in effect and \{ is a \delimiter again.
+% But can't use \lbracecmd and \rbracecmd because texindex assumes
+% braces and backslashes are used only as delimiters.
+\let\{ = \mylbrace
+\let\} = \myrbrace
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+%\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\result{\realbackslash result}%
+\def\equiv{\realbackslash equiv}%
+\def\expansion{\realbackslash expansion}%
+\def\print{\realbackslash print}%
+\def\error{\realbackslash error}%
+\def\point{\realbackslash point}%
+\def\copyright{\realbackslash copyright}%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\uref##1{\realbackslash uref {##1}}%
+\def\url##1{\realbackslash url {##1}}%
+\def\env##1{\realbackslash env {##1}}%
+\def\command##1{\realbackslash command {##1}}%
+\def\option##1{\realbackslash option {##1}}%
+\def\dotless##1{\realbackslash dotless {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\,##1{\realbackslash ,{##1}}%
+\def\t##1{\realbackslash t {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\sc##1{\realbackslash sc {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+\def\acronym##1{\realbackslash acronym {##1}}%
+%
+% Handle some cases of @value -- where the variable name does not
+% contain - or _, and the value does not contain any
+% (non-fully-expandable) commands.
+\let\value = \expandablevalue
+%
+\unsepspaces
+% Turn off macro expansion
+\turnoffmacros
+}
+
+% If an index command is used in an @example environment, any spaces
+% therein should become regular spaces in the raw index file, not the
+% expansion of \tie (\\leavevmode \penalty \@M \ ).
+{\obeyspaces
+ \gdef\unsepspaces{\obeyspaces\let =\space}}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+% Just ignore accents.
+\let\,=\indexdummyfont
+\let\"=\indexdummyfont
+\let\`=\indexdummyfont
+\let\'=\indexdummyfont
+\let\^=\indexdummyfont
+\let\~=\indexdummyfont
+\let\==\indexdummyfont
+\let\b=\indexdummyfont
+\let\c=\indexdummyfont
+\let\d=\indexdummyfont
+\let\u=\indexdummyfont
+\let\v=\indexdummyfont
+\let\H=\indexdummyfont
+\let\dotless=\indexdummyfont
+% Take care of the plain tex special European modified letters.
+\def\oe{oe}%
+\def\ae{ae}%
+\def\aa{aa}%
+\def\OE{OE}%
+\def\AE{AE}%
+\def\AA{AA}%
+\def\o{o}%
+\def\O{O}%
+\def\l{l}%
+\def\L{L}%
+\def\ss{ss}%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\url=\indexdummyfont
+\let\uref=\indexdummyfont
+\let\env=\indexdummyfont
+\let\command=\indexdummyfont
+\let\option=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+\def\@{@}%
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+ @gdef@realbackslash{\}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% For \ifx comparisons.
+\def\emptymacro{\empty}
+
+% Most index entries go through here, but \dosubind is the general case.
+%
+\def\doind#1#2{\dosubind{#1}{#2}\empty}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% \empty if called from \doind, as we usually are.  The main exception
+% is with defuns, which call us directly.
+%
+\def\dosubind#1#2#3{%
+  % Put the index entry in the margin if desired.
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}%
+  \fi
+  {%
+    \count255=\lastpenalty
+    {%
+      \indexdummies % Must do this here, since \bf, etc expand at this stage
+      \escapechar=`\\
+      {%
+        \let\folio = 0% We will expand all macros now EXCEPT \folio.
+        \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+        % so it will be output as is; and it will print as backslash.
+        %
+        \def\thirdarg{#3}%
+        %
+        % If third arg is present, precede it with space in sort key.
+        \ifx\thirdarg\emptymacro
+          \let\subentry = \empty
+        \else
+          \def\subentry{ #3}%
+        \fi
+        %
+        % First process the index entry with all font commands turned
+        % off to get the string to sort by.
+        {\indexnofonts \xdef\indexsorttmp{#2\subentry}}%
+        %
+        % Now the real index entry with the fonts.
+        \toks0 = {#2}%
+        %
+        % If third (subentry) arg is present, add it to the index
+        % string.  And include a space.
+        \ifx\thirdarg\emptymacro \else
+          \toks0 = \expandafter{\the\toks0 \space #3}%
+        \fi
+        %
+        % Set up the complete index entry, with both the sort key
+        % and the original text, including any font commands.  We write
+        % three arguments to \entry to the .?? file, texindex reduces to
+        % two when writing the .??s sorted result.
+        \edef\temp{%
+          \write\csname#1indfile\endcsname{%
+            \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}%
+        }%
+        %
+        % If a skip is the last thing on the list now, preserve it
+        % by backing up by \lastskip, doing the \write, then inserting
+        % the skip again.  Otherwise, the whatsit generated by the
+        % \write will make \lastskip zero.  The result is that sequences
+        % like this:
+        % @end defun
+        % @tindex whatever
+        % @defun ...
+        % will have extra space inserted, because the \medbreak in the
+        % start of the @defun won't see the skip inserted by the @end of
+        % the previous defun.
+        %
+        % But don't do any of this if we're not in vertical mode.  We
+        % don't want to do a \vskip and prematurely end a paragraph.
+        %
+        % Avoid page breaks due to these extra skips, too.
+        %
+        \iflinks
+          \ifvmode
+            \skip0 = \lastskip
+            \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi
+          \fi
+          %
+          \temp % do the write
+          %
+          %
+          \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi
+        \fi
+      }%
+    }%
+    \penalty\count255
+  }%
+}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\def\printindex{\parsearg\doprintindex}
+\def\doprintindex#1{\begingroup
+  \dobreak \chapheadingskip{10000}%
+  %
+  \indexfonts \rm
+  \tolerance = 9500
+  \indexbreaks
+  %
+  % See if the index file exists and is nonempty.
+  % Change catcode of @ here so that if the index file contains
+  % \initial {@}
+  % as its first line, TeX doesn't complain about mismatched braces
+  % (because it thinks @} is a control sequence).
+  \catcode`\@ = 11
+  \openin 1 \jobname.#1s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    \putwordIndexNonexistent
+  \else
+    %
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \temp
+    \ifeof 1
+      \putwordIndexIsEmpty
+    \else
+      % Index files are almost Texinfo source, but we use \ as the escape
+      % character.  It would be better to use @, but that's too big a change
+      % to make right now.
+      \def\indexbackslash{\rawbackslashxx}%
+      \catcode`\\ = 0
+      \escapechar = `\\
+      \begindoublecolumns
+      \input \jobname.#1s
+      \enddoublecolumns
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+  % Some minor font changes for the special characters.
+  \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+  %
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  %
+  % We like breaks before the index initials, so insert a bonus.
+  \penalty -300
+  %
+  % Typeset the initial.  Making this add up to a whole number of
+  % baselineskips increases the chance of the dots lining up from column
+  % to column.  It still won't often be perfect, because of the stretch
+  % we need before each entry, but it's better.
+  %
+  % No shrink because it confuses \balancecolumns.
+  \vskip 1.67\baselineskip plus .5\baselineskip
+  \leftline{\secbf #1}%
+  \vskip .33\baselineskip plus .1\baselineskip
+  %
+  % Do our best not to break after the initial.
+  \nobreak
+}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin.  It is used for index and table of contents
+% entries.  The paragraph is indented by \leftskip.
+%
+\def\entry#1#2{\begingroup
+  %
+  % Start a new paragraph if necessary, so our assignments below can't
+  % affect previous text.
+  \par
+  %
+  % Do not fill out the last line with white space.
+  \parfillskip = 0in
+  %
+  % No extra space above this paragraph.
+  \parskip = 0in
+  %
+  % Do not prefer a separate line ending with a hyphen to fewer lines.
+  \finalhyphendemerits = 0
+  %
+  % \hangindent is only relevant when the entry text and page number
+  % don't both fit on one line.  In that case, bob suggests starting the
+  % dots pretty far over on the line.  Unfortunately, a large
+  % indentation looks wrong when the entry text itself is broken across
+  % lines.  So we use a small indentation and put up with long leaders.
+  %
+  % \hangafter is reset to 1 (which is the value we want) at the start
+  % of each paragraph, so we need not do anything with that.
+  \hangindent = 2em
+  %
+  % When the entry text needs to be broken, just fill out the first line
+  % with blank space.
+  \rightskip = 0pt plus1fil
+  %
+  % A bit of stretch before each entry for the benefit of balancing columns.
+  \vskip 0pt plus1pt
+  %
+  % Start a ``paragraph'' for the index entry so the line breaking
+  % parameters we've set above will have an effect.
+  \noindent
+  %
+  % Insert the text of the index entry.  TeX will do line-breaking on it.
+  #1%
+  % The following is kludged to not output a line of dots in the index if
+  % there are no page numbers.  The next person who breaks this will be
+  % cursed by a Unix daemon.
+  \def\tempa{{\rm }}%
+  \def\tempb{#2}%
+  \edef\tempc{\tempa}%
+  \edef\tempd{\tempb}%
+  \ifx\tempc\tempd\ \else%
+    %
+    % If we must, put the page number on a line of its own, and fill out
+    % this line with blank space.  (The \hfil is overwhelmed with the
+    % fill leaders glue in \indexdotfill if the page number does fit.)
+    \hfil\penalty50
+    \null\nobreak\indexdotfill % Have leaders before the page number.
+    %
+    % The `\ ' here is removed by the implicit \unskip that TeX does as
+    % part of (the primitive) \par.  Without it, a spurious underfull
+    % \hbox ensues.
+    \ #2% The page number ends the paragraph.
+  \fi%
+  \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % Grab any single-column material above us.
+  \output = {%
+    %
+    % Here is a possibility not foreseen in manmac: if we accumulate a
+    % whole lot of material, we might end up calling this \output
+    % routine twice in a row (see the doublecol-lose test, which is
+    % essentially a couple of indexes with @setchapternewpage off).  In
+    % that case we just ship out what is in \partialpage with the normal
+    % output routine.  Generally, \partialpage will be empty when this
+    % runs and this will be a no-op.  See the indexspread.tex test case.
+    \ifvoid\partialpage \else
+      \onepageout{\pagecontents\partialpage}%
+    \fi
+    %
+    \global\setbox\partialpage = \vbox{%
+      % Unvbox the main output page.
+      \unvbox\PAGE
+      \kern-\topskip \kern\baselineskip
+    }%
+  }%
+  \eject % run that output routine to set \partialpage
+  %
+  % Use the double-column output routine for subsequent pages.
+  \output = {\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it in one place.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +-<1pt)
+  % as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Double the \vsize as well.  (We don't need a separate register here,
+  % since nobody clobbers \vsize.)
+  \advance\vsize by -\ht\partialpage
+  \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+%
+\def\doublecolumnout{%
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar
+  \unvbox255
+  \penalty\outputpenalty
+}
+\def\pagesofar{%
+  % Re-output the contents of the output page -- any previous material,
+  % followed by the two boxes we just split, in box0 and box2.
+  \unvbox\partialpage
+  %
+  \hsize = \doublecolumnhsize
+  \wd0=\hsize \wd2=\hsize
+  \hbox to\pagewidth{\box0\hfil\box2}%
+}
+\def\enddoublecolumns{%
+  \output = {%
+    % Split the last of the double-column material.  Leave it on the
+    % current page, no automatic page break.
+    \balancecolumns
+    %
+    % If we end up splitting too much material for the current page,
+    % though, there will be another page break right after this \output
+    % invocation ends.  Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.  (We hope \balancecolumns will never be
+    % called on to balance too much material, but if it is, this makes
+    % the output somewhat more palatable.)
+    \global\output = {\onepageout{\pagecontents\PAGE}}%
+  }%
+  \eject
+  \endgroup % started in \begindoublecolumns
+  %
+  % \pagegoal was set to the doubled \vsize above, since we restarted
+  % the current page.  We're now back to normal single-column
+  % typesetting, so reset \pagegoal to the normal \vsize (after the
+  % \endgroup where \vsize got restored).
+  \pagegoal = \vsize
+}
+\def\balancecolumns{%
+  % Called at the end of the double column material.
+  \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \advance\dimen@ by \topskip
+  \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by 2 % target to split to
+  %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+  \splittopskip = \topskip
+  % Loop until we get a decent breakpoint.
+  {%
+    \vbadness = 10000
+    \loop
+      \global\setbox3 = \copy0
+      \global\setbox1 = \vsplit3 to \dimen@
+    \ifdim\ht3>\dimen@
+      \global\advance\dimen@ by 1pt
+    \repeat
+  }%
+  %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+  \setbox0=\vbox to\dimen@{\unvbox1}%
+  \setbox2=\vbox to\dimen@{\unvbox3}%
+  %
+  \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount\chapno
+\newcount\secno        \secno=0
+\newcount\subsecno     \subsecno=0
+\newcount\subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno  \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it.  @section does likewise.
+\def\thischapter{}
+\def\thissection{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \chapterzzz{#2}
+\or
+  \seczzz{#2}
+\or
+  \numberedsubseczzz{#2}
+\or
+  \numberedsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \chapterzzz{#2}
+  \else
+    \numberedsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \appendixzzz{#2}
+\or
+  \appendixsectionzzz{#2}
+\or
+  \appendixsubseczzz{#2}
+\or
+  \appendixsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \appendixzzz{#2}
+  \else
+    \appendixsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \unnumberedzzz{#2}
+\or
+  \unnumberedseczzz{#2}
+\or
+  \unnumberedsubseczzz{#2}
+\or
+  \unnumberedsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \unnumberedzzz{#2}
+  \else
+    \unnumberedsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% @chapter, @appendix, @unnumbered.
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+                                  {\the\chapno}}}%
+\temp
+\donoderef
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1
+\message{\putwordAppendix\space \appendixletter}%
+\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+                       {\putwordAppendix{} \appendixletter}}}%
+\temp
+\appendixnoderef
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\def\centerchap{\parsearg\centerchapyyy}
+\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}}
+
+% @top is like @unnumbered.
+\outer\def\top{\parsearg\unnumberedyyy}
+
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% This used to be simply \message{#1}, but TeX fully expands the
+% argument to \message.  Therefore, if #1 contained @-commands, TeX
+% expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+% expanded @cite (which turns out to cause errors because \cite is meant
+% to be executed, not expanded).
+%
+% Anyway, we don't want the fully-expanded definition of @cite to appear
+% as a result of the \message, we just want `@cite' itself.  We use
+% \the<toks register> to achieve this: TeX expands \the<toks> only once,
+% simply yielding the contents of <toks register>.  (We also do this for
+% the toc entries.)
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% Sections.
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+                                  {\the\chapno}{\the\secno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+                                  {\appendixletter}{\the\secno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsections.
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+                                    {\the\chapno}{\the\secno}{\the\subsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+                                {\appendixletter}{\the\secno}{\the\subsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{%
+\plainsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry%
+                                    {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsubsections.
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+  {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{%
+\plainsubsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry%
+                                    {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and such:
+%       1) We use \vbox rather than the earlier \line to permit
+%          overlong headings to fold.
+%       2) \hyphenpenalty is set to 10000 because hyphenation in a
+%          heading is obnoxious; this forbids it.
+%       3) Likewise, headings look best if no \parindent is used, and
+%          if justification is not attempted.  Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 200}
+
+% @heading, @subheading, @subsubheading.
+\def\heading{\parsearg\plainsecheading}
+\def\subheading{\parsearg\plainsubsecheading}
+\def\subsubheading{\parsearg\plainsubsubsecheading}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip\chapheadingskip
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain
+\global\let\centerchapmacro=\centerchfplain}
+
+% Plain chapter opening.
+% #1 is the text, #2 the chapter number or empty if unnumbered.
+\def\chfplain#1#2{%
+  \pchapsepmacro
+  {%
+    \chapfonts \rm
+    \def\chapnum{#2}%
+    \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}%
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+          \hangindent = \wd0 \centerparametersmaybe
+          \unhbox0 #1\par}%
+  }%
+  \nobreak\bigskip % no page break after a chapter title
+  \nobreak
+}
+
+% Plain opening for unnumbered.
+\def\unnchfplain#1{\chfplain{#1}{}}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerchfplain#1{{%
+  \def\centerparametersmaybe{%
+    \advance\rightskip by 3\rightskip
+    \leftskip = \rightskip
+    \parfillskip = 0pt
+  }%
+  \chfplain{#1}{}%
+}}
+
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt\raggedright
+                       \rm #1\hfill}}\bigskip \par\nobreak
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\centerchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt
+                       \hfill {\rm #1}\hfill}}\bigskip \par\nobreak
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen
+\global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles.
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}}
+\def\plainsecheading#1{\sectionheading{sec}{}{#1}}
+
+% Subsection titles.
+\newskip \subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}}
+\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}}
+
+% Subsubsection titles.
+\let\subsubsecheadingskip = \subsecheadingskip
+\let\subsubsecheadingbreak = \subsecheadingbreak
+\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}}
+\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}}
+
+
+% Print any size section title.
+%
+% #1 is the section type (sec/subsec/subsubsec), #2 is the section
+% number (maybe empty), #3 the text.
+\def\sectionheading#1#2#3{%
+  {%
+    \expandafter\advance\csname #1headingskip\endcsname by \parskip
+    \csname #1headingbreak\endcsname
+  }%
+  {%
+    % Switch to the right set of fonts.
+    \csname #1fonts\endcsname \rm
+    %
+    % Only insert the separating space if we have a section number.
+    \def\secnum{#2}%
+    \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}%
+    %
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+          \hangindent = \wd0 % zero if no section number
+          \unhbox0 #3}%
+  }%
+  \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak
+}
+
+
+\message{toc,}
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.  We supply {\folio} at the end of the
+% argument, which will end up as the last argument to the \...entry macro.
+%
+% We open the .toc file here instead of at @setfilename or any other
+% given time so that @contents can be put in the document anywhere.
+%
+\newif\iftocfileopened
+\def\writetocentry#1{%
+  \iftocfileopened\else
+    \immediate\openout\tocfile = \jobname.toc
+    \global\tocfileopenedtrue
+  \fi
+  \iflinks \write\tocfile{#1{\folio}}\fi
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Finish up the main text and prepare to read what we've written
+% to \tocfile.
+%
+\def\startcontents#1{%
+   % If @setchapternewpage on, and @headings double, the contents should
+   % start on an odd page, unlike chapters.  Thus, we maintain
+   % \contentsalignmacro in parallel with \pagealignmacro.
+   % From: Torbjorn Granlund <tege@matematik.su.se>
+   \contentsalignmacro
+   \immediate\closeout\tocfile
+   %
+   % Don't need to put `Contents' or `Short Contents' in the headline.
+   % It is abundantly clear what they are.
+   \unnumbchapmacro{#1}\def\thischapter{}%
+   \savepageno = \pageno
+   \begingroup                  % Set up to handle contents files properly.
+      \catcode`\\=0  \catcode`\{=1  \catcode`\}=2  \catcode`\@=11
+      % We can't do this, because then an actual ^ in a section
+      % title fails, e.g., @chapter ^ -- exponentiation.  --karl, 9jul97.
+      %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
+      \raggedbottom             % Worry more about breakpoints than the bottom.
+      \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+      %
+      % Roman numerals for page numbers.
+      \ifnum \pageno>0 \pageno = \lastnegativepageno \fi
+}
+
+
+% Normal (long) toc.
+\def\contents{%
+   \startcontents{\putwordTOC}%
+     \openin 1 \jobname.toc
+     \ifeof 1 \else
+       \closein 1
+       \input \jobname.toc
+     \fi
+     \vfill \eject
+     \contentsalignmacro % in case @setchapternewpage odd is in effect
+   \endgroup
+   \lastnegativepageno = \pageno
+   \pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+   \startcontents{\putwordShortTOC}%
+      %
+      \let\chapentry = \shortchapentry
+      \let\unnumbchapentry = \shortunnumberedentry
+      % We want a true roman here for the page numbers.
+      \secfonts
+      \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+      \rm
+      \hyphenpenalty = 10000
+      \advance\baselineskip by 1pt % Open it up a little.
+      \def\secentry ##1##2##3##4{}
+      \def\unnumbsecentry ##1##2{}
+      \def\subsecentry ##1##2##3##4##5{}
+      \def\unnumbsubsecentry ##1##2{}
+      \def\subsubsecentry ##1##2##3##4##5##6{}
+      \def\unnumbsubsubsecentry ##1##2{}
+      \openin 1 \jobname.toc
+      \ifeof 1 \else
+        \closein 1
+        \input \jobname.toc
+      \fi
+     \vfill \eject
+     \contentsalignmacro % in case @setchapternewpage odd is in effect
+   \endgroup
+   \lastnegativepageno = \pageno
+   \pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm \putwordAppendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+  % We typeset #1 in a box of constant width, regardless of the text of
+  % #1, so the chapter titles will come out aligned.
+  \setbox0 = \hbox{#1}%
+  \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+  %
+  % This space should be plenty, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in by \shortchapentry above.)
+  \advance\dimen0 by 1.1em
+  \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+  \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+   \begingroup
+     \chapentryfonts
+     \tocentry{#1}{\dopageno{#2}}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here.  (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+\def\tocentry#1#2{\begingroup
+  \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks
+  % Do not use \turnoffactive in these arguments.  Since the toc is
+  % typeset in cmr, so characters such as _ would come out wrong; we
+  % have to do the usual translation tricks.
+  \entry{#1}{#2}%
+\endgroup}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox    \newbox\longdblarrowbox
+\newbox\pushcharbox    \newbox\bullbox
+\newbox\equivbox       \newbox\errorbox
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+%                                      depth .1ex\hfil}
+%}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+\def\point{$\star$}
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+  \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+  \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+  \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+  \catcode `\%=14
+  \catcode 43=12 % plus
+  \catcode`\"=12
+  \catcode`\==12
+  \catcode`\|=12
+  \catcode`\<=12
+  \catcode`\>=12
+  \escapechar=`\\
+  %
+  \let\b=\ptexb
+  \let\bullet=\ptexbullet
+  \let\c=\ptexc
+  \let\,=\ptexcomma
+  \let\.=\ptexdot
+  \let\dots=\ptexdots
+  \let\equiv=\ptexequiv
+  \let\!=\ptexexclam
+  \let\i=\ptexi
+  \let\{=\ptexlbrace
+  \let\+=\tabalign
+  \let\}=\ptexrbrace
+  \let\*=\ptexstar
+  \let\t=\ptext
+  %
+  \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+  \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+  \def\@{@}%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% Make each space character in the input produce a normal interword
+% space in the output.  Don't allow a line break at this space, as this
+% is used only in environments like @example, where each line of input
+% should produce a line of output anyway.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is.  This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip
+%
+\def\aboveenvbreak{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+        \ctl\leaders\hrule height\circthick\hfil\ctr
+        \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+        \cbl\leaders\hrule height\circthick\hfil\cbr
+        \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+        \lskip=\leftskip \rskip=\rightskip
+        \leftskip=0pt\rightskip=0pt %we want these *outside*.
+        \cartinner=\hsize \advance\cartinner by-\lskip
+                          \advance\cartinner by-\rskip
+        \cartouter=\hsize
+        \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+%                                    side, and for 6pt waste from
+%                                    each corner char, and rule thickness
+        \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+        % Flag to tell @lisp, etc., not to narrow margin.
+        \let\nonarrowing=\comment
+        \vbox\bgroup
+                \baselineskip=0pt\parskip=0pt\lineskip=0pt
+                \carttop
+                \hbox\bgroup
+                        \hskip\lskip
+                        \vrule\kern3pt
+                        \vbox\bgroup
+                                \hsize=\cartinner
+                                \kern3pt
+                                \begingroup
+                                        \baselineskip=\normbskip
+                                        \lineskip=\normlskip
+                                        \parskip=\normpskip
+                                        \vskip -\parskip
+\def\Ecartouche{%
+                                \endgroup
+                                \kern3pt
+                        \egroup
+                        \kern3pt\vrule
+                        \hskip\rskip
+                \egroup
+                \cartbot
+        \egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+  \aboveenvbreak
+  \inENV % This group ends at the end of the body
+  \hfuzz = 12pt % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \singlespace
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  \parindent = 0pt
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  % @cartouche defines \nonarrowing to inhibit narrowing
+  % at next level down.
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+    \let\exdent=\nofillexdent
+    \let\nonarrowing=\relax
+  \fi
+}
+
+% Define the \E... control sequence only if we are inside the particular
+% environment, so the error checking in \end will work.
+%
+% To end an @example-like environment, we first end the paragraph (via
+% \afterenvbreak's vertical glue), and then the group.  That way we keep
+% the zero \parskip that the environments set -- \parskip glue will be
+% inserted at the beginning of the next paragraph in the document, after
+% the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}
+
+% @lisp: indented, narrowed, typewriter font.
+\def\lisp{\begingroup
+  \nonfillstart
+  \let\Elisp = \nonfillfinish
+  \tt
+  \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+  \gobble       % eat return
+}
+
+% @example: Same as @lisp.
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+
+% @small... is usually equivalent to the non-small (@smallbook
+% redefines).  We must call \example (or whatever) last in the
+% definition, since it reads the return following the @example (or
+% whatever) command.
+%
+% This actually allows (for example) @end display inside an
+% @smalldisplay.  Too bad, but makeinfo will catch the error anyway.
+%
+\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display}
+\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format}
+\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts.
+% Originally contributed by Pavel@xerox.
+\def\smalllispx{\begingroup
+  \def\Esmalllisp{\nonfillfinish\endgroup}%
+  \def\Esmallexample{\nonfillfinish\endgroup}%
+  \indexfonts
+  \lisp
+}
+
+% @display: same as @lisp except keep current font.
+%
+\def\display{\begingroup
+  \nonfillstart
+  \let\Edisplay = \nonfillfinish
+  \gobble
+}
+
+% @smalldisplay (when @smallbook): @display plus smaller fonts.
+%
+\def\smalldisplayx{\begingroup
+  \def\Esmalldisplay{\nonfillfinish\endgroup}%
+  \indexfonts \rm
+  \display
+}
+
+% @format: same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eformat = \nonfillfinish
+  \gobble
+}
+
+% @smallformat (when @smallbook): @format plus smaller fonts.
+%
+\def\smallformatx{\begingroup
+  \def\Esmallformat{\nonfillfinish\endgroup}%
+  \indexfonts \rm
+  \format
+}
+
+% @flushleft (same as @format).
+%
+\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format}
+
+% @flushright.
+%
+\def\flushright{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eflushright = \nonfillfinish
+  \advance\leftskip by 0pt plus 1fill
+  \gobble
+}
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.
+%
+\def\quotation{%
+  \begingroup\inENV %This group ends at the end of the @quotation body
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \singlespace
+  \parindent=0pt
+  % We have retained a nonzero parskip for the environment, since we're
+  % doing normal filling. So to avoid extra space below the environment...
+  \def\Equotation{\parskip = 0pt \nonfillfinish}%
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \advance\rightskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+    \let\nonarrowing = \relax
+  \fi
+}
+
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+% This is used to turn on special parens
+% but make & act ordinary (given that it's active).
+\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested
+  \global\advance\parencount by 1
+}
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+  % also in that case restore the outer-level definition of (.
+  \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+  \global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text.  This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 }
+\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 }
+\def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}}
+\def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\noindent
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2
+\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip        % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+%    such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+%
+\def\defmethparsebody#1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+% @deftypemethod has an extra argument that nothing else does.  Sigh.
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+% #5 is the method's return type.
+%
+\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody.  It could probably be used for
+% some of the others, too, with some judicious conditionals.
+%
+\def\parsebodycommon#1#2#3{%
+  \begingroup\inENV %
+  \medbreak %
+  % Define the end token that this defining construct specifies
+  % so that it will exit this group.
+  \def#1{\endgraf\endgroup\medbreak}%
+  \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+  \parindent=0in
+  \advance\leftskip by \defbodyindent
+  \exdentamount=\defbodyindent
+  \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+  \parsebodycommon{#1}{#2}{#3}%
+  \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument.  Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name.  That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+  \parsebodycommon{#1}{#2}{#3}%
+  \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any).  That's what this does.
+%
+\def\removeemptybraces\empty#1\relax{#1}
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+%
+\def\parsetpheaderline#1#2#3{%
+  #1{\removeemptybraces#2\relax}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+%  the first is all of #2 before the space token,
+%  the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+% Use \boldbraxnoamp, not \functionparens, so that & is not special.
+\boldbraxnoamp
+\tclose{#1}% avoid \code because of side effects on active chars
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDeffunc}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type.  #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% \defheaderxcond#1\relax$$$
+% puts #1 in @code, followed by a space, but does nothing if #1 is null.
+\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
+
+% #1 is the classification.  #2 is the data type.  #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+%               at least some C++ text from working
+\defname {\defheaderxcond#2\relax$$$#3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDefmac}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDefspec}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}}
+\def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop CATEGORY CLASS OPERATION ARG...
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{}\putwordon\ #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @deftypemethod CLASS RETURN-TYPE METHOD ARG...
+%
+\def\deftypemethod{%
+  \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader}
+%
+% #1 is the class name, #2 the data type, #3 the method name, #4 the args.
+\def\deftypemethodheader#1#2#3#4{%
+  \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index
+  \begingroup
+    \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}%
+    \deftypefunargs{#4}%
+  \endgroup
+}
+
+% @defmethod == @defop Method
+%
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+%
+% #1 is the class name, #2 the method name, #3 the args.
+\def\defmethodheader#1#2#3{%
+  \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index
+  \begingroup
+    \defname{#2}{\putwordMethodon\ \code{#1}}%
+    \defunargs{#3}%
+  \endgroup
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index
+\begingroup\defname {#2}{\putwordDefivar\ \putwordof\ #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{\putwordDefvar}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{\putwordDefopt}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type.  #2 is the name, perhaps followed by text that
+% is actually part of the data type, which should not be put into the index.
+\def\deftypevarheader #1#2{%
+\dovarind#2 \relax% Make entry in variables index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\dovarind#3 \relax%
+\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\undefined
+ \newwrite\macscribble
+ \def\scanmacro#1{%
+   \begingroup \newlinechar`\^^M
+   % Undo catcode changes of \startcontents and \doprintindex
+   \catcode`\@=0 \catcode`\\=12 \escapechar=`\@
+   % Append \endinput to make sure that TeX does not see the ending newline.
+   \toks0={#1\endinput}%
+   \immediate\openout\macscribble=\jobname.tmp
+   \immediate\write\macscribble{\the\toks0}%
+   \immediate\closeout\macscribble
+   \let\xeatspaces\eatspaces
+   \input \jobname.tmp
+   \endgroup
+}
+\else
+\def\scanmacro#1{%
+\begingroup \newlinechar`\^^M
+% Undo catcode changes of \startcontents and \doprintindex
+\catcode`\@=0 \catcode`\\=12 \escapechar=`\@
+\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup}
+\fi
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+\def\macrolist{}    % List of all defined macros in the form
+                    % \do\macro1\do\macro2...
+
+% Utility routines.
+% Thisdoes \let #1 = #2, except with \csnames.
+\def\cslet#1#2{%
+\expandafter\expandafter
+\expandafter\let
+\expandafter\expandafter
+\csname#1\endcsname
+\csname#2\endcsname}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=12\catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \.
+
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by  making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+
+\def\macrobodyctxt{%
+  \catcode`\~=12
+  \catcode`\^=12
+  \catcode`\_=12
+  \catcode`\|=12
+  \catcode`\<=12
+  \catcode`\>=12
+  \catcode`\+=12
+  \catcode`\{=12
+  \catcode`\}=12
+  \catcode`\@=12
+  \catcode`\^^M=12
+  \usembodybackslash}
+
+\def\macroargctxt{%
+  \catcode`\~=12
+  \catcode`\^=12
+  \catcode`\_=12
+  \catcode`\|=12
+  \catcode`\<=12
+  \catcode`\>=12
+  \catcode`\+=12
+  \catcode`\@=12
+  \catcode`\\=12}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+  \getargs{#1}%           now \macname is the macname and \argl the arglist
+  \ifx\argl\empty       % no arguments
+     \paramno=0%
+  \else
+     \expandafter\parsemargdef \argl;%
+  \fi
+  \if1\csname ismacro.\the\macname\endcsname
+     \message{Warning: redefining \the\macname}%
+  \else
+     \expandafter\ifx\csname \the\macname\endcsname \relax
+     \else \errmessage{The name \the\macname\space is reserved}\fi
+     \global\cslet{macsave.\the\macname}{\the\macname}%
+     \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+     % Add the macroname to \macrolist
+     \toks0 = \expandafter{\macrolist\do}%
+     \xdef\macrolist{\the\toks0
+       \expandafter\noexpand\csname\the\macname\endcsname}%
+  \fi
+  \begingroup \macrobodyctxt
+  \ifrecursive \expandafter\parsermacbody
+  \else \expandafter\parsemacbody
+  \fi}
+
+\def\unmacro{\parsearg\unmacroxxx}
+\def\unmacroxxx#1{%
+  \if1\csname ismacro.#1\endcsname
+    \global\cslet{#1}{macsave.#1}%
+    \global\expandafter\let \csname ismacro.#1\endcsname=0%
+    % Remove the macro name from \macrolist
+    \begingroup
+      \edef\tempa{\expandafter\noexpand\csname#1\endcsname}%
+      \def\do##1{%
+        \def\tempb{##1}%
+        \ifx\tempa\tempb
+          % remove this
+        \else
+          \toks0 = \expandafter{\newmacrolist\do}%
+          \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}%
+        \fi}%
+      \def\newmacrolist{}%
+      % Execute macro list to define \newmacrolist
+      \macrolist
+      \global\let\macrolist\newmacrolist
+    \endgroup
+  \else
+    \errmessage{Macro #1 not defined}%
+  \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname #1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% Parse the optional {params} list.  Set up \paramno and \paramlist
+% so \defmacro knows what to do.  Define \macarg.blah for each blah
+% in the params list, to be ##N where N is the position in that list.
+% That gets used by \mbodybackslash (above).
+
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX:  let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+
+\def\parsemargdef#1;{\paramno=0\def\paramlist{}%
+        \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,}
+\def\parsemargdefxxx#1,{%
+  \if#1;\let\next=\relax
+  \else \let\next=\parsemargdefxxx
+    \advance\paramno by 1%
+    \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+        {\xeatspaces{\hash\the\paramno}}%
+    \edef\paramlist{\paramlist\hash\the\paramno,}%
+  \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+
+% This defines the macro itself. There are six cases: recursive and
+% nonrecursive macros of zero, one, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+\def\defmacro{%
+  \let\hash=##% convert placeholders to macro parameter chars
+  \ifrecursive
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\scanmacro{\temp}}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline
+         \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+         \egroup\noexpand\scanmacro{\temp}}%
+    \else % many
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\csname\the\macname xx\endcsname}%
+      \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+        \csname\the\macname xxx\endcsname
+          \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+    \fi
+  \else
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline
+         \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+        \egroup
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \else % many
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \expandafter\noexpand\csname\the\macname xx\endcsname}%
+      \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+      \csname\the\macname xxx\endcsname
+      \paramlist{%
+          \egroup
+          \noexpand\norecurse{\the\macname}%
+          \noexpand\scanmacro{\temp}\egroup}%
+    \fi
+  \fi}
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {.  If so it reads up to the closing }, if not, it reads the whole
+% line.  Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg)
+\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup\else
+    \expandafter\parsearg
+  \fi \next}
+
+% We mant to disable all macros during \shipout so that they are not
+% expanded by \write.
+\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}%
+  \edef\next{\macrolist}\expandafter\endgroup\next}
+
+
+% @alias.
+\def\alias#1=#2{\gdef#1{#2}}
+
+
+\message{cross references,}
+\newwrite\auxfile
+
+\newif\ifhavexrefs    % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+% @node's job is to define \lastnode.
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+% The sectioning commands (@chapter, etc.) call these.
+\def\donoderef{%
+  \ifx\lastnode\relax\else
+    \expandafter\expandafter\expandafter\setref{\lastnode}%
+      {Ysectionnumberandtype}%
+    \global\let\lastnode=\relax
+  \fi
+}
+\def\unnumbnoderef{%
+  \ifx\lastnode\relax\else
+    \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}%
+    \global\let\lastnode=\relax
+  \fi
+}
+\def\appendixnoderef{%
+  \ifx\lastnode\relax\else
+    \expandafter\expandafter\expandafter\setref{\lastnode}%
+      {Yappendixletterandtype}%
+    \global\let\lastnode=\relax
+  \fi
+}
+
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\def\anchor#1{\setref{#1}{Ynothing}}
+
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME, namely
+% NAME-title, NAME-pg, and NAME-SNT.  Called from \foonoderef.  We have
+% to set \indexdummies so commands such as @code in a section title
+% aren't expanded.  It would be nicer not to expand the titles in the
+% first place, but there's so many layers that that is hard to do.
+%
+\def\setref#1#2{{%
+  \indexdummies
+  \dosetq{#1-title}{Ytitle}%
+  \dosetq{#1-pg}{Ypagenumber}%
+  \dosetq{#1-snt}{#2}%
+}}
+
+% @xref, @pxref, and @ref generate cross-references.  For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual.  All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \def\printedmanual{\ignorespaces #5}%
+  \def\printednodename{\ignorespaces #3}%
+  \setbox1=\hbox{\printedmanual}%
+  \setbox0=\hbox{\printednodename}%
+  \ifdim \wd0 = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax
+      % Use the node name inside the square brackets.
+      \def\printednodename{\ignorespaces #1}%
+    \else
+      % Use the actual chapter/section title appear inside
+      % the square brackets.  Use the real section title if we have it.
+      \ifdim \wd1 > 0pt
+        % It is in another manual, so we don't have it.
+        \def\printednodename{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We know the real title if we have the xref values.
+          \def\printednodename{\refx{#1-title}{}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printednodename{\ignorespaces #1}%
+        \fi%
+      \fi
+    \fi
+  \fi
+  %
+  % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+  % insert empty discretionaries after hyphens, which means that it will
+  % not find a line break at a hyphen in a node names.  Since some manuals
+  % are best written with fairly long node names, containing hyphens, this
+  % is a loss.  Therefore, we give the text of the node name again, so it
+  % is as if TeX is seeing it for the first time.
+  \ifdim \wd1 > 0pt
+    \putwordsection{} ``\printednodename'' in \cite{\printedmanual}%
+  \else
+    % _ (for example) has to be the character _ for the purposes of the
+    % control sequence corresponding to the node, but it has to expand
+    % into the usual \leavevmode...\vrule stuff for purposes of
+    % printing. So we \turnoffactive for the \refx-snt, back on for the
+    % printing, back off for the \refx-pg.
+    {\normalturnoffactive
+     % Only output a following space if the -snt ref is nonempty; for
+     % @unnumbered and @anchor, it won't be.
+     \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+     \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+    }%
+    % [mynode],
+    [\printednodename],\space
+    % page 3
+    \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+  \fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \normalturnoffactive so that punctuation chars such as underscore
+% and backslash work in node names.  (\turnoffactive doesn't do \.)
+\def\dosetq#1#2{%
+  {\let\folio=0
+   \normalturnoffactive
+   \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}%
+   \iflinks
+     \next
+   \fi
+  }%
+}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Non-3.0.
+\else
+  \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+  \expandafter\ifx\csname X#1\endcsname\relax
+    % If not defined, say something at least.
+    \angleleft un\-de\-fined\angleright
+    \iflinks
+      \ifhavexrefs
+        \message{\linenumber Undefined cross reference `#1'.}%
+      \else
+        \ifwarnedxrefs\else
+          \global\warnedxrefstrue
+          \message{Cross reference values unknown; you must run TeX again.}%
+        \fi
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \csname X#1\endcsname
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.
+%
+\def\xrdef#1{\begingroup
+  % Reenable \ as an escape while reading the second argument.
+  \catcode`\\ = 0
+  \afterassignment\endgroup
+  \expandafter\gdef\csname X#1\endcsname
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+\def\readauxfile{\begingroup
+  \catcode`\^^@=\other
+  \catcode`\^^A=\other
+  \catcode`\^^B=\other
+  \catcode`\^^C=\other
+  \catcode`\^^D=\other
+  \catcode`\^^E=\other
+  \catcode`\^^F=\other
+  \catcode`\^^G=\other
+  \catcode`\^^H=\other
+  \catcode`\^^K=\other
+  \catcode`\^^L=\other
+  \catcode`\^^N=\other
+  \catcode`\^^P=\other
+  \catcode`\^^Q=\other
+  \catcode`\^^R=\other
+  \catcode`\^^S=\other
+  \catcode`\^^T=\other
+  \catcode`\^^U=\other
+  \catcode`\^^V=\other
+  \catcode`\^^W=\other
+  \catcode`\^^X=\other
+  \catcode`\^^Z=\other
+  \catcode`\^^[=\other
+  \catcode`\^^\=\other
+  \catcode`\^^]=\other
+  \catcode`\^^^=\other
+  \catcode`\^^_=\other
+  \catcode`\@=\other
+  \catcode`\^=\other
+  % It was suggested to define this as 7, which would allow ^^e4 etc.
+  % in xref tags, i.e., node names.  But since ^^e4 notation isn't
+  % supported in the main text, it doesn't seem desirable.  Furthermore,
+  % that is not enough: for node names that actually contain a ^
+  % character, we would end up writing a line like this: 'xrdef {'hat
+  % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+  % argument, and \hat is not an expandable control sequence.  It could
+  % all be worked out, but why?  Either we support ^^ or we don't.
+  %
+  % The other change necessary for this was to define \auxhat:
+  % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+  % and then to call \auxhat in \setq.
+  %
+  \catcode`\~=\other
+  \catcode`\[=\other
+  \catcode`\]=\other
+  \catcode`\"=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\$=\other
+  \catcode`\#=\other
+  \catcode`\&=\other
+  \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+  % Make the characters 128-255 be printing characters
+  {%
+    \count 1=128
+    \def\loop{%
+      \catcode\count 1=\other
+      \advance\count 1 by 1
+      \ifnum \count 1<256 \loop \fi
+    }%
+  }%
+  % The aux file uses ' as the escape (for now).
+  % Turn off \ as an escape so we do not lose on
+  % entries which were dumped with control sequences in their names.
+  % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+  % Reference to such entries still does not work the way one would wish,
+  % but at least they do not bomb out when the aux file is read in.
+  \catcode`\{=1
+  \catcode`\}=2
+  \catcode`\%=\other
+  \catcode`\'=0
+  \catcode`\\=\other
+  %
+  \openin 1 \jobname.aux
+  \ifeof 1 \else
+    \closein 1
+    \input \jobname.aux
+    \global\havexrefstrue
+    \global\warnedobstrue
+  \fi
+  % Open the new aux file.  TeX will close it automatically at exit.
+  \openout\auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only.
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \footnotezzz
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset and anything else that uses
+% \parseargline fail inside footnotes because the tokens are fixed when
+% the footnote is read.  --karl, 16nov96.
+%
+\long\gdef\footnotezzz{\insert\footins\bgroup
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  % Hang the footnote text off the number.
+  \hang
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  \futurelet\next\fo@t
+}
+\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t
+  \else\let\next\f@t\fi \next}
+\def\f@@t{\bgroup\aftergroup\@foot\let\next}
+\def\f@t#1{#1\@foot}
+\def\@foot{\strut\egroup}
+
+}%end \catcode `\@=11
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+  \normalbaselineskip = #1\relax
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% @| inserts a changebar to the left of the current line.  It should
+% surround any changed text.  This approach does *not* work if the
+% change spans more than two lines of output.  To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+  % \vadjust can only be used in horizontal mode.
+  \leavevmode
+  %
+  % Append this vertical mode material after the current line in the output.
+  \vadjust{%
+    % We want to insert a rule with the height and depth of the current
+    % leading; that is exactly what \strutbox is supposed to record.
+    \vskip-\baselineskip
+    %
+    % \vadjust-items are inserted at the left edge of the type.  So
+    % the \llap here moves out into the left-hand margin.
+    \llap{%
+      %
+      % For a thicker or thinner bar, change the `1pt'.
+      \vrule height\baselineskip width1pt
+      %
+      % This is the space between the bar and the text.
+      \hskip 12pt
+    }%
+  }%
+}
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+% @image.  We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front.  If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+  \closein 1
+  % Do not bother showing banner with post-v2.7 epsf.tex (available in
+  % doc/epsf.tex until it shows up on ctan).
+  \def\epsfannounce{\toks0 = }%
+  \input epsf.tex
+\fi
+%
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+  work.  It is also included in the Texinfo distribution, or you can get
+  it from ftp://tug.org/tex/epsf.tex.}
+%
+% Only complain once about lack of epsf.tex.
+\def\image#1{%
+  \ifx\pdfoutput\undefined
+    \ifx\epsfbox\undefined
+      \ifwarnednoepsf \else
+        \errhelp = \noepsfhelp
+        \errmessage{epsf.tex not found, images will be ignored}%
+        \global\warnednoepsftrue
+      \fi
+    \else
+      \imagexxx #1,,,\finish
+    \fi
+  \else
+    \centerline{\pdfimage #1.pdf}%
+  \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is just the usual extra ignored arg for parsing this stuff.
+\def\imagexxx#1,#2,#3,#4\finish{%
+  % \epsfbox itself resets \epsf?size at each figure.
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+  \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+  % If the image is by itself, center it.
+  \ifvmode
+    \nobreak\medskip
+    \nobreak
+    \centerline{\epsfbox{#1.eps}}%
+    \bigbreak
+  \else
+    % In the middle of a paragraph, no extra space.
+    \epsfbox{#1.eps}%
+  \fi
+}
+
+
+\message{localization,}
+
+% @documentlanguage is usually given very early, just after
+% @setfilename.  If done too late, it may not override everything
+% properly.  Single argument is the language abbreviation.
+% It would be nice if we could set up a hyphenation file here.
+%
+\def\documentlanguage{\parsearg\dodocumentlanguage}
+\def\dodocumentlanguage#1{%
+  \tex % read txi-??.tex file in plain TeX.
+  % Read the file if it exists.
+  \openin 1 txi-#1.tex
+  \ifeof1
+    \errhelp = \nolanghelp
+    \errmessage{Cannot read language file txi-#1.tex}%
+    \let\temp = \relax
+  \else
+    \def\temp{\input txi-#1.tex }%
+  \fi
+  \temp
+  \endgroup
+}
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty.  Maybe you need to install it?  In the current directory
+should work if nowhere else does.}
+
+
+% @documentencoding should change something in TeX eventually, most
+% likely, but for now just recognize it.
+\let\documentencoding = \comment
+
+
+% Page size parameters.
+%
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be so finicky about underfull hboxes, either.
+\hbadness = 2000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+  \ifx\emergencystretch\thisisundefined
+    % Allow us to assign to \emergencystretch anyway.
+    \def\emergencystretch{\dimen0}%
+  \else
+    \emergencystretch = \hsize
+    \divide\emergencystretch by 40
+  \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth; 3) voffset;
+% 4) hoffset; 5) binding offset; 6) topskip.  Then whoever calls us can
+% set \parskip and call \setleading for \baselineskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6{%
+  \voffset = #3\relax
+  \topskip = #6\relax
+  \splittopskip = \topskip
+  %
+  \vsize = #1\relax
+  \advance\vsize by \topskip
+  \outervsize = \vsize
+  \advance\outervsize by 2\topandbottommargin
+  \pageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \pagewidth = \hsize
+  %
+  \normaloffset = #4\relax
+  \bindingoffset = #5\relax
+  %
+  \parindent = \defaultparindent
+  \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{13.2pt}%
+  %
+  % If page is nothing but text, make it come out even.
+  \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.5 (or so) format.
+\def\smallbook{{\globaldefs = 1
+  \parskip = 2pt plus 1pt
+  \setleading{12pt}%
+  %
+  \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}%
+  %
+  \lispnarrowing = 0.3in
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \deftypemargin = 0pt
+  \defbodyindent = .5cm
+  %
+  \let\smalldisplay = \smalldisplayx
+  \let\smallexample = \smalllispx
+  \let\smallformat = \smallformatx
+  \let\smalllisp = \smalllispx
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+  \setleading{12pt}%
+  \parskip = 3pt plus 2pt minus 1pt
+  %
+  \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}%
+  %
+  \tolerance = 700
+  \hfuzz = 1pt
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.  Top margin
+% 29mm, hence bottom margin 28mm, nominal side margin 3cm.
+\def\afourlatex{{\globaldefs = 1
+  \setleading{13.6pt}%
+  %
+  \afourpaper
+  \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}%
+  %
+  \globaldefs = 0
+}}
+
+% Use @afourwide to print on European A4 paper in wide format.
+\def\afourwide{%
+  \afourpaper
+  \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}%
+  %
+  \globaldefs = 0
+}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\def\pagesizes{\parsearg\pagesizesxxx}
+\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+  \globaldefs = 1
+  %
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{13.2pt}%
+  %
+  \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+\message{and turning on texinfo input format.}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`+=\active
+\catcode`\_=\active
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0   % Define control-q
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{@let"=@normaldoublequote
+@let\=@realbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+@def@normalturnoffactive{@let"=@normaldoublequote
+@let\=@normalbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also back turn on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi
+  @catcode`+=@active @catcode`@_=@active}
+
+% These look ok in all fonts, so just make them not special.  The @rm below
+% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%H"
+@c time-stamp-end: "}"
+@c End:
diff --git a/doc/vtysh.1 b/doc/vtysh.1
new file mode 100644 (file)
index 0000000..302e016
--- /dev/null
@@ -0,0 +1,68 @@
+.TH VTYSH 1 "July 2000" "Zebra Beast - VTY shell" "Version 0.88"
+
+.SH NAME
+vtysh \- a integrated shell for Zebra routing software
+
+.SH SYNOPSIS
+.B vtysh
+[
+.B \-e command
+]
+
+.SH DESCBGPTION
+.B vtysh
+is a integrated shell for
+.B Zebra
+routing engine.
+
+
+.SH OPTIONS
+
+.TP
+\fB\-e
+Specify command to be executed under batch mode.
+
+
+.SH COMMANDS
+
+\fB Almost Zebra commands.
+
+\fB ping
+\fB traceroute
+\fB telnnet
+
+\fB start-shell
+\fB start-shell bash
+\fB start-shell zsh
+
+
+.SH FILES
+
+.TP
+.BI /usr/local/etc/Zebra.conf
+The default location of the 
+.B vtysh
+config file.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line
+options, and for config file commands. The definitive document is the
+Info file \fBZebra\fR.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+bgpd(8), ripd(8), ripngd(8), ospfd(8), ospf6d(8), zebra(8)
+
+
+.SH BUGS
+.B vtysh
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/vtysh.texi b/doc/vtysh.texi
new file mode 100644 (file)
index 0000000..72490db
--- /dev/null
@@ -0,0 +1,27 @@
+@node VTY shell
+@comment  node-name,  next,  previous,  up
+@chapter VTY shell
+
+@command{vtysh} is integrated shell of Zebra software.
+
+To use vtysh please specify ---enable-vtysh to configure script.  To use
+PAM for authentication use ---with-libpam option to configure script.
+
+vtysh only searches @value{INSTALL_PREFIX_ETC} path for vtysh.conf which
+is the vtysh configuration file.  Vtysh does not search current
+directory for configuration file because the file includes user
+authentication settings.
+
+Currently, vtysh.conf has only one command.
+
+@example
+!
+username foo nopassword
+!
+@end example
+
+With this set, user foo does not need password authentication for user vtysh.
+With PAM vtysh uses PAM authentication mechanism.
+
+If vtysh is compiled without PAM authentication, every user can use vtysh
+without authentication.
diff --git a/doc/zebra.8 b/doc/zebra.8
new file mode 100644 (file)
index 0000000..190f4a6
--- /dev/null
@@ -0,0 +1,146 @@
+.TH ZEBRA 8 "July 2000" "Zebra" "Version 0.88"
+
+.SH NAME
+zebra \- a routing manager for use with associated components
+
+.SH SYNOPSIS
+.B zebra
+[
+.B \-bdhklrv
+]
+[
+.B \-f config-file
+]
+[
+.B \-i pid-file
+]
+[
+.B \-P port-number
+]
+
+.SH DESCRIPTION
+.B zebra 
+is a routing manager that implements the 
+.B zebra
+route engine.
+.B zebra 
+supports RIPv1, RIPv2, RIPng, OSPF, OSPF6, BGP4+, and BGP4-.
+
+
+.SH OPTIONS
+
+.TP
+\fB\-b\fR, \fB\-\-batch\fR
+Runs in batch mode, \fBzebra\fR parses its config and exits.
+
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
+Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/zebra.conf\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When zebra starts its process idenifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart zebra.  The likely default is \fB\fI/var/run/zebra.pid\fR.
+
+.TP
+\fB\-k\fR, \fB\-\-keep_kernel\fR
+On startup, don't delete self inserted routes.
+
+.TP
+\fB\-l\fR, \fB\-\-log_mode\fR
+Turn verbose logging on.
+
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the zebra VTY will listen on. This defaults to
+2602, as specified in \fB\fI/etc/services\fR.
+
+.TP
+\fB\-r\fR, \fB\-\-retain\fR 
+When the program terminates, retain routes added by \fBzebra\fR.
+
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+
+
+.SH COMMANDS
+
+\fB table [TABLENO] \fR -- for use with multi-table kernels 
+
+\fB ip route [NETWORK] [GATEWAY] \fR
+\fB ipv6 route [NETWORK] [GATEWAY] \fR
+
+\fB show ip route \fR
+\fB show ipv6 route \fR
+\fB show interface \fR
+\fB show ipforward \fR
+\fB show ipv6forward \fR
+
+.TP
+\fB interface [IFNAME] \fR
+\fB shutdown \fR
+\fB no shutdown \fR
+\fB ip address [IP-ADDRESS] \fR
+\fB description [DESCRIPTION] \fR
+\fB multicast \fR
+\fB no multicast \fR
+
+
+.SH FILES
+
+.TP
+.BI /usr/local/sbin/zebra
+The default location of the 
+.B zebra
+binary.
+
+.TP
+.BI /usr/local/etc/zebra.conf
+The default location of the 
+.B zebra
+config file.
+
+.TP
+.BI $(PWD)/zebra.log 
+If the 
+.B zebra
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBzebra\fR.
+
+
+.SH WARNING
+This man page is intended as a quick reference for command line options, and for config file commands. The definitive document is the Info file \fBzebra\fR.
+
+
+.SH DIAGNOSTICS
+The zebra process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. 
+.B zebra
+supports many debugging options, see the Info file, or the source for details.
+
+
+.SH "SEE ALSO"
+References to other related man pages:
+
+ripngd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1)
+
+
+
+.SH BUGS
+.B zebra
+eats bugs for breakfast. If you have food for the maintainers try 
+.BI <bug-zebra@gnu.org>
+
+
+.SH AUTHOR[S]
+See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors.
+
diff --git a/doc/zebra.info b/doc/zebra.info
new file mode 100644 (file)
index 0000000..ca805e1
--- /dev/null
@@ -0,0 +1,170 @@
+This is zebra.info, produced by makeinfo version 4.2 from zebra.texi.
+
+INFO-DIR-SECTION Routing Software:
+START-INFO-DIR-ENTRY
+* Zebra: (zebra).              The GNU Zebra routing software
+END-INFO-DIR-ENTRY
+
+   This file documents the GNU Zebra software which manages common
+TCP/IP routing protocols.
+
+   This is Edition 0.1, last updated 12 September 2002 of `The GNU
+Zebra Manual', for Zebra Version 0.93b.
+
+   Copyright (C) 1999, 2000, 2001, 2002 Kunihiro Ishiguro
+
+   Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+   Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+   Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by Kunihiro Ishiguro.
+
+\1f
+Indirect:
+zebra.info-1: 1121
+zebra.info-2: 48818
+zebra.info-3: 95581
+zebra.info-4: 143934
+\1f
+Tag Table:
+(Indirect)
+Node: Top\7f1121
+Node: Overview\7f1646
+Node: About Zebra\7f3063
+Node: System Architecture\7f5332
+Node: Supported Platforms\7f8330
+Node: Supported RFC\7f9317
+Node: How to get Zebra\7f11119
+Node: Mailing List\7f11824
+Node: Bug Reports\7f12491
+Node: Installation\7f13336
+Node: Configure the Software\7f13767
+Ref: Configure the Software-Footnote-1\7f16134
+Node: Build the Software\7f17776
+Node: Install the Software\7f18318
+Node: Basic commands\7f19689
+Node: Config Commands\7f20402
+Node: Basic Config Commands\7f21284
+Node: Sample Config File\7f23682
+Node: Common Invocation Options\7f24442
+Node: Virtual Terminal Interfaces\7f25564
+Node: VTY Overview\7f26069
+Node: VTY Modes\7f27353
+Node: VTY View Mode\7f27793
+Node: VTY Enable Mode\7f28047
+Node: VTY Other Modes\7f28311
+Node: VTY CLI Commands\7f28473
+Node: CLI Movement Commands\7f28923
+Node: CLI Editing Commands\7f29456
+Node: CLI Advanced Commands\7f30029
+Node: Zebra\7f30780
+Node: Invoking zebra\7f31287
+Node: Interface Commands\7f31873
+Node: Static Route Commands\7f32703
+Node: zebra Terminal Mode Commands\7f34790
+Node: RIP\7f35751
+Node: Starting and Stopping ripd\7f36686
+Node: RIP netmask\7f38107
+Node: RIP Configuration\7f39229
+Node: How to Announce RIP route\7f43124
+Node: Filtering RIP Routes\7f45653
+Node: RIP Metric Manipulation\7f47112
+Node: RIP distance\7f48015
+Node: RIP route-map\7f48818
+Node: RIP Authentication\7f51320
+Node: RIP Timers\7f52410
+Node: Show RIP Information\7f53685
+Node: RIP Debug Commands\7f55048
+Node: RIPng\7f56032
+Node: Invoking ripngd\7f56350
+Node: ripngd Configuration\7f56607
+Node: ripngd Terminal Mode Commands\7f57346
+Node: ripngd Filtering Commands\7f57696
+Node: OSPFv2\7f58195
+Node: Configuring ospfd\7f58752
+Node: OSPF router\7f59229
+Node: OSPF area\7f60960
+Node: OSPF interface\7f63174
+Node: Redistribute routes to OSPF\7f65956
+Node: Showing OSPF information\7f68072
+Node: Debugging OSPF\7f69292
+Node: OSPFv3\7f70303
+Node: OSPF6 router\7f70621
+Node: OSPF6 area\7f70978
+Node: OSPF6 interface\7f71150
+Node: Redistribute routes to OSPF6\7f72002
+Node: Showing OSPF6 information\7f72306
+Node: BGP\7f73111
+Node: Starting BGP\7f73972
+Node: BGP router\7f74557
+Node: BGP distance\7f75793
+Node: BGP decision process\7f76234
+Node: BGP network\7f76490
+Node: BGP route\7f76671
+Node: Route Aggregation\7f77232
+Node: Redistribute to BGP\7f77784
+Node: BGP Peer\7f78293
+Node: Defining Peer\7f78471
+Node: BGP Peer commands\7f79087
+Node: Peer filtering\7f81458
+Node: BGP Peer Group\7f81949
+Node: BGP Address Family\7f82251
+Node: Autonomous System\7f82396
+Node: AS Path Regular Expression\7f83227
+Node: Display BGP Routes by AS Path\7f84490
+Node: AS Path Access List\7f84919
+Node: Using AS Path in Route Map\7f85373
+Node: Private AS Numbers\7f85639
+Node: BGP Communities Attribute\7f85784
+Node: BGP Community Lists\7f88245
+Node: Numbered BGP Community Lists\7f90926
+Node: BGP Community in Route Map\7f92500
+Node: Display BGP Routes by Community\7f94427
+Node: Using BGP Communities Attribute\7f95581
+Node: BGP Extended Communities Attribute\7f99139
+Node: BGP Extended Community Lists\7f100905
+Node: BGP Extended Communities in Route Map\7f102806
+Node: Displaying BGP routes\7f103249
+Node: Show IP BGP\7f103475
+Node: More Show IP BGP\7f104197
+Node: Capability Negotiation\7f105317
+Node: Route Reflector\7f108605
+Node: Route Server\7f108870
+Node: Multiple instance\7f109928
+Node: BGP instance and view\7f111741
+Node: Routing policy\7f113107
+Node: Viewing the view\7f113863
+Node: How to set up a 6-Bone connection\7f114135
+Node: Dump BGP packets and table\7f115507
+Node: VTY shell\7f116037
+Node: Filtering\7f116877
+Node: IP Access List\7f117225
+Node: IP Prefix List\7f117616
+Node: ip prefix-list description\7f120785
+Node: ip prefix-list sequential number control\7f121318
+Node: Showing ip prefix-list\7f121843
+Node: Clear counter of ip prefix-list\7f122926
+Node: Route Map\7f123347
+Node: Route Map Command\7f123848
+Node: Route Map Match Command\7f124051
+Node: Route Map Set Command\7f124659
+Node: IPv6 Support\7f125517
+Node: Router Advertisement\7f126082
+Node: Kernel Interface\7f126413
+Node: SNMP Support\7f128363
+Node: How to get ucd-snmp\7f128992
+Node: SMUX configuration\7f130040
+Node: Zebra Protocol\7f130473
+Node: Packet Binary Dump Format\7f132367
+Node: Command Index\7f143934
+Node: VTY Key Index\7f173652
+\1f
+End Tag Table
diff --git a/doc/zebra.texi b/doc/zebra.texi
new file mode 100644 (file)
index 0000000..d09ff4d
--- /dev/null
@@ -0,0 +1,150 @@
+\input texinfo @c -*- texinfo -*-
+@c %**start of header
+@setchapternewpage odd
+@settitle GNU Zebra
+@setfilename zebra.info
+@defcodeindex op
+@synindex pg cp
+@c %**end of header
+
+@c Set variables
+@set EDITION 0.1
+@set VERSION 0.93b
+@set UPDATED 12 September 2002
+@set UPDATED-MONTH September 2002
+
+@c These may vary with installation environment.
+@set INSTALL_PREFIX_ETC /usr/local/etc
+@set INSTALL_PREFIX_SBIN /usr/local/sbin
+
+@c Info entry
+@dircategory Routing Software:
+@direntry
+* Zebra: (zebra).              The @sc{gnu} Zebra routing software
+@end direntry
+
+@c @smallbook
+
+@ifinfo
+This file documents the @sc{gnu} Zebra software which manages common
+TCP/IP routing protocols.
+
+This is Edition @value{EDITION}, last updated @value{UPDATED} of
+@cite{The GNU Zebra Manual}, for Zebra Version @value{VERSION}.
+
+Copyright (C) 1999, 2000, 2001, 2002 Kunihiro Ishiguro
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copyright permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by Kunihiro Ishiguro.
+@end ifinfo
+
+@titlepage
+@title GNU Zebra
+@subtitle A routing software package for TCP/IP networks
+@subtitle Zebra version @value{VERSION}
+@subtitle @value{UPDATED-MONTH}
+@author Kunihiro Ishiguro
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1999, 2000, 2001, 2002 Kunihiro Ishiguro
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by Kunihiro Ishiguro.
+@end titlepage
+@page
+
+@ifnottex
+@node Top, Overview, (dir), (dir)
+@comment  node-name,  next,  previous,  up
+@top Zebra
+                    
+Zebra is a advanced routing software package that provides TCP/IP
+based routing protocols.  This is the Zebra Manual for
+zebra-@value{VERSION}.
+@end ifnottex
+
+@menu
+* Overview::                    
+* Installation::                
+* Basic commands::              
+* Zebra::                       
+* RIP::                         
+* RIPng::                       
+* OSPFv2::                      
+* OSPFv3::                      
+* BGP::                         
+* VTY shell::                       
+* Filtering::                   
+* Route Map::                   
+* IPv6 Support::                
+* Kernel Interface::            
+* SNMP Support::                
+* Zebra Protocol::              
+* Packet Binary Dump Format::   
+* Command Index::               
+* VTY Key Index::               
+@end menu
+
+@include overview.texi
+@include install.texi
+@include basic.texi
+@include main.texi
+@include ripd.texi
+@include ripngd.texi
+@include ospfd.texi
+@include ospf6d.texi
+@include bgpd.texi
+@include vtysh.texi
+@include filter.texi
+@include routemap.texi
+@include ipv6.texi
+@include kernel.texi
+@include snmp.texi
+@include protocol.texi
+@include appendix.texi
+
+@node Command Index, VTY Key Index, Top, Top
+@comment  node-name,  next,  previous,  up
+@unnumbered Command Index
+
+@printindex fn
+
+@node VTY Key Index,  , Command Index, Top
+@comment  node-name,  next,  previous,  up
+@unnumbered VTY Key Index
+
+@printindex ky
+
+@summarycontents
+@contents
+@bye
diff --git a/guile/.cvsignore b/guile/.cvsignore
new file mode 100644 (file)
index 0000000..bdcccd6
--- /dev/null
@@ -0,0 +1,3 @@
+Makefile
+*.o
+zebra-guile
diff --git a/guile/ChangeLog b/guile/ChangeLog
new file mode 100644 (file)
index 0000000..751e952
--- /dev/null
@@ -0,0 +1,26 @@
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+1999-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * guile-bgp.c (scm_router_bgp): Allocate real struct bgp object.
+
+       * Makefile.am: Delete -DPACKAGE and -DVERSION.
+
+       * zebra-guile.h: File added.
+       * zebra-support.c: File added.
+       * guile-bgp.c: File added.
+
+1999-04-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * guile/Makefile.am (INCLUDES): Use @GUILE_CFLAGS@ and
+       @GUILE_LDFLAGS@
+
+1999-04-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-guile work restarted.
diff --git a/guile/Makefile.am b/guile/Makefile.am
new file mode 100644 (file)
index 0000000..58b0547
--- /dev/null
@@ -0,0 +1,9 @@
+## Process this file with Automake to create Makefile.in
+
+INCLUDES = @GUILE_CFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -I. -I$(srcdir)
+
+bin_PROGRAMS = zebra-guile
+zebra_guile_SOURCES = zebra-guile.c zebra-support.c guile-bgp.c
+noinst_HEADERS = zebra-guile.h
+zebra_guile_LDADD = @GUILE_LDFLAGS@ ../bgpd/libbgp.a ../lib/libzebra.a
diff --git a/guile/Makefile.in b/guile/Makefile.in
new file mode 100644 (file)
index 0000000..2773029
--- /dev/null
@@ -0,0 +1,299 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 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.
+
+
+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
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AR = @AR@
+BGPD = @BGPD@
+CC = @CC@
+CPP = @CPP@
+CURSES = @CURSES@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LIBPAM = @LIBPAM@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+MAKEINFO = @MAKEINFO@
+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@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+
+INCLUDES = @GUILE_CFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -I. -I$(srcdir)
+
+bin_PROGRAMS = zebra-guile
+zebra_guile_SOURCES = zebra-guile.c zebra-support.c guile-bgp.c
+noinst_HEADERS = zebra-guile.h
+zebra_guile_LDADD = @GUILE_LDFLAGS@ ../bgpd/libbgp.a ../lib/libzebra.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+zebra_guile_OBJECTS =  zebra-guile.o zebra-support.o guile-bgp.o
+zebra_guile_DEPENDENCIES =  ../bgpd/libbgp.a ../lib/libzebra.a
+zebra_guile_LDFLAGS = 
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS =  $(noinst_HEADERS)
+
+DIST_COMMON =  README ChangeLog Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(zebra_guile_SOURCES)
+OBJECTS = $(zebra_guile_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps guile/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo "  $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+            $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(bin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+       done
+
+.c.o:
+       $(COMPILE) -c $<
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+zebra-guile: $(zebra_guile_OBJECTS) $(zebra_guile_DEPENDENCIES)
+       @rm -f zebra-guile
+       $(LINK) $(zebra_guile_LDFLAGS) $(zebra_guile_OBJECTS) $(zebra_guile_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = guile
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         if test -d $$d/$$file; then \
+           cp -pr $$/$$file $(distdir)/$$file; \
+         else \
+           test -f $(distdir)/$$file \
+           || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+           || cp -p $$d/$$file $(distdir)/$$file || :; \
+         fi; \
+       done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+all-redirect: all-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
+               mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-binPROGRAMS clean-compile clean-tags clean-generic \
+               mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-binPROGRAMS distclean-compile distclean-tags \
+               distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-binPROGRAMS \
+               maintainer-clean-compile maintainer-clean-tags \
+               maintainer-clean-generic distclean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# 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/guile/README b/guile/README
new file mode 100644 (file)
index 0000000..8e18fae
--- /dev/null
@@ -0,0 +1,17 @@
+
+                            zebra-guile
+
+                         Kunihiro Ishiguro
+                                1999
+
+1. What is zebra-guile
+
+zebra-guile is GNU Zebra which linked with guile.  Almost zebra's
+command can be called from guile interpreter.  So you can use guile as
+a routing scripting language.
+
+2. How to use it.
+
+(define bgp (router-bgp 7675))
+
+3.
diff --git a/guile/guile-bgp.c b/guile/guile-bgp.c
new file mode 100644 (file)
index 0000000..fbd01ba
--- /dev/null
@@ -0,0 +1,117 @@
+/* Guile bgp interface.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+#include <guile/gh.h>
+
+#include "log.h"
+#include "bgpd/bgpd.h"
+
+/* static SCM scm_mark_bgp (SCM obj); */
+static size_t scm_free_bgp (SCM vect);
+static int scm_print_bgp (SCM vect, SCM port, scm_print_state *pstate);
+static SCM scm_equalp_bgp (SCM a, SCM b);
+
+/* Tag of scheme type of bgp. */
+long scm_tag_bgp;
+
+static scm_smobfuns bgp_funs =
+{
+  scm_mark0, scm_free_bgp, scm_print_bgp, scm_equalp_bgp
+};
+
+static int
+scm_print_bgp (SCM vect, SCM port, scm_print_state *pstate)
+{
+  unsigned short num;
+  struct bgp *bgp;
+
+  num = 0;
+  bgp = (struct bgp *) SCM_CDR (vect);
+  num = bgp->as;
+  scm_puts ("#<bgp ", port);
+  scm_intprint (num, 10, port);
+  scm_putc ('>', port);
+  return 1;
+}
+
+static size_t
+scm_free_bgp (SCM obj)
+{
+  /* dummy function. */
+  return 10;
+}
+
+static SCM
+scm_equalp_bgp (SCM a, SCM b)
+{
+  
+  return SCM_BOOL_F;
+}
+
+/* Make bgp instance. */
+SCM
+scm_router_bgp (SCM as_number)
+{
+  SCM cell;
+  long num;
+  struct bgp *bgp;
+  struct bgp *bgp_create ();
+
+  SCM_ASSERT (SCM_INUMP (as_number), as_number, SCM_ARG1, "router-bgp");
+
+  SCM_DEFER_INTS;
+
+  num = gh_scm2long (as_number);
+
+  /* Make new bgp object. */
+  bgp = bgp_create ();
+  bgp->as = num;
+
+  SCM_NEWCELL (cell);
+  SCM_SETCAR (cell, scm_tag_bgp);
+  SCM_SETCDR (cell, bgp);
+
+  SCM_ALLOW_INTS;
+
+  return cell;
+}
+
+#if 0
+SCM
+scm_router_bgp_list ()
+{
+  return NULL;
+}
+#endif
+
+void
+init_bgp ()
+{
+  void bgp_init ();
+
+  bgp_init ();
+
+  /* Initi types. */
+  scm_tag_bgp  = scm_newsmob (&bgp_funs);
+
+  gh_new_procedure ("router-bgp", scm_router_bgp, 1, 0, 0);
+  /* gh_new_procedure ("router-bgp-list", scm_router_bgp_list, 0, 0, 0); */
+}
diff --git a/guile/zebra-guile.c b/guile/zebra-guile.c
new file mode 100644 (file)
index 0000000..f618dbc
--- /dev/null
@@ -0,0 +1,71 @@
+/* Zebra guile interface.
+   Copyright (C) 1998, 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 <libguile.h>
+#include "zebra-guile.h"
+
+#include "zebra.h"
+#include "thread.h"
+
+struct thread *master;
+
+static void
+init_libzebra ()
+{
+  void cmd_init();
+  void vty_init();
+  void memory_init();
+
+  cmd_init (1);
+  vty_init ();
+  memory_init ();
+}
+
+/* Install scheme procudures. */
+void
+init_zebra_guile ()
+{
+  init_libzebra ();
+
+  init_bgp ();
+
+#if 0
+  init_zebra ();
+  init_rip ();
+  init_ospf ();
+#endif /* 0 */
+}
+
+static void
+inner_main (void *closure, int argc, char **argv)
+{
+  /* Install zebra related scheme procedures. */
+  init_zebra_guile ();
+
+  /* Invoke interpreter. */
+  scm_shell (argc, argv);
+}
+
+int
+main (int argc, char **argv)
+{
+  scm_boot_guile (argc, argv, inner_main, 0);
+  return 0;                    /* Not reached */
+}
diff --git a/guile/zebra-guile.h b/guile/zebra-guile.h
new file mode 100644 (file)
index 0000000..f43e287
--- /dev/null
@@ -0,0 +1,21 @@
+/* Zebra guile header.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+void init_bgp ();
diff --git a/guile/zebra-support.c b/guile/zebra-support.c
new file mode 100644 (file)
index 0000000..9a6ef81
--- /dev/null
@@ -0,0 +1,19 @@
+/* Zebra guile interface support.
+   Copyright (C) 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
diff --git a/init/.cvsignore b/init/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/init/ChangeLog b/init/ChangeLog
new file mode 100644 (file)
index 0000000..90d3d24
--- /dev/null
@@ -0,0 +1,39 @@
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+2000-11-06  Lennert Buytenhek <buytenh@gnu.org>
+
+       * redhat/zebra.spec.in: Don't include ospf6d and ripngd in
+       package.
+
+       * redhat/zebra.logrotate: Fix logrotate file (add ospf.log).
+
+2000-10-02  Horms <horms@vergenet.net>
+
+       * redhat/zebra.spec.in: Moved chkconfig --del operations from
+       %postun to %preun, as chkconfig needs to run while the init files
+       are still present on the system.
+
+       * redhat/zebra.logrotate: New file is added.
+       
+2000-09-18  Lennert Buytenhek <buytenh@gnu.org>
+
+       * redhat/zebra.spec.in: New file is added.
+       redhat/ripd.init: Likewise.
+       redhat/ripngd.init: Likewise.
+       redhat/ospfd.init: Likewise.
+       redhat/ospf6d.init: Likewise.
+       redhat/bgpd.init: Likewise.
diff --git a/init/redhat/bgpd.init b/init/redhat/bgpd.init
new file mode 100644 (file)
index 0000000..91d2aeb
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: - 16 84
+# description: A BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra
+#
+# processname: bgpd
+# config: /etc/bgpd.conf
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+[ -f /etc/bgpd.conf ] || exit 0
+
+case "$1" in
+  start)
+       echo -n "Starting bgpd: "
+        daemon /usr/sbin/bgpd -d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/bgpd
+       echo
+       ;;
+  stop)
+       echo -n "Shutting down bgpd: "
+       killproc bgpd
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/bgpd
+       echo
+       ;;
+  restart)
+        $0 stop
+        $0 start
+       RETVAL=$?
+        ;;
+  status)
+        status bgpd
+       RETVAL=$?
+        ;;
+  *)
+       echo "Usage: bgpd {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/init/redhat/ospf6d.init b/init/redhat/ospf6d.init
new file mode 100644 (file)
index 0000000..4d89f8a
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: - 16 84
+# description: An OSPF routing engine for use with Zebra and IPv6
+#
+# processname: ospf6d
+# config: /etc/ospf6d.conf
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+[ -f /etc/ospf6d.conf ] || exit 0
+
+case "$1" in
+  start)
+       echo -n "Starting ospf6d: "
+        daemon /usr/sbin/ospf6d -d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospf6d
+       echo
+       ;;
+  stop)
+       echo -n "Shutting down ospf6d: "
+       killproc ospf6d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospf6d
+       echo
+       ;;
+  restart)
+        $0 stop
+        $0 start
+       RETVAL=$?
+        ;;
+  status)
+        status ospf6d
+       RETVAL=$?
+        ;;
+  *)
+       echo "Usage: ospf6d {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/init/redhat/ospfd.init b/init/redhat/ospfd.init
new file mode 100644 (file)
index 0000000..d7453b6
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: - 16 84
+# description: An OSPF v2 routing engine for use with Zebra
+#
+# processname: ospfd
+# config: /etc/ospfd.conf
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+[ -f /etc/ospfd.conf ] || exit 0
+
+case "$1" in
+  start)
+       echo -n "Starting ospfd: "
+        daemon /usr/sbin/ospfd -d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospfd
+       echo
+       ;;
+  stop)
+       echo -n "Shutting down ospfd: "
+       killproc ospfd
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospfd
+       echo
+       ;;
+  restart)
+        $0 stop
+        $0 start
+       RETVAL=$?
+        ;;
+  status)
+        status ospfd
+       RETVAL=$?
+        ;;
+  *)
+       echo "Usage: ospfd {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/init/redhat/ripd.init b/init/redhat/ripd.init
new file mode 100644 (file)
index 0000000..d87f498
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: - 16 84
+# description: A RIP routing engine for use with Zebra
+#
+# processname: ripd
+# config: /etc/ripd.conf
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+[ -f /etc/ripd.conf ] || exit 0
+
+case "$1" in
+  start)
+       echo -n "Starting ripd: "
+        daemon /usr/sbin/ripd -d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripd
+       echo
+       ;;
+  stop)
+       echo -n "Shutting down ripd: "
+       killproc ripd
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripd
+       echo
+       ;;
+  restart)
+        $0 stop
+        $0 start
+       RETVAL=$?
+        ;;
+  status)
+        status ripd
+       RETVAL=$?
+        ;;
+  *)
+       echo "Usage: ripd {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/init/redhat/ripngd.init b/init/redhat/ripngd.init
new file mode 100644 (file)
index 0000000..26c153b
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: - 16 84
+# description: A RIP routing engine for use with Zebra and IPv6
+#
+# processname: ripngd
+# config: /etc/ripngd.conf
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+[ -f /etc/ripngd.conf ] || exit 0
+
+case "$1" in
+  start)
+       echo -n "Starting ripngd: "
+        daemon /usr/sbin/ripngd -d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripngd
+       echo
+       ;;
+  stop)
+       echo -n "Shutting down ripngd: "
+       killproc ripngd
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripngd
+       echo
+       ;;
+  restart)
+        $0 stop
+        $0 start
+       RETVAL=$?
+        ;;
+  status)
+        status ripngd
+       RETVAL=$?
+        ;;
+  *)
+       echo "Usage: ripngd {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/init/redhat/zebra.init b/init/redhat/zebra.init
new file mode 100644 (file)
index 0000000..b09918a
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: - 15 85
+# description: GNU Zebra routing manager
+#
+# processname: zebra
+# config: /etc/zebra.conf
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+[ -f /etc/zebra.conf ] || exit 0
+
+case "$1" in
+  start)
+       echo -n "Starting zebra: "
+        daemon /usr/sbin/zebra -d
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/zebra
+       echo
+       ;;
+  stop)
+       echo -n "Shutting down zebra: "
+       killproc zebra
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/zebra
+       echo
+       ;;
+  restart)
+        $0 stop
+        $0 start
+       RETVAL=$?
+        ;;
+  status)
+        status zebra
+       RETVAL=$?
+        ;;
+  *)
+       echo "Usage: zebra {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/init/redhat/zebra.logrotate b/init/redhat/zebra.logrotate
new file mode 100644 (file)
index 0000000..0d13baf
--- /dev/null
@@ -0,0 +1,47 @@
+/var/log/zebra/zebra.log {
+    notifempty
+    missingok
+    postrotate
+       /usr/bin/killall -USR1 zebra
+    endscript
+}
+
+/var/log/zebra/bgpd.log {
+    notifempty
+    missingok
+    postrotate
+       /usr/bin/killall -USR1 bgpd
+    endscript
+}
+
+/var/log/zebra/ospf.log {
+    notifempty
+    missingok
+    postrotate
+       /usr/bin/killall -USR1 ospfd
+    endscript
+}
+
+/var/log/zebra/ospf6.log {
+    notifempty
+    missingok
+    postrotate
+       /usr/bin/killall -USR1 ospf6d
+    endscript
+}
+
+/var/log/zebra/rip.log {
+    notifempty
+    missingok
+    postrotate
+       /usr/bin/killall -USR1 ripd
+    endscript
+}
+
+/var/log/zebra/ripng.log {
+    notifempty
+    missingok
+    postrotate
+       /usr/bin/killall -USR1 ripng
+    endscript
+}
diff --git a/init/redhat/zebra.spec.in b/init/redhat/zebra.spec.in
new file mode 100644 (file)
index 0000000..e517a46
--- /dev/null
@@ -0,0 +1,128 @@
+%define version @VERSION@
+
+Summary:       Zebra routing engine
+Name:          zebra
+Version:       %{version}
+Release:       1
+Source:                zebra-%{version}.tar.gz
+URL:           http://www.zebra.org
+Copyright:     GPL
+Group:         System Environment/Daemons
+BuildRoot:     /tmp/zebra-%{version}-root
+
+%description
+GNU Zebra is free software (distributed under GNU Generic Public License)
+that manages TCP/IP based routing protocols. It supports BGP-4 protocol as
+described in RFC1771 (A Border Gateway Protocol 4) as well as RIPv1, RIPv2
+and OSPFv2. Unlike traditional, Gated based, monolithic architectures and
+even the so-called "new modular architectures" that remove the burden of
+processing routing functions from the cpu and utilize special ASIC chips
+instead, Zebra software offers true modularity.
+
+%prep
+%setup
+
+%build
+#./configure --enable-snmp --prefix=/usr --sysconfdir=/etc
+./configure --prefix=/usr --sysconfdir=/etc
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make DESTDIR=$RPM_BUILD_ROOT install
+rm -f $RPM_BUILD_ROOT/usr/info/dir
+rm -f $RPM_BUILD_ROOT/usr/man/man8/ospf6*
+rm -f $RPM_BUILD_ROOT/usr/man/man8/ripng*
+rm -f $RPM_BUILD_ROOT/usr/sbin/ospf6d
+rm -f $RPM_BUILD_ROOT/usr/sbin/ripngd
+strip $RPM_BUILD_ROOT/usr/sbin/*
+
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
+install -m755 init/redhat/bgpd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/bgpd
+#install -m755 init/redhat/ospf6d.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospf6d
+install -m755 init/redhat/ospfd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospfd
+install -m755 init/redhat/ripd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripd
+#install -m755 init/redhat/ripngd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripngd
+install -m755 init/redhat/zebra.init $RPM_BUILD_ROOT/etc/rc.d/init.d/zebra 
+
+mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
+install -m644 init/redhat/zebra.logrotate $RPM_BUILD_ROOT/etc/logrotate.d/zebra
+
+
+%post
+# zebra_spec_add_service <sercice name> <port/proto> <comment>
+# e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service"
+
+zebra_spec_add_service ()
+{
+  # Add port /etc/services entry if it isn't already there 
+  if [ -f /etc/services ] && ! grep -q "^$1[^a-zA-Z0-9]" /etc/services ; then
+    echo "$1            $2              # $3"  >> /etc/services
+  fi
+}
+
+zebra_spec_add_service zebrasrv 2600/tcp "zebra service"
+zebra_spec_add_service zebra    2601/tcp "zebra vty"
+zebra_spec_add_service ripd     2602/tcp "RIPd vty"
+zebra_spec_add_service ripngd   2603/tcp "RIPngd vty"
+zebra_spec_add_service ospfd    2604/tcp "OSPFd vty"
+zebra_spec_add_service bgpd     2605/tcp "BGPd vty"
+zebra_spec_add_service ospf6d   2606/tcp "OSPF6d vty"
+
+#Install info
+/sbin/install-info /usr/info/zebra.info /usr/info/dir
+
+if [ -x /sbin/chkconfig ]; then
+  chkconfig --add bgpd
+#  chkconfig --add ospf6d
+  chkconfig --add ospfd
+  chkconfig --add ripd
+#  chkconfig --add ripngd
+  chkconfig --add zebra
+fi
+
+
+%preun
+if [ "$1" = 0 ] ; then
+  /sbin/install-info --delete /usr/info/zebra.info /usr/info/dir
+
+  if [ -x /sbin/chkconfig ]; then
+    chkconfig --del bgpd
+#    chkconfig --del ospf6d
+    chkconfig --del ospfd
+    chkconfig --del ripd
+#    chkconfig --del ripngd
+    chkconfig --del zebra
+  fi
+fi
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+rm -rf $RPM_BUILD_DIR/%{name}-%{version}
+
+%files
+%attr(-,root,root) %doc AUTHORS COPYING ChangeLog INSTALL NEWS README SERVICES TODO bgpd/bgpd.conf.sample ospfd/ospfd.conf.sample ripd/ripd.conf.sample zebra/zebra.conf.sample
+%attr(-,root,root) %config /etc/rc.d/init.d/*
+%attr(-,root,root) %config /etc/logrotate.d/*
+%attr(-,root,root) /usr/info/*
+#%attr(-,root,root) /usr/man/*      # Not man1 to exclude vtysh man page as
+                                    # it is not build by default (for now)
+%attr(-,root,root) /usr/man/man8/*
+%attr(-,root,root) /usr/sbin/*
+
+%changelog
+* Mon Nov 6 2000 Lennert Buytenhek <buytenh@gnu.org>
+- Don't include ospf6d and ripngd in package.
+- Fix logrotate file (add ospf.log).
+* Mon Oct 2 2000 Horms <horms@valinux.com>
+- Install and uninstall info in %post and %preun respectively
+- Moved chkconfig --del operations from %postun to %preun, as
+  chkconfig needs to run while the init files are still present on
+  the system.
+- Don't install vtysh man page as vtysh is not build by default
+- Added logrotate script so logs won't grow without bound
+* Wed Sep 27 2000 Horms <horms@vergenet.net>
+- Add ports to /etc/services if they aren't there
+- forcibly remove $RPM_BUILD_ROOT/usr/info/dir and friends so
+  there is no error if it does not exist when rm is run.
+- Clean up the zebra build dir 
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..398a88e
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       :
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=$mkdirprog
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               :
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               :
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               :
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+       '
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               :
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               :
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/lib/.cvsignore b/lib/.cvsignore
new file mode 100644 (file)
index 0000000..051b8e4
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+*.o
+version.c
+.deps
diff --git a/lib/ChangeLog b/lib/ChangeLog
new file mode 100644 (file)
index 0000000..b4d0ae1
--- /dev/null
@@ -0,0 +1,1926 @@
+2002-09-28  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * vty.c (vty_flush): One line more on vty.
+
+2002-09-27  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * vector.c (vector_lookup): Add new function.
+
+2002-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * thread.c (timeval_adjust): Fix unconditional crush due to
+       FreeBSD's select() system call timeval value check.
+
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2002-06-21  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * if.c (ifc_pointopoint): Add ifc_pointopoint() accoding to Frank
+       van Maarseveen's suggestion.
+
+2002-06-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c: Change bcopy() to memcpy().
+
+2001-12-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (config_password): Fix host.password clear bug.
+       Reported by Wang Jian <lark@linux.net.cn>.
+
+2001-08-29  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * thread.c (thread_should_yield): New function to check thread
+       should yeild it's execution to other thread.  Suggested by: Rick
+       Payne <rickp@ayrnetworks.com>
+
+2001-08-20  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * thread.c (thread_timer_cmp): Rewrite function.
+
+       * hash.c: Add hash_get().  Change hash_pull() to hash_release().
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-08-12  Akihiro Mizutani <mizutani@dml.com>
+
+       * prefix.c (netmask_str2prefix_str): Convert "1.1.0.0 255.255.0.0"
+       string to "1.1.0.0/16".
+
+2001-08-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c (access_list_lookup): access_list_lookup's first
+       argument is changed from address family to AFI.
+
+       * plist.c: (prefix_list_lookup): Likewise.
+
+2001-07-27  Akihiro Mizutani <mizutani@dml.com>
+
+       * plist.c: ge and le display order is changed.  Old compatible
+       rule (len <= ge-value <= le-value) is removed.
+
+2001-07-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * prefix.h: Temporary fix for alignment of prefix problem.
+
+2001-06-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * prefix.h (struct prefix): Remove safi and padding field.
+       (struct prefix_ipv4): Likewise.
+       (struct prefix_ipv6): Likewise.
+       (struct prefix_ls): Likewise.
+       (struct prefix_rd): Likewise.
+
+       * command.h (enum node_type): Preparation for BGP new config.
+
+       * vty.c (vty_end_config): Likewise.
+
+2001-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.c (route_map_rule_delete): Call func_free when
+       route-map rule is deleted.
+
+2001-06-14  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * routemap.c (route_map_index_lookup): Prevent to use deny and
+       permit for same route-map sequence.
+
+2001-04-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_read_config): Fix warning.
+
+2001-03-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (IPV6_PREFIX_STR): Add '.' and '%' for IPv6 address
+       strings.
+
+2001-03-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (_XPG4_2): Define _XPG4_2 and __EXTENSIONS__ for
+       CMSG_FIRSTHDR.
+
+2001-03-07  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * zebra.h (struct in_pktinfo): structure in_pktinfo declaration.
+
+2001-02-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.c (memory_list_lib): Add MTYPE_NEXTHOP for "show memory
+       lib" member.
+
+2001-02-13  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * vty.c (vty_read_config): Revert check of integrate_default when
+       VTYSH is defined.
+
+2001-02-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_read_config): Do not check integrate_default.  That
+       should be used only by vtysh.
+
+2001-02-08  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * vty.c (vty_serv_un): Set umask 0077.
+       (vty_read_config): Stat for vtysh Zebra.conf, if found startup and
+       wait for boot configuration.
+
+       * if.c (if_lookup_address): Make it smart implementation.
+
+       * sockopt.c (setsockopt_multicast_ipv4): Set up a multicast socket
+       options for IPv4 This is here so that people only have to do their
+       OS multicast mess in one place rather than all through zebra,
+       ospfd, and ripd .
+
+2001-02-04  Akihiro Mizutani <mizutani@dml.com>
+
+       * plist.c (vty_prefix_list_install): Even when argument is
+       invalid, new memory is allocated.  Now memory allocation is done
+       after argument check.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-31  Akihiro Mizutani <mizutani@dml.com>
+
+       * vty.c (vty_login): Add vty login command.
+
+2001-01-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_reset): Close accept socket.
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): MTYPE_ATTR_TRANSIT is added for unknown transit
+       attribute.
+
+2001-01-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.c (zebra_interface_address_add_read): Fetch interface
+       address flag.
+       (zebra_interface_address_delete_read): Likewise.
+
+2001-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * table.c (route_node_match_ipv4): Utility function for IPv4
+       address lookup.
+       (route_node_match_ipv6): Utility function for IPv4 address lookup.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c: Delete RIP_API part until new implementation comes out.
+
+2001-01-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * hash.h (struct Hash): Rename alloc to count.  Change type to
+       unsigned long.
+
+       * stream.c (stream_getc_from): New function.
+       (stream_getw_from): Likewise.
+
+       * zebra.h (ZEBRA_FLAG_STATIC): Add new flag for persistent route.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * flap.c: File is removed.
+
+       * flap.c: Likewise.
+
+       * roken.h: Likewise.
+
+       * buffer.c (buffer_new): Remove type option to buffer_new().
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.c (zapi_ipv4_delete): Remove OLD_RIB part.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+       * command.c: Update Copyright year.
+
+2001-01-09  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * if.c (if_create): Register connected_free() function for
+       deletion.
+       (if_delete): Free connected information when the interface is
+       deleted.
+       (if_lookup_by_index): Fix argument type from int to unsigned int.
+       (connected_add): Keep list in order if old info found, essential
+       for repeatable operation in some daemons.
+
+2001-01-09  endo@suri.co.jp (Masahiko Endo)
+
+       * vty.c (vty_flush): When vty->statis is VTY_CLOSE do not add vty
+       read thread.
+
+2001-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c (access_list_delete): Access-list name is not freed.
+
+       * plist.c (prefix_list_delete): Prefix-list name is not freed.
+
+2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.c (zclient_start): Change to use UNIX domain
+       socket for zebra communication.
+
+       * vector.c (vector_init): vector_alloc and vector_data_alloc is
+       removed.  All memory allocation count should be maintained by
+       XMALLOC and XFREE macros.
+
+2000-12-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_NEXTHOP_IFINDEX): Define ZEBRA_NEXTHOP_* values.
+
+2000-12-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_ERR_RTEXIST): Make zebra error code to negative
+       value.
+
+2000-12-25  "Wataru Uno" <wataru@po.ntts.co.jp>
+
+       * vty.c (vtysh_read): Don't allocate new buffer because buffer is
+       allocated in vty_new ().
+
+2000-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_AS_FILTER_STR.
+
+       * command.c (config_write_terminal): Display "end" at the end of
+       configuration.
+
+       * plist.c (vty_prefix_list_install): Use AF_INET to determine
+       lenum length.
+
+2000-12-13  "Wataru Uno" <wataru@po.ntts.co.jp>
+
+       * buffer.c (buffer_flush_vty): If IOV_MAX defined in the System,
+       then all lines write by IOV_MAX.
+
+2000-12-12  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * command.c (config_write_file): Robust method for writing
+       configuration file and recover from backing up config file.
+
+2000-11-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * smux.c (smux_connect): More fail check.
+       (smux_trap): When SMUX connection is not established, do nothing.
+
+2000-11-28  Gleb Natapov <gleb@nbase.co.il>
+
+       * thread.c (thread_fetch): Execut event list first.  Old event
+       list is renamed to ready list.  With this change, event thread is
+       executed before any other thread.
+
+       * thread.h (struct thread_master): Add ready list.
+
+2000-11-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * linklist.c (listnode_add_after): Add node right after the
+       listnode pointer.
+
+2000-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * smux.h: Pass struct variable to WriteMethod.
+
+2000-11-25  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+       * if.c (if_lookup_address): When looking up interface with IP
+       address, Sometimes multiple interfaces will match.  Now PtP
+       interfaces prevail in such a case which seem the right thing to
+       do: There will probably also be host routes which usually prevail
+       over network routes.
+
+2000-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * smux.c (smux_trap): SMUX trap implementation.
+
+2000-11-19  Akihiro Mizutani <mizutani@dml.com>
+
+       * plist.c: Add automatic conversion function of an old rule. 
+       ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 le 32
+
+2000-11-16  Yon Uriarte <ukl2@rz.uni-karlsruhe.de>
+
+       * zclient.c (zebra_interface_add_read): Read hardware address when
+       hw_addr_len is greater than 0.
+
+2000-11-15  Akihiro Mizutani <mizutani@dml.com>
+
+       * plist.c: The rule of "len <= ge-value <= le-value" 
+       was changed to "len < ge-value <= le-value".
+
+2000-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * memory.[ch]: Added #define and functions for ospf6d.
+
+       * log.[ch]: some platform says that the data of used va_list
+       is undefined. Changed to hold list of va_list for each
+       vsnprintf.
+
+2000-11-07  Rick Payne <rickp@rossfell.co.uk>
+
+       * memory.h (enum): Add MTYPE_COMMUNITY_REGEXP.
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (config_exit): Fix bug of missing break after case
+       BGP_VPNV4_NODE.
+
+2000-10-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vector.c (vector_unset): Check i is not nevative.
+
+2000-10-24  Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+       * smux.c (smux_sock): Set terminating '\0'.  Check address family.
+
+       * vty.c (vty_serv_sock_addrinfo): Set terminating '\0'. Use
+       gai_strerror.  Check address family.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+       * smux.c: Use linklist rather than vector.
+       (smux_getnext): A SMUX subagent has to behave as if it manages the
+       whole SNMP MIB tree itself. It's the duty of the master agent to
+       collect the best answer and return it to the manager. See RFC 1227
+       chapter 3.1.6 for the glory details :-). ucd-snmp really behaves
+       bad here as it actually might ask multiple times for the same
+       GETNEXT request as it throws away the answer when it expects it in
+       a different subtree and might come back later with the very same
+       request.
+
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_init): Log related command are only installed for
+       terminal mode.
+
+2000-10-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (libzebra_a_SOURCES): Remove duplicated buffer.c.
+
+       * zebra.h: Remove #warn directive.
+
+2000-10-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * keychain.c (keychain_init): Register "key chain" command to
+       KEYCHAIN_NODE and KEYCHAIN_KEY_NODE.
+
+       * vty.c (vty_end_config): Fix missing vty_cinfig_unlock for other
+       CONFIG_NODE.
+
+       * command.c (config_end): Likewise.
+
+       * keychain.c (keychain_get): Key is sorted by it's identifier
+       value.
+
+2000-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * linklist.c (list_delete_all_node): Call delete function if it is
+       defined.
+
+       * command.c (cmd_execute_command_strict): Add modification for
+       vtysh.
+       (cmd_execute_command_strict): Remove first argument cmdvec because
+       it is global varibale in command.c.
+
+2000-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_init): Install
+       copy_runningconfig_startupconfig_cmd only in terminal mode.
+
+       * linklist.c (list_delete_node): Simplify the function.
+       (listnode_lookup): Renamed from list_lookup_node.
+
+2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * stream.h: Undef stream_read and stream_write without
+       parenthesis.
+
+       * newlist.c: File removed.
+
+       * newlist.h: Likewise.
+
+       * linklist.c (list_new): Remove list_init().  To allocate new
+       linked list, please use list_new().
+       (listnode_add): Remove list_add_node().  To add new node to linked
+       list, please use listnode_add().
+       (list_delete_by_val): Revemove fucntion.
+
+2000-10-16  Nobuaki Tanaka <nobby@po.ntts.co.jp>
+
+       * table.c (route_table_free): Reimplement route_table_free().
+
+2000-10-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * keychain.c (keychain_get): Register key_delete_func to key
+       list's delete function.  Use linklist.c instead of newlist.c.
+
+2000-10-04  Akihiro Mizutani <mizutani@dml.com>
+
+       * filter.c (access_list_remark): Add access-list's remark command.
+       (no_access_list): "no access-list 100 permit any" error message
+       bug is fixed.
+
+2000-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_SOCKUNION.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-10-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * linklist.c (list_add_node_head): Delete unused function.
+       (list_add_node_tail): Likewise.
+
+2000-09-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * stream.c (stream_read_unblock): Add new function for unblocking
+       read.
+
+2000-09-26  Jochen Friedrich <jochen@nwe.de>
+
+       * smux.c (smux_register): Fix bug of can't register more than one
+       MIB with SMUX.
+
+2000-09-26  Makoto Otsuka <otsuka@inl.ntts.co.jp>
+
+       * vty.c (vty_close): Fix memory leak of sb_buffer.
+       (vty_new): Likewise.
+
+2000-09-21  steve@Watt.COM (Steve Watt)
+
+       * log.h: Do not declare zlog_priority[0] variable.
+
+2000-09-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * linklist.h (struct _list ): Add member cmp for compare function.
+       (struct _list ): Member up is deleted
+
+2000-09-12  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+       * if.c: Include RIP_API header when RIP API is enabled.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * prefix.c (prefix_free): Siplify prefix_free().
+
+       * keychain.c (key_match_for_accept): strncmp check bug is fixed.
+
+2000-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h: Merge roken.h into zebra.h.
+
+2000-09-05  Akihiro Mizutani <mizutani@dml.com>
+
+       * routemap.c (route_map_init_vty): Install route-map command to
+       RMAP_NODE.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * thread.c (thread_get_id): Remove pthread related garbage.
+
+       * command.h (struct host): Likewise.
+
+       * zebra.h: Likewise.
+
+2000-08-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add AAA node for authentication.
+
+       * vty.c (vty_close): Do not close stdout.
+
+2000-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_init_vtysh): Added for vtysh.
+
+       * distribute.c (districute_list_prefix_all): Interface independent
+       filter can be set.
+       (distribute_list_all): Likewise.
+       (config_show_distribute): Display current distribute-list status
+       for "show ip protocols".
+
+2000-08-18  Akihiro Mizutani <mizutani@dml.com>
+
+       * command.c (config_terminal_no_length): no terminal monitor ->
+       terminal no monitor
+       (cmd_init): Do not install service_terminal_length_cmd into
+       ENABLE_NODE.
+
+       * vty.c (terminal_no_monitor): no terminal length -> terminal no
+       length.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+2000-08-17  Magnus Ahltorp <ahltorp@nada.kth.se>
+
+       * vty.h (struct vty ): Add iac_sb_in_progress and sb_buffer for
+       better IAC handling.
+
+       * vty.c (vty_telnet_option): Change telnet option handling.
+
+2000-08-15  Gleb Natapov <gleb@nbase.co.il>
+
+       * zclient.c (zclient_redistribute_unset):  New function added.
+
+2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.c (zebra_interface_add_read): Change ifindex restore
+       size from two octet to four.
+       (zebra_interface_state_read): Likewise.
+       (zebra_interface_address_add_read): Likewise.
+
+2000-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_event): Use vector_set_index() instead of
+       vector_set().
+
+2000-08-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_XXX_DISTANCE_DEFAULT): Define Default
+       Administrative Distance of each protocol.
+
+2000-08-07  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * if.h (struct interface ): Add new member bandwidth to struct
+       interface.
+
+       * zclient.c (zebra_interface_add_read): Fetch bandwidth value.
+       (zebra_interface_state_read): Likewise.
+
+2000-08-07  Gleb Natapov <gleb@nbase.co.il>
+
+       * routemap.c (route_map_event_hook): New hook route_map_event_hook
+       is added.  This hook is called when route-map is changed. The
+       parameters passed to the hook are 'event' and 'route-map name'
+
+       * routemap.h: Add prototype for route_map_event_hook().
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.c (zebra_ipv4_route): zebra_ipv4_route(),
+       zebra_ipv4_add(), zebra_ipv4_delete() are removed.
+
+       * routemap.c (route_map_empty): Add new function.
+       (route_map_delete): Use route_map_index_delete() instead of
+       route_map_index_free().
+       (route_map_index_free): Function removed.
+
+2000-08-06  Gleb Natapov <gleb@nbase.co.il>
+
+       * routemap.c (route_map_index_delete): Add check for route-map is
+       empty or not.
+
+2000-08-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.c (zebra_ipv4_add): Change socket arguemnt with struct
+       zclient.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.h (struct zebra): Add obuf for output buffer.
+
+       * if.c: Remove #ifdef NRL enclosing if_nametoindex() and
+       if_indextoname().
+
+2000-08-02  David Lipovkov <davidl@nbase.co.il>
+
+       * if.h (IF_PSEUDO_UNSET): IF_PSEUDO related macro added.
+       (IF_UNKNOWN_SET): IF_UNKNOWN related macro deleted.
+
+       * if.c (interface_pseudo): Add "pseudo" command to interface node.
+       (no_interface_pseudo): Add "no pseudo" command to interface node.
+
+       * zclient.c (zebra_interface_add_read): Set pseudo flag when it is
+       send from zebra.
+
+2000-08-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_IPV4_NEXTHOP_LOOKUP): Add new message.
+       (ZEBRA_IPV6_NEXTHOP_LOOKUP): Likewise.
+
+       * vty.c (vty_serv_un): Use AF_UNIX for backward compatibility.
+
+2000-07-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c: Use vector for VTY server thread listing instead of
+       single value.
+
+2000-07-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * keychain.c (no_key_chain): "no key chain WORD" command is added.
+
+2000-07-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (config_from_file): If command fail in
+       KEYCHAIN_KEY_NODE, down to KEYCHAIN_NODE.
+
+       * vty.h (struct vty ): Add index_sub member.
+
+2000-07-27  Akihiro Mizutani <mizutani@dml.com>
+
+       * if.c: Help strings updates.
+
+2000-07-11  Akihiro Mizutani <mizutani@dml.com>
+
+       * command.c (no_config_enable_password): Add "no enable password"
+       command.
+       (config_write_host): Display password string.
+
+       * routemap.c (route_map_delete_match): Add support for delete
+       match without argument.
+       (route_map_delete_set): Likewise.
+
+2000-07-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Change KEYCHAIN_NODE and
+       KEYCHAIN_KEY_NODE place just before INTERFACE_NODE.
+
+2000-07-09  Jochen Friedrich <jochen@scram.de>
+
+       * smux.c (config_write_smux): Fixes the option to override OID and
+       password for SMUX.
+
+2000-07-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add SMUX_NODE for SMUX configuration.
+
+2000-07-09  Toshiaki Takada  <takada@zebra.org>
+
+       * command.c: Sort descvec command's help.
+
+       * vty.c (vty_describe_command): Display '<cr>' at the end of
+       descriptions.
+
+2000-07-05  Toshiaki Takada  <takada@zebra.org>
+
+       * command.c (cmd_ipv6_match), (cmd_ipv6_prefix_match):  Fix bug
+       treatment of double colon.
+
+2000-07-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zclient.h: Add zclient_redistribute_default_{set,unset}().
+
+       * keychain.c: New file for authentication key management.
+       * keychain.h: Likewise.
+       
+       * tcpfilter.c: New file for TCP/UDP base filtering using ipfw or
+       ipchains.
+       * tcpfilter.h: Likewise.
+       
+       * flap.h: New file for route flap dampening.
+       * flap.c: Likewise.
+
+2000-07-04  Toshiaki Takada <takada@zebra.org>
+
+       * filter.c (struct filter): Add exact flag.
+       (access_list): Add exact-match command.
+       (ipv6_access_list): Add exact-match command.
+       
+2000-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_REDISTRIBUTE_DEFAULT_ADD): New message for
+       request default route.
+
+2000-07-01  Hideaki YOSHIFUJI (\e$B5HF#1QL@\e(B) <yoshfuji@ecei.tohoku.ac.jp>
+
+       * smux.c: Add IPv6 smux connection code.
+
+2000-06-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_complete_command): To cooperate readline library,
+       returned string is newly allocated.  So some match function case
+       need, free of memory.
+
+2000-06-12  Akihiro Mizutani <mizutani@dml.com>
+
+       * distribute.c: Fix help strings.
+
+2000-06-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_complete_command): Add check for vector_slot
+       (vline, index) is not NULL when calculating lcd.
+       (cmd_entry_function): First check variable arguemnt to prevent it
+       from completion.
+
+2000-06-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.h (struct vty ): Add output_count member for displaying
+       output route count.  Remove arugment arg from output_func because
+       the value is passed by vty argument.  Change output to output_rn.
+       Add output_clean function pointer member.  Add output_type member.
+
+2000-06-10  Toshiaki Takada <takada@zebra.org>
+
+       * command.c (show_startup_config): Add "show startup-config"
+       command.
+
+2000-06-06  Akihiro Mizutani <mizutani@dml.com>
+
+       * filter.c: Fix help strings.
+
+2000-06-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * prefix.h (struct prefix_rd): New prefix structure for routing
+       distinguisher.
+       (struct prefix): Add padding to every prefix structure.
+
+
+       * routemap.c (route_map_add_match): When completely same match
+       statement exists, don't duplicate it.
+
+2000-06-05  Akihiro Mizutani <mizutani@dml.com>
+
+       * routemap.c: Change NAME to WORD.
+
+       * plist.c: Fix help strings.
+
+2000-06-02  Akihiro Mizutani <mizutani@dml.com>
+
+       * routemap.c: Fix route-map help strings.
+
+2000-06-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_filter_by_completion): Fix CMD_VARARG treatment
+       to filter other non vararg commands.
+
+       * routemap.c (route_map_init_vty): Use install_default() for
+       install common commands into route-map node..
+
+2000-06-01  Akihiro Mizutani  <mizutani@dml.com>
+
+       * command.h (OSPF_STR):  Macro added.
+
+2000-05-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_complete_command): LCD completion must not modify
+       installed command string.
+
+       * plist.c (ipv6_prefix_list): Fix wrong syntax definition.  Change
+       X:X::X:X to X:X::X:X/M.
+
+2000-05-31  Toshiaki Takada  <takada@zebra.org>
+
+       * vty.c (show_history):  New defun added.
+
+2000-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (CMD_COMPLETE_LIST_MATCH): New define for completion
+       list.  CMD_COMPLETE_MATCH is used for LCD completion.
+
+       * vty.c (vty_complete_command): Matched string's LCD is completed.
+
+       * command.c (cmd_lcd): New function for calculate LCD of matched
+       strings.
+
+2000-05-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (install_default): config_write_terminal_cmd,
+       config_write_file_cmd, config_write_memory_cmd are added to
+       default node.
+
+       * memory.c (memory_init): Divide show memory command into each
+       sort.
+
+       * command.c (cmd_init): config_write_terminal_cmd,
+       config_write_file_cmd, config_write_memory_cmd are added to
+       CONFIG_NODE.
+
+       * routemap.c (route_map_index_free): New function.
+       (no_route_map_all): New DEFUN for "no route-map NAME".
+
+       * filter.c (no_access_list_all): New DEFUN for delete access-list
+       with NAME.
+       (no_ipv6_access_list_all): Likewise.
+
+2000-05-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * plist.c: Change IPV6_PREFIX to X:X::X:X.  When "any" is
+       specified, user can not use "ge" and "le" statement.
+
+2000-05-22  Thomas Molkenbur <tmo@datus.datus.com>
+
+       * routemap.c (route_map_add_set): Fix bug of next pointer missing.
+
+       * table.c (route_table_free): Like wise.
+
+2000-05-22  Toshiaki Takada  <takada@zebra.org>
+
+       * vty.c (vty_stop_input): Set history pointer to the latest one.
+
+       * vty.c (vty_hist_add): Do not add command line history when input
+       is as same as previous one.
+
+2000-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_ECOMMUNITY and MTYPE_ECOMMUNITY_VAL.
+
+2000-05-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add BGP_VPNV4_NODE.
+
+2000-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vtysh_accept): Add cast of struct sockaddr * to bind
+       argument.  Reported by: Vesselin Mladenov <mladenov@netbg.com>.
+
+       * filter.c (ipv6_access_list): Add IPv6 prefix example instead of
+       IPv4 example.  Reported by: Love <lha@s3.kth.se>.
+
+       * command.c (cmd_complete_command): Make it sure last element of
+       matchvec is NULL.  This fix problem which cause crush in
+       vty_complete_command().  Reported by: JINMEI Tatuya
+       <jinmei@isl.rdc.toshiba.co.jp>.
+
+2000-04-28  Love <lha@s3.kth.se>
+
+       * prefix.h (struct prefix): Add padding.
+
+2000-04-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (show_version): Update copyright year.
+
+2000-04-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.c (route_map_apply): When map is NULL, return deny.
+
+2000-04-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c (access_list_apply): When access is NULL, return deny.
+
+       * plist.c (prefix_list_apply): When plist is NULL, return deny.
+
+2000-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Change RDISC_NODE to IRDP_NODE.
+
+2000-04-18  Toshiaki Takada  <takada@zebra.org>
+
+       * filter.[ch] (access_list_add_hook), (access_list_delete_hook):
+       Add argument for hook function to give struct access_list *.
+
+2000-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * plist.c (prefix_list_entry_match): In case of le nor ge is
+       specified, exact match is performed.
+       (prefix_list_entry_match): Add any entry matching check.
+
+2000-04-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (exec_timeout): Separate timeout setting to minutes and
+       seconds.
+       (no_exec_timeout): Add "no exec-timeout" command.
+
+       * vty.h (VTY_TIMEOUT_DEFAULT): Change default value from 300 to
+       600.
+
+2000-03-31  Jochen Friedrich <jochen@scram.de>
+
+       * smux.h (SMUX_CLOSE): The SMUX_CLOSE PDU is implicit integer, so
+       it is a primitive encoding and not constructed.
+
+2000-03-28  Toshiaki Takada  <takada@zebra.org>
+
+       * memory.[ch] (enum): Add MTYPE_OSPF_EXTERNAL_INFO.
+
+2000-03-26  Love <lha@s3.kth.se>
+
+       * zclient.c (zclient_read): Add nbytes size check for
+       ZEBRA_HEADER_SIZE.  Check return value of steam_read ().
+
+2000-03-26  Rick Payne <rickp@rossfell.co.uk>
+
+       * routemap.c: Add flexible route-map commands such as on-match
+       next, on-match goto N.
+
+       * routemap.h: Likewise
+
+2000-03-23  Adrian Bool <aid@u.net.uk>
+
+       * command.c (config_log_trap): Add new command "log trap
+       PRIORITY".
+
+2000-03-14  Toshiaki Takada  <takada@zebra.org>
+
+       * memory.c (struct memory_list): Add Link List and Link Node
+       to view.
+       
+       * memory.h (enum): Remove MTYPE_OSPF_EXTERNAL_ROUTE.
+       
+2000-01-20  Hideto Yamakawa <hideto.yamakawa@soliton.co.jp>
+
+       * str.c (snprintf): Fix bug of calling sprintf instead of
+       vsprintf.
+
+2000-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_RIP_PEER.
+
+2000-01-15  Toshiaki Takada  <takada@zebra.org>
+
+       * memory.h (enum): Add MTYPE_OSPF_CRYPT_KEY.
+
+2000-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add MASC_NODE for masc.
+
+2000-01-09  Wang Jianliang <wangjl@soim.net>
+
+       * routemap.c (route_map_index_add): When route_map_index is not
+       empty and insert new item at the head, it can cause core dump.
+       Fix "if (index == map->head)" to "if (point == map->head).
+       (route_map_add_set): If there is an old set command, override old
+       set command with new one.
+       (route_map_index_delete): Use while() instead of for for() for
+       logical correctness.
+
+1999-12-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_BGP_STATIC.
+
+1999-12-23  Alex Zinin <zinin@amt.ru>
+       * zebra.h, zclient.*: dynamic int up/down message
+       support
+
+1999-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * thread.c (thread_cancel_event): Add a function for clean up
+       events.
+
+1999-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * dropline.c: Delete file.
+       dropline.h: Linewise.   
+
+1999-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c (access_list_filter_delete): Wrong pointer
+       access->master was pointed out after access is freed.  I store
+       master value at the beginning of the function.
+
+1999-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (exec_timeout): Change of VTY timeout affect to current
+       VTY connection.
+       (vty_accept): Instead of immediate exit() return -1.
+
+1999-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_configure_lock): Configuration lock function added.
+       Only one VTY can use CONFI_NODE at the same time.
+
+       * log.c: Delete zvlog_* functions.  Now zlog_* does the same
+       thing.
+
+       * log.c (log_init): Function removed.
+       (log_close): Likewise.
+       (log_flush): Likewise.
+       (log_open): Likewise.
+
+       * vty.c (terminal_monitor): Add new command.
+       (no_terminal_monitor): Likewise.
+
+       * log.c (old_log): Function removed.
+       (old_log2): Likewise.
+       (old_log_warn): Likewise.
+
+1999-12-04  Toshiaki Takada  <takada@zebra.org>
+
+       * command.c (cmd_ipv6_match): New function added.
+       (cmd_ipv6_prefix_match): Likewise.
+       
+1999-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_ipv6_match): 
+
+       * table.c: Delete #ifdef HAVE_MBGPV4.
+
+       * prefix.h (struct prefix): Add safi member.
+       (struct prefix_ipv4): Likewise.
+       (struct prefix_ipv6): Likewise.
+
+1999-12-04  Rumen Svobodnikov <rumen@linux.tu-varna.acad.bg>
+
+       * memory.c (struct mstat): Revert to support MEMORY_LOG.
+
+1999-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Bump up to 0.81c for testing new kernel codes.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * thread.h (struct thread): Pthread support is disabled all
+       platform.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+       * Include <limits.h> and <strings.h> under SUNOS_5.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * sockunion.c (in6addr_cmp): Enclosed by #define HAVE_IPV6
+1999-11-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add BGP_IPV4_NODE and BGP_IPV6_NODE.
+
+1999-11-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (disable): Add `disable' command.
+
+1999-11-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * plist.c (vty_prefix_list_install): Add any check.
+
+1999-11-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add DUMP_NODE.
+
+1999-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * smux.c: Change default SMUX oid to compatible with gated.
+
+1999-10-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_rmap.c: New file added.
+
+       * if_rmap.h: New file added.
+
+1999-10-29  Alex Zinin  <zinin@amt.ru>
+
+       * hash.c: add hash_free() function
+
+1999-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * hash.c (hash_clean): Add clean function.
+
+       * plist.c (prefix_list_reset): Add reset function.
+
+       * filter.c (access_list_reset): Add reset function.
+
+1999-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * client.c: Merged with zclient.c.
+       * client.h: Merged with zclient.h.
+
+1999-10-15  Jordan Mendelson <jordy@wserv.com>
+
+       * md5.c: Imported from GNU C Library.
+       * md5-gnu.h: Likewise.
+
+1999-10-15  Jochen Friedrich <jochen@scram.de>
+
+       * smux.c (smux_getresp_send): SMUX_GETRSP codes improvement.
+
+1999-10-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * smux.h: New file added.
+
+       * snmp.c: Rename to smux.c.
+
+1999-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_execute_command_strict): Filter ambious commands.
+       (cmd_filter_by_string): Change to return enum match_type.
+
+1999-10-01  Toshiaki Takada  <takada@zebra.org>
+
+       * vty.c (vty_describe_fold): New function which does VTY
+       description line fold.
+       * vty.c (vty_describe_command): Set description column.
+
+1999-09-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * plist.c (prefix_list_init_ipv4): VTY user interface is improved.
+
+1999-09-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_filter_by_string): Fix bug of CMD_IPV4 and
+       CMD_IPV4_PREFIX check.  Both return type must be exact_match.
+
+1999-09-24  Toshiaki Takada  <takada@zebra.org>
+
+       * command.c (cmd_filter_by_completion),
+       (is_cmd_ambiguous): Check IPv4 address, IPv4 prefix and range 
+       parameter matches range.
+
+1999-09-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.c (route_map_apply): Returm RM_DENYMATCH when no match
+       is performed.
+
+1999-09-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_read): Control-C stop VTY_MORE mode.
+
+1999-09-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add ACCESS_IPV6_NODE and
+       PREFIX_IPV6_NODE.
+
+       * distribute.h: New file added.
+
+       * command.h (node_type ): Delete DISTRIBUTE_NODE.
+
+1999-09-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_terminate_all): New function added for reload
+       support.
+
+1999-09-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add new type MTYPE_OSPF_EXTERNAL_ROUTE.
+
+1999-08-31  Janos Farkas <chexum@shadow.banki.hu>
+
+       * vty.c (vty_read): Handle also 0x7f (alt-backspace), just like
+       esc-ctrl-h (delete word backwards).
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.h: Add if_nametoindex for NRL.
+
+1999-08-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c (if_create): New function.
+
+1999-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * snmp.c: New file.
+
+1999-08-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * stream.c (stream_put): stream_memcpy () is changed to stream_put
+       ().  stream_get () is added.
+
+1999-08-18  Toshiaki Takada  <takada@zebra.org>
+
+       * memory.h (enum): Add MTYPE_OSPF_LSA_DATA.
+       
+1999-08-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * table.c (route_table_finish): add function frees table.
+
+1999-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_RTADV_PREFIX.
+
+1999-08-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.h (struct interface ): hw_address, hw_address_len added.
+
+1999-08-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.h (struct interface ): Change structure member if_data to
+       info, index to ifindex.
+
+1999-08-08  Rick Payne <rickp@rossfell.co.uk>
+
+       * routemap.c: Multi protocol route-map modification.
+
+       * routemap.c (route_map_apply): Route match process bug is fixed.
+
+1999-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * thread.c (thread_fetch): When signal comes, goto retry point.
+
+1999-08-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: Add sockopt.c and sockopt.h
+       * sockopt.c: New file.
+       * sockopt.h: New file.
+       
+1999-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h (ZEBRA_VERSION): Release zebra-0.75
+
+1999-08-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_RIPNG_AGGREGATE.
+
+1999-07-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * sockunion.h: Add sockunion_getpeername ().
+
+1999-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Release zebra-0.74
+
+1999-07-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (struct host): Delete lines from struct host.  Add
+       lines to struct vty.
+
+       * command.c: Delete `lines LINES'.  Terminal display line settings
+       should be done by `terminal length' command.
+
+1999-07-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): MTYPE_OSPF_PATH are added.
+
+1999-07-22  Toshiaki Takada  <takada@zebra.org>
+
+       * memory.h (enum): MTYPE_OSPF_NEXTHOP is added.
+
+1999-07-21  Toshiaki Takada  <takada@zebra.org>
+
+       * linklist.c (list_add_node_prev), (list_add_node_next),
+       (list_add_list): New function added.
+
+       * table.c (route_table_free): New function added.
+       
+1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * plist.c (config_write_prefix): Set write flag when configuration
+       is written.
+
+1999-07-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp> 
+
+       * prefix.c : prefix_cmp() added. change apply_mask() to
+       apply_mask_ipv4(), and new apply_mask() added.
+
+1999-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * prefix.c (prefix2str): append prefixlen.
+
+1999-07-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (config_terminal): Change "config terminal" to
+       "configure terminal".  Reported by Georg Hitsch
+       <georg@atnet.at>.
+       (config_terminal_length): `terminal length <0-512>' is added.  At
+       this moment this command is only usef for vty interface.
+       Suggested by Georg Hitsch <georg@atnet.at>.
+
+1999-07-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.c (rulecmp): Add wrapper function of strcmp.
+
+1999-07-08  Rick Payne <rickp@rossfell.co.uk>
+
+       * sockunion.c (inet_aton): Fix bug of inet_aton.
+
+1999-07-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h (ZEBRA_VERSION): Start zebra-0.73
+
+1999-07-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Bump up to 0.72.
+
+1999-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (install_default): New function for install default
+       commands to the node.
+
+       * memory.h (enum): MTYPE_NEXTHOP is added.
+
+1999-07-01    <kunihiro@zebra.org>
+
+       * command.c (no_banner_motd): `no banner motd' command added.
+
+1999-06-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * regex.c: Update to glibc-2.1.1's posix/regex.c
+
+       * regex-gnu.h: Update to glibc-2.1.1's posix/regex.h
+
+       * prefix.h (IPV4_ADDR_SAME): Macro added.
+       (IPV6_ADDR_SAME): Likewise.
+
+1999-06-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_OSPF_VERTEX
+
+       * version.h: Bump up to 0.71.
+
+       * vty.c (vty_serv_sock_addrinfo): Use addrinfo function to bind
+       VTY socket when IPv6 is enabled.
+
+1999-06-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_serv_sock): Change vty_serv_sock determine which
+       address family to bind.
+
+       * command.c: Add quit command.
+
+1999-06-26  NOGUCHI kay <kay@dti.ad.jp>
+
+       * vty.c (vty_read_config): Fix bug of configuration file path
+       detection.
+
+1999-06-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Bump up to 0.70.
+
+1999-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * buffer.h (GETL): Remove GETL macro.
+
+       * version.h: Bump up to 0.69.
+
+1999-06-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c (connected_add): Commented out connected_log.
+
+1999-06-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (struct cmd_element ): strvec and descvec is combined
+       into newstrvec.
+
+       * command.c (desc_make): Function removed.
+       (desc_next): Function removed.
+
+       * command.h (struct cmd_element ): docvec is removed from struct
+       cmd_element.
+
+1999-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_execute_command): Remove command NULL check.
+
+       * command.h (struct cmd_element ): Add newstrvec entry to struct
+       cmd_element.
+       (DEFUN2): DEFUN2 macro is removed.  DEFUN is extended to support
+       (a|b|c) statement.
+       (DESC): DESC macro is removed.
+
+       * vty.c (vty_complete_command): When return value is
+       CMD_ERR_NO_MATCH, don't display error message.
+
+1999-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * table.c (route_next_until): New function.
+
+       * version.h: Bump up to 0.68.
+
+1999-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_close): Free vty->buf when vty is closed.
+
+       * memory.h (enum): Add MTYPE_COMMUNITY_ENTRY and
+       MTYPE_COMMUNITY_LIST.
+
+       * vty.h (struct vty ): Change buf from static length buffer to
+       variable length buffer.
+
+       * vty.c (vty_ensure): New function added.
+       
+1999-06-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add COMMUNITY_LIST_NODE.
+
+       * command.c (config_enable_password): Freeing host.enable bug is
+       fixed.
+       (config_enable_password): Add argc count check.
+
+1999-05-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h: Bump up to 0.67.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (zencrypt): New function for encrypt password.
+
+       * command.h (struct host): Add password_encrypt and
+       enable_encrypt.
+
+1999-05-30  Jochen Friedrich <jochen@scram.de>
+
+       * command.h (struct host): New member encrypt is added for
+       encrypted password.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c: Remove all_digit_check function.  Instead use all_digit.
+
+       * prefix.c (all_digit): New function for checking string is made
+       from digit character.
+
+1999-05-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (libzebra_a_SOURCES): Add zclient.c.
+       (noinst_HEADERS): Add zclient.h
+
+       * zclient.[ch]: New file for zebra client routine.
+
+       * memory.h (enum): Add MTYPE_ZEBRA.
+
+1999-05-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h (ZEBRA_VERSION): Update to 0.66.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * buffer.h (GETC,GETW): Macro deleted.
+
+1999-05-15  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * prefix.h (IPV4_NET0, IPV4_NET127): Macro added.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (service_advanced_vty): New command added.
+       (no_service_advanced_vty): Likewise.
+
+1999-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_auth): If advanced flag is set and enable password is
+       not set, directly login to the ENABLE_NODE.  This feature is
+       originally designed and implemented by Stephen R. van den Berg
+       <srb@cuci.nl>.
+
+       * command.h (host): Add advanced flag to struct host for advanced
+       vty terminal interface.
+
+       * version.h (ZEBRA_VERSION): Update to 0.65 for next beta release.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+       * command.h (node_type ): Add TABLE_NODE.
+       
+       * vty.c (vty_telnet_option): Check host.lines value.
+
+       * command.c (config_lines): DEFUN for 'lines LINES' command.
+
+       * zebra.h: Include <sys/utsname.h> for uname().
+       (RT_TABLE_MAIN): Defined as 0 if OS does not support multiple
+       routing table.
+
+       * vty.c (vty_auth): Directly login to the ENABLE_NODE when enable
+       password is not set.
+       (vty_prompt): Get machine's hostname when hostname is not set.
+
+1999-05-11  James Willard <james@whispering.org>
+
+       * command.c (config_exit): Close connection when `exit' command is
+       executed at ENABLE_NODE.
+
+1999-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_stop_input): `C-c' key change node to ENABLE_NODE.
+
+       * command.c (cmd_execute_command_strict): Matched command size
+       check added.
+       (cmd_make_desc_line): New function for DEFUN2.
+
+       * command.h (struct cmd_element ): Add descsize.
+
+1999-05-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (struct cmd_element ): Remame descvec to docvec.
+       (struct cmd_element ): Add descvec for new description system.
+
+       * command.c (desc_make): Check cmd->descvec.
+
+1999-05-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTYPE_CLUSTER, MTYPE_CLUSTER_VAL.
+
+1999-05-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h (ZEBRA_VERSION): Bump up to 0.64 for next beta
+       release.
+
+1999-05-04  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * linklist.c (list_delete_all_node): bug fix. 
+       previous code loses current position when node
+       is deleted.
+
+1999-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (DESC): Macro added.
+       (struct cmd_element2): Delete struct cmd_element2.
+
+       * plist.c (prefix_list): Sequential number option check is added.
+
+1999-05-02  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * log.c (zvlog_{debug,info,notice,warn,err}): have been
+       added. now we can log both console and file, but still 
+       need some fix about config write.
+
+1999-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * log.c (zvlog_debug): Fix yasu's change.
+
+1999-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * plist.c (prefix_list): Fix typo.
+
+1999-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Set version to 0.63 for first beta package.
+
+1999-04-27  Carlos Barcenilla <barce@frlp.utn.edu.ar>
+
+       * prefix.c (str2prefix_ipv4): Fix prefix length check.
+       (str2prefix_ipv6): Likewise.
+
+1999-04-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): Add MTPYE_PREFIX_LIST and
+       MTYPE_PREFIX_LIST_ENTRY.
+
+       * command.h (node_type ): Add PREFIX_NODE.
+
+1999-04-25  Carlos Barcenilla <barce@frlp.utn.edu.ar>
+
+       * command.c: ALIAS (config_write_memory_cmd) and ALIAS
+       (copy_runningconfig_startupconfig_cmd) is added.
+
+       * table.c (route_node_lookup): Unused match variable deletion.
+
+1999-04-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (libzebra_a_SOURCES): plist.c added.
+       (noinst_HEADERS): plist.h added.
+
+       * plist.c, plist.h: New file added.
+
+       * memory.h (enum): Rename MTYPE_AS_PASN to MTYPE_AS_STR.
+       * memory.c: Likewise.
+
+1999-04-19  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * command.c (show_version): `show version' command added.
+
+1999-04-19  Kunihiro Ishiguro <kunihiro@zebra.org>
+
+       * prefix.c (str2prefix_ipv6): Prefix length overflow check.
+
+1999-04-19  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * prefix.c (str2prefix_ipv4): Prefix length overflow check.
+
+1999-04-19  Alex Bligh <amb@gxn.net>
+
+       * prefix.c (sockunion2hostprefix): Function added.
+       (sockunion2prefix): Address family was not set.  Now it is set.
+       
+       * vty.c: VTY access-class command is added.
+
+1999-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.c: Change xmalloc to zmalloc.  xcalloc, xrealloc, xfree,
+       xstrdup are likewise.
+
+1999-04-18  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * thread.c: Add thread_execute for other routing daemon.
+       OSPF tasks need to be generated by "sheduled" and "executed".
+
+1999-04-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * buffer.c: Rewrite buffer_write and buffer_flush related
+       functions for fixing bugs.  Reason of the problem and fix is
+       suggested by Alex Bligh <amb@gxn.net>.
+       
+1999-04-12  Alex Bligh <amb@gxn.net>
+
+       * command.c (cmd_entry_function_descr): Added for variable
+       argument help display.
+
+1999-04-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * regex.c, regex-gnu.h: Imported from GNU sed-3.02 distribution.
+
+1999-03-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * stream.c: stream_fifo_free bug is fixed.
+
+1999-03-19  Toshiaki Takada  <takada@zebra.org>
+
+       * stream.c (stream_strncpy): Added for getting any length bytes
+       from stream.
+
+1999-03-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * version.h (ZEBRA_BUG_ADDRESS): New macro added.
+
+1999-03-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * buffer.c (buffer_flush_window): If ep is same as buffer's size
+       length and lp is overrun one octet.
+
+1999-03-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.h: add VTY's timeout function.
+
+1999-03-05    <kunihiro@zebra.org>
+
+       * command.h (node_type ): Add OSPF6_node.
+
+1999-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h: Check HAVE_SYS_SELECT_H when include <sys/select.h>
+
+1999-03-03  Jeroen Ruigrok/Asmodai <asmodai@wxs.nl>
+
+       * zebra.h: Include <net/if_var.h> if it exists.
+
+1999-03-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * getopt.[ch],getopt1.c: Sync with glibc-2.1.
+
+       * log.c (zlog): Tempolary ZLOG_STDOUT feature added.
+
+       * command.h: Include vector.h and vty.h
+
+1999-02-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.h (struct route_map_rule_cmd): Add prefix arguemnt.
+
+       * routemap.c (route_map_apply_index): Add prefix argument.
+       (route_map_apply): Likewise.
+
+       * memory.h (enum): Add MTYPE_ROUTE_MAP_COMPILED.
+
+       * stream.c: Add stream_fifo related functions.
+
+1999-02-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * daemon.c: Return integer value.  File descriptor close is added.
+
+       * memory.h (enum): add MTYPE_OSPF_LSA.
+
+1999-02-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rsh.c: Remove empty file.
+
+1999-02-22    <kunihiro@zebra.org>
+
+       * routemap.c: Add add/delete hook to route_map_master.
+
+1999-02-19  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * str.[ch] added to supply wrappers for snprintf(), strlcat() and
+       strlcpy on system without these.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * syslog support added
+
+1999-02-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c (access_list_add_hook): added for hook function management.
+       * filter.c (access_list_delete_hook): Likewise.
+
+1999-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * stream.c: New file.
+       * stream.h: New file.
+       * Divide stream related fucntions from buffer.[ch] into stream.[ch].
+       
+1999-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * memory.h (enum): add MTYPE_STREAM, MTYPE_STREAM_DATA
+
+       * buffer.c (stream_new): Set MTYPE_STREAM to XMALLOC argument.
+
+1998-12-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * routemap.c: route_map_index_delete() added.
+
+1998-12-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * buffer.c (buffer_empty): check cp instead of sp.
+
+1998-12-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * radix.[ch]: Deleted.
+
+1998-12-15  Magnus Ahltorp <map@stacken.kth.se>
+
+       * buffer.c: Prototype fixes.
+       * prefix.c: Likewise.
+       * sockunion.c: Likewise.
+       * sockunion.h: Likewise.
+
+1998-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_read): DELETE key works as vty_delete_char.
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * log.c (time_print): chane %y to %Y.
+
+1998-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * distribute.c: new file.
+
+1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c: Remove all of struct prefix_{ipv4,ipv6} and add
+       complete support of IPv6 access list.
+
+       * command.c (config_write_element): function delete.
+       (config_write_host): function add.  password and enable password
+       isn't printed to vty interface.
+
+1998-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.c: Change prefix_ipv4 to prefix and add support of
+       prefix_ipv6 filtering.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6 inet6-apps
+       header includes.
+
+1998-12-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * log.c (log_flush): fix function name typo.
+
+1998-12-04  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * memory.h: OSPF memory type is added.
+
+1998-11-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (sort_node): add sort_node() for pretty printing of
+       command on vty interface.
+       (config_password): delete the restriction of charaster of password
+       string.
+
+1998-09-05  Kunihiro Ishiguro  <kunihiro@debian.zebra.org>
+
+       * prefix.c (prefix_ipv4_any): add prefix_ipv4_any().
+
+1998-08-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * network.h: New file.
+
+1998-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_will_echo): function name change from vty_off_echo.
+
+1998-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * buffer.h: add PUTC,PUTW,PUTL macros.
+
+1998-07-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * route.[ch]: renamed to prefix.[ch]
+
+1998-06-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * prefix_in, prefix_in6 is replaced by prefix_ipv4, prefix_ipv6.
+
+       * Makefile.am: @INCLUDES@ is deleted from INCLUDES.
+
+1998-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * host.[ch]: merged with command.[ch]
+
+1998-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (libzebra_a_SOURCES): add route.c to libzebra_a_SOURCES.
+
+1998-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * route.c (str2prefix): str2prefix () is gone.
+
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_read_config): change CONDIR to SYSCONFDIR.
+
+       * .cvsignore: add file.
+
+       * memory.c (xerror): add arguent `type' and `size'.
+
+       * socket.c: deleted.
+
+1998-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vector.c: malloc,free,realloc -> XMALLOC,XFREE,XREALLOC.
+       * linklist.c: same as above.
+
+1998-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * filter.[ch]: added.
+
+1998-04-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (config_who): return CMD_SUCCESS
+
+1998-04-01  Jochen Friedrich <jochen@scram.de>
+
+       * table.c (route_dump_node): route_dump_node is IPv6 specific
+       function so move #ifdef to the end of route_dump_node ().
+
+1998-03-05  "Hannes R. Boehm" <hannes@boehm.org>
+
+       * if.c: DEFUN(interface_desc) added.
+
+1998-03-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c: separated from ripd/rip_interface.c
+
+1998-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * thread.[ch] : added.
+
+1998-02-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_delete_char): fix size bug.
+       (vty_backward_pure_word): function added.
+       (vty_read): ESC + 'f' perform vty_forward_word.
+       (vty_read): ESC + 'b' perform vty_backward_word.
+
+1998-02-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * radix.c (radix_lookup_rt): add mask check.
+       (radix_delete_duproute): add mask check.
+
+1998-02-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (config_write_file): fix vty -> file_vty.
+
+1998-02-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_filter_ambiguous): add complex type treatment.
+
+1998-02-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_time_print): function added.
+       (vty_complete_command): now [...] element isn't shown by completion.
+
+1998-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c : change from cmd_install_node() to install_node().
+
+1998-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * route.[ch]: struct rt{} is replaced by struct prefix{}.
+
+1998-01-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c (cmd_execute_command): check command length.
+
+       * timer.c (zebra_timer_set): add zebra_timer_set.
+
+1998-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.h (node_type ): add ZEBRA_NODE.
+
+       * command.c (config_exit): add RIP_NODE.
+       (config_write_file): add RIP_NODE.
+
+1998-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * print_version.c (print_version): Now Copyright is 1996-1998.
+
+       * sockunion.c (sockunion_log): moved from ../zebra/route.c
+
+1997-12-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * host.c (config_logfile): change 'log PATH' to 'logfile PATH'.
+
+       * sockunion.c (sockunion_sameprefix): add same prefix for
+       sockunion.
+
+1997-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * radix.[ch] : are moved from ../zebra directroy.
+       
+       * command.c (config_from_file): if command execution failed down
+       level to CONFIG_NODE.
+
+       * host.c: config_log function which enable 'log FILENAME' command.
+
+1997-12-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c: add vty_transpose_chars ().  Now you can use '^T' to
+       transpose character.
+
+       * command.c: cmd_cmdsize add, this is useful to check incomplete
+       command.
+
+1997-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * fd.h: add family for address family
+
+1997-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.o
+       * vty.o
+       * host.o    is moved from ../zebra
+
+1997-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * make library directory.
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644 (file)
index 0000000..81f1e41
--- /dev/null
@@ -0,0 +1,29 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+
+noinst_LIBRARIES = libzebra.a
+
+libzebra_a_SOURCES = \
+       version.c network.c pid_output.c getopt.c getopt1.c daemon.c \
+       print_version.c checksum.c vector.c linklist.c vty.c command.c \
+       sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
+       filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
+       zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c
+
+libzebra_a_DEPENDENCIES = @LIB_REGEX@
+
+libzebra_a_LIBADD = @LIB_REGEX@
+
+noinst_HEADERS = \
+       buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \
+       memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
+       str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
+       plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h
+
+EXTRA_DIST = regex.c regex-gnu.h
+
+version.c: Makefile
+       echo '' >version.c
+       echo 'char *host_name = "$(host_alias)";' >>version.c
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644 (file)
index 0000000..d821f23
--- /dev/null
@@ -0,0 +1,469 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+
+noinst_LIBRARIES = libzebra.a
+
+libzebra_a_SOURCES = \
+       version.c network.c pid_output.c getopt.c getopt1.c daemon.c \
+       print_version.c checksum.c vector.c linklist.c vty.c command.c \
+       sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
+       filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
+       zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c
+
+
+libzebra_a_DEPENDENCIES = @LIB_REGEX@
+
+libzebra_a_LIBADD = @LIB_REGEX@
+
+noinst_HEADERS = \
+       buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \
+       memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
+       str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
+       plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h
+
+
+EXTRA_DIST = regex.c regex-gnu.h
+subdir = lib
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libzebra_a_AR = $(AR) cru
+am_libzebra_a_OBJECTS = version.$(OBJEXT) network.$(OBJEXT) \
+       pid_output.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
+       daemon.$(OBJEXT) print_version.$(OBJEXT) checksum.$(OBJEXT) \
+       vector.$(OBJEXT) linklist.$(OBJEXT) vty.$(OBJEXT) \
+       command.$(OBJEXT) sockunion.$(OBJEXT) prefix.$(OBJEXT) \
+       thread.$(OBJEXT) if.$(OBJEXT) memory.$(OBJEXT) buffer.$(OBJEXT) \
+       table.$(OBJEXT) hash.$(OBJEXT) filter.$(OBJEXT) \
+       routemap.$(OBJEXT) distribute.$(OBJEXT) stream.$(OBJEXT) \
+       str.$(OBJEXT) log.$(OBJEXT) plist.$(OBJEXT) zclient.$(OBJEXT) \
+       sockopt.$(OBJEXT) smux.$(OBJEXT) md5.$(OBJEXT) \
+       if_rmap.$(OBJEXT) keychain.$(OBJEXT)
+libzebra_a_OBJECTS = $(am_libzebra_a_OBJECTS)
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/buffer.Po ./$(DEPDIR)/checksum.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/command.Po ./$(DEPDIR)/daemon.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/distribute.Po ./$(DEPDIR)/filter.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/getopt.Po ./$(DEPDIR)/getopt1.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/hash.Po ./$(DEPDIR)/if.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/if_rmap.Po ./$(DEPDIR)/keychain.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/linklist.Po ./$(DEPDIR)/log.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/md5.Po ./$(DEPDIR)/memory.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/network.Po ./$(DEPDIR)/pid_output.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/plist.Po ./$(DEPDIR)/prefix.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/print_version.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/routemap.Po ./$(DEPDIR)/smux.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/sockopt.Po ./$(DEPDIR)/sockunion.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/str.Po ./$(DEPDIR)/stream.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/table.Po ./$(DEPDIR)/thread.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/vector.Po ./$(DEPDIR)/version.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/vty.Po ./$(DEPDIR)/zclient.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libzebra_a_SOURCES)
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(libzebra_a_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  lib/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libzebra.a: $(libzebra_a_OBJECTS) $(libzebra_a_DEPENDENCIES) 
+       -rm -f libzebra.a
+       $(libzebra_a_AR) libzebra.a $(libzebra_a_OBJECTS) $(libzebra_a_LIBADD)
+       $(RANLIB) libzebra.a
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksum.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/distribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if_rmap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keychain.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linklist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pid_output.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prefix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print_version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smux.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockunion.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vty.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zclient.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+           dir="/$$dir"; \
+           $(mkinstalldirs) "$(distdir)$$dir"; \
+         else \
+           dir=''; \
+         fi; \
+         if test -d $$d/$$file; then \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+       distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-noinstLIBRARIES ctags distclean distclean-compile \
+       distclean-depend distclean-generic distclean-tags distdir dvi \
+       dvi-am info info-am install install-am install-data \
+       install-data-am install-exec install-exec-am install-info \
+       install-info-am install-man install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am
+
+
+version.c: Makefile
+       echo '' >version.c
+       echo 'char *host_name = "$(host_alias)";' >>version.c
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/buffer.c b/lib/buffer.c
new file mode 100644 (file)
index 0000000..de51ee3
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * Buffering of output and input. 
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "buffer.h"
+
+/* Make buffer data. */
+struct buffer_data *
+buffer_data_new (size_t size)
+{
+  struct buffer_data *d;
+
+  d = XMALLOC (MTYPE_BUFFER_DATA, sizeof (struct buffer_data));
+  memset (d, 0, sizeof (struct buffer_data));
+  d->data = XMALLOC (MTYPE_BUFFER_DATA, size);
+
+  return d;
+}
+
+void
+buffer_data_free (struct buffer_data *d)
+{
+  if (d->data)
+    XFREE (MTYPE_BUFFER_DATA, d->data);
+  XFREE (MTYPE_BUFFER_DATA, d);
+}
+
+/* Make new buffer. */
+struct buffer *
+buffer_new (size_t size)
+{
+  struct buffer *b;
+
+  b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
+  memset (b, 0, sizeof (struct buffer));
+
+  b->size = size;
+
+  return b;
+}
+
+/* Free buffer. */
+void
+buffer_free (struct buffer *b)
+{
+  struct buffer_data *d;
+  struct buffer_data *next;
+
+  d = b->head;
+  while (d)
+    {
+      next = d->next;
+      buffer_data_free (d);
+      d = next;
+    }
+
+  d = b->unused_head;
+  while (d)
+    {
+      next = d->next;
+      buffer_data_free (d);
+      d = next;
+    }
+  
+  XFREE (MTYPE_BUFFER, b);
+}
+
+/* Make string clone. */
+char *
+buffer_getstr (struct buffer *b)
+{
+  return strdup ((char *)b->head->data);
+}
+
+/* Return 1 if buffer is empty. */
+int
+buffer_empty (struct buffer *b)
+{
+  if (b->tail == NULL || b->tail->cp == b->tail->sp)
+    return 1;
+  else
+    return 0;
+}
+
+/* Clear and free all allocated data. */
+void
+buffer_reset (struct buffer *b)
+{
+  struct buffer_data *data;
+  struct buffer_data *next;
+  
+  for (data = b->head; data; data = next)
+    {
+      next = data->next;
+      buffer_data_free (data);
+    }
+  b->head = b->tail = NULL;
+  b->alloc = 0;
+  b->length = 0;
+}
+
+/* Add buffer_data to the end of buffer. */
+void
+buffer_add (struct buffer *b)
+{
+  struct buffer_data *d;
+
+  d = buffer_data_new (b->size);
+
+  if (b->tail == NULL)
+    {
+      d->prev = NULL;
+      d->next = NULL;
+      b->head = d;
+      b->tail = d;
+    }
+  else
+    {
+      d->prev = b->tail;
+      d->next = NULL;
+
+      b->tail->next = d;
+      b->tail = d;
+    }
+
+  b->alloc++;
+}
+
+/* Write data to buffer. */
+int
+buffer_write (struct buffer *b, u_char *ptr, size_t size)
+{
+  struct buffer_data *data;
+
+  data = b->tail;
+  b->length += size;
+
+  /* We use even last one byte of data buffer. */
+  while (size)    
+    {
+      /* If there is no data buffer add it. */
+      if (data == NULL || data->cp == b->size)
+       {
+         buffer_add (b);
+         data = b->tail;
+       }
+
+      /* Last data. */
+      if (size <= (b->size - data->cp))
+       {
+         memcpy ((data->data + data->cp), ptr, size);
+
+         data->cp += size;
+         size = 0;
+       }
+      else
+       {
+         memcpy ((data->data + data->cp), ptr, (b->size - data->cp));
+
+         size -= (b->size - data->cp);
+         ptr += (b->size - data->cp);
+
+         data->cp = b->size;
+       }
+    }
+  return 1;
+}
+
+/* Insert character into the buffer. */
+int
+buffer_putc (struct buffer *b, u_char c)
+{
+  buffer_write (b, &c, 1);
+  return 1;
+}
+
+/* Insert word (2 octets) into ther buffer. */
+int
+buffer_putw (struct buffer *b, u_short c)
+{
+  buffer_write (b, (char *)&c, 2);
+  return 1;
+}
+
+/* Put string to the buffer. */
+int
+buffer_putstr (struct buffer *b, u_char *c)
+{
+  size_t size;
+
+  size = strlen ((char *)c);
+  buffer_write (b, c, size);
+  return 1;
+}
+
+/* Flush specified size to the fd. */
+void
+buffer_flush (struct buffer *b, int fd, size_t size)
+{
+  int iov_index;
+  struct iovec *iovec;
+  struct buffer_data *data;
+  struct buffer_data *out;
+  struct buffer_data *next;
+
+  iovec = malloc (sizeof (struct iovec) * b->alloc);
+  iov_index = 0;
+
+  for (data = b->head; data; data = data->next)
+    {
+      iovec[iov_index].iov_base = (char *)(data->data + data->sp);
+
+      if (size <= (data->cp - data->sp))
+       {
+         iovec[iov_index++].iov_len = size;
+         data->sp += size;
+         if (data->sp == data->cp)
+           data = data->next;
+         break;
+       }
+      else
+       {
+         iovec[iov_index++].iov_len = data->cp - data->sp;
+         size -= data->cp - data->sp;
+         data->sp = data->cp;
+       }
+    }
+
+  /* Write buffer to the fd. */
+  writev (fd, iovec, iov_index);
+
+  /* Free printed buffer data. */
+  for (out = b->head; out && out != data; out = next)
+    {
+      next = out->next;
+      if (next)
+       next->prev = NULL;
+      else
+       b->tail = next;
+      b->head = next;
+
+      buffer_data_free (out);
+      b->alloc--;
+    }
+
+  free (iovec);
+}
+
+/* Flush all buffer to the fd. */
+int
+buffer_flush_all (struct buffer *b, int fd)
+{
+  int ret;
+  struct buffer_data *d;
+  int iov_index;
+  struct iovec *iovec;
+
+  if (buffer_empty (b))
+    return 0;
+
+  iovec = malloc (sizeof (struct iovec) * b->alloc);
+  iov_index = 0;
+
+  for (d = b->head; d; d = d->next)
+    {
+      iovec[iov_index].iov_base = (char *)(d->data + d->sp);
+      iovec[iov_index].iov_len = d->cp - d->sp;
+      iov_index++;
+    }
+  ret = writev (fd, iovec, iov_index);
+
+  free (iovec);
+
+  buffer_reset (b);
+
+  return ret;
+}
+
+/* Flush all buffer to the fd. */
+int
+buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
+                     int no_more_flag)
+{
+  int nbytes;
+  int iov_index;
+  struct iovec *iov;
+  struct iovec small_iov[3];
+  char more[] = " --More-- ";
+  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+                  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+                  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+  struct buffer_data *data;
+  struct buffer_data *out;
+  struct buffer_data *next;
+
+  /* For erase and more data add two to b's buffer_data count.*/
+  if (b->alloc == 1)
+    iov = small_iov;
+  else
+    iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
+
+  data = b->head;
+  iov_index = 0;
+
+  /* Previously print out is performed. */
+  if (erase_flag)
+    {
+      iov[iov_index].iov_base = erase;
+      iov[iov_index].iov_len = sizeof erase;
+      iov_index++;
+    }
+
+  /* Output data. */
+  for (data = b->head; data; data = data->next)
+    {
+      iov[iov_index].iov_base = (char *)(data->data + data->sp);
+      iov[iov_index].iov_len = data->cp - data->sp;
+      iov_index++;
+    }
+
+  /* In case of `more' display need. */
+  if (! buffer_empty (b) && !no_more_flag)
+    {
+      iov[iov_index].iov_base = more;
+      iov[iov_index].iov_len = sizeof more;
+      iov_index++;
+    }
+
+  /* We use write or writev*/
+  nbytes = writev (fd, iov, iov_index);
+
+  /* Error treatment. */
+  if (nbytes < 0)
+    {
+      if (errno == EINTR)
+       ;
+      if (errno == EWOULDBLOCK)
+       ;
+    }
+
+  /* Free printed buffer data. */
+  for (out = b->head; out && out != data; out = next)
+    {
+      next = out->next;
+      if (next)
+       next->prev = NULL;
+      else
+       b->tail = next;
+      b->head = next;
+
+      buffer_data_free (out);
+      b->alloc--;
+    }
+
+  if (iov != small_iov)
+    XFREE (MTYPE_TMP, iov);
+
+  return nbytes;
+}
+
+/* Flush buffer to the file descriptor.  Mainly used from vty
+   interface. */
+int
+buffer_flush_vty (struct buffer *b, int fd, int size, 
+                 int erase_flag, int no_more_flag)
+{
+  int nbytes;
+  int iov_index;
+  struct iovec *iov;
+  struct iovec small_iov[3];
+  char more[] = " --More-- ";
+  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+                  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+                  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+  struct buffer_data *data;
+  struct buffer_data *out;
+  struct buffer_data *next;
+
+#ifdef  IOV_MAX
+  int iov_size;
+  int total_size;
+  struct iovec *c_iov;
+  int c_nbytes;
+#endif /* IOV_MAX */
+
+  /* For erase and more data add two to b's buffer_data count.*/
+  if (b->alloc == 1)
+    iov = small_iov;
+  else
+    iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
+
+  data = b->head;
+  iov_index = 0;
+
+  /* Previously print out is performed. */
+  if (erase_flag)
+    {
+      iov[iov_index].iov_base = erase;
+      iov[iov_index].iov_len = sizeof erase;
+      iov_index++;
+    }
+
+  /* Output data. */
+  for (data = b->head; data; data = data->next)
+    {
+      iov[iov_index].iov_base = (char *)(data->data + data->sp);
+
+      if (size <= (data->cp - data->sp))
+       {
+         iov[iov_index++].iov_len = size;
+         data->sp += size;
+         if (data->sp == data->cp)
+           data = data->next;
+         break;
+       }
+      else
+       {
+         iov[iov_index++].iov_len = data->cp - data->sp;
+         size -= (data->cp - data->sp);
+         data->sp = data->cp;
+       }
+    }
+
+  /* In case of `more' display need. */
+  if (!buffer_empty (b) && !no_more_flag)
+    {
+      iov[iov_index].iov_base = more;
+      iov[iov_index].iov_len = sizeof more;
+      iov_index++;
+    }
+
+  /* We use write or writev*/
+
+#ifdef IOV_MAX
+  /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
+     example: Solaris2.6 are defined IOV_MAX size at 16.     */
+  c_iov = iov;
+  total_size = iov_index;
+  nbytes = 0;
+
+  while( total_size > 0 )
+    {
+       /* initialize write vector size at once */
+       iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
+
+       c_nbytes = writev (fd, c_iov, iov_size );
+
+       if( c_nbytes < 0 )
+         {
+           if(errno == EINTR)
+             ;
+             ;
+           if(errno == EWOULDBLOCK)
+             ;
+             ;
+           nbytes = c_nbytes;
+           break;
+
+         }
+
+        nbytes += c_nbytes;
+
+       /* move pointer io-vector */
+       c_iov += iov_size;
+       total_size -= iov_size;
+    }
+#else  /* IOV_MAX */
+   nbytes = writev (fd, iov, iov_index);
+
+  /* Error treatment. */
+  if (nbytes < 0)
+    {
+      if (errno == EINTR)
+       ;
+      if (errno == EWOULDBLOCK)
+       ;
+    }
+#endif /* IOV_MAX */
+
+  /* Free printed buffer data. */
+  for (out = b->head; out && out != data; out = next)
+    {
+      next = out->next;
+      if (next)
+       next->prev = NULL;
+      else
+       b->tail = next;
+      b->head = next;
+
+      buffer_data_free (out);
+      b->alloc--;
+    }
+
+  if (iov != small_iov)
+    XFREE (MTYPE_TMP, iov);
+
+  return nbytes;
+}
+
+/* Calculate size of outputs then flush buffer to the file
+   descriptor. */
+int
+buffer_flush_window (struct buffer *b, int fd, int width, int height, 
+                    int erase, int no_more)
+{
+  unsigned long cp;
+  unsigned long size;
+  int lp;
+  int lineno;
+  struct buffer_data *data;
+
+  if (height >= 2)
+    height--;
+
+  /* We have to calculate how many bytes should be written. */
+  lp = 0;
+  lineno = 0;
+  size = 0;
+  
+  for (data = b->head; data; data = data->next)
+    {
+      cp = data->sp;
+
+      while (cp < data->cp)
+       {
+         if (data->data[cp] == '\n' || lp == width)
+           {
+             lineno++;
+             if (lineno == height)
+               {
+                 cp++;
+                 size++;
+                 goto flush;
+               }
+             lp = 0;
+           }
+         cp++;
+         lp++;
+         size++;
+       }
+    }
+
+  /* Write data to the file descriptor. */
+ flush:
+
+  return buffer_flush_vty (b, fd, size, erase, no_more);
+}
diff --git a/lib/buffer.h b/lib/buffer.h
new file mode 100644 (file)
index 0000000..7449aa7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Buffering to output and input. 
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_BUFFER_H
+#define _ZEBRA_BUFFER_H
+
+/* Buffer master. */
+struct buffer
+{
+  /* Data list. */
+  struct buffer_data *head;
+  struct buffer_data *tail;
+
+  /* Current allocated data. */
+  unsigned long alloc;
+
+  /* Total length of buffer. */
+  unsigned long size;
+
+  /* For allocation. */
+  struct buffer_data *unused_head;
+  struct buffer_data *unused_tail;
+
+  /* Current total length of this buffer. */
+  unsigned long length;
+};
+
+/* Data container. */
+struct buffer_data
+{
+  struct buffer *parent;
+  struct buffer_data *next;
+  struct buffer_data *prev;
+
+  /* Acctual data stream. */
+  unsigned char *data;
+
+  /* Current pointer. */
+  unsigned long cp;
+
+  /* Start pointer. */
+  unsigned long sp;
+};
+
+/* Buffer prototypes. */
+struct buffer *buffer_new (size_t);
+int buffer_write (struct buffer *, u_char *, size_t);
+void buffer_free (struct buffer *);
+char *buffer_getstr (struct buffer *);
+int buffer_putc (struct buffer *, u_char);
+int buffer_putstr (struct buffer *, u_char *);
+void buffer_reset (struct buffer *);
+int buffer_flush_all (struct buffer *, int);
+int buffer_flush_vty_all (struct buffer *, int, int, int);
+int buffer_flush_window (struct buffer *, int, int, int, int, int);
+int buffer_empty (struct buffer *);
+
+#endif /* _ZEBRA_BUFFER_H */
diff --git a/lib/checksum.c b/lib/checksum.c
new file mode 100644 (file)
index 0000000..6a29cba
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Checksum routine for Internet Protocol family headers (C Version).
+ *
+ * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and
+ * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989,
+ * pp. 86-101, for additional details on computing this checksum.
+ */
+
+#include <zebra.h>
+
+int                            /* return checksum in low-order 16 bits */
+in_cksum(ptr, nbytes)
+register u_short       *ptr;
+register int           nbytes;
+{
+       register long           sum;            /* assumes long == 32 bits */
+       u_short                 oddbyte;
+       register u_short        answer;         /* assumes u_short == 16 bits */
+
+       /*
+        * Our algorithm is simple, using a 32-bit accumulator (sum),
+        * we add sequential 16-bit words to it, and at the end, fold back
+        * all the carry bits from the top 16 bits into the lower 16 bits.
+        */
+
+       sum = 0;
+       while (nbytes > 1)  {
+               sum += *ptr++;
+               nbytes -= 2;
+       }
+
+                               /* mop up an odd byte, if necessary */
+       if (nbytes == 1) {
+               oddbyte = 0;            /* make sure top half is zero */
+               *((u_char *) &oddbyte) = *(u_char *)ptr;   /* one byte only */
+               sum += oddbyte;
+       }
+
+       /*
+        * Add back carry outs from top 16 bits to low 16 bits.
+        */
+
+       sum  = (sum >> 16) + (sum & 0xffff);    /* add high-16 to low-16 */
+       sum += (sum >> 16);                     /* add carry */
+       answer = ~sum;          /* ones-complement, then truncate to 16 bits */
+       return(answer);
+}
diff --git a/lib/command.c b/lib/command.c
new file mode 100644 (file)
index 0000000..8cbecce
--- /dev/null
@@ -0,0 +1,2981 @@
+/* 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
+};
+\f
+/* 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 KEYCHAIN_NODE:
+    case MASC_NODE:
+    case RMAP_NODE:
+    case VTY_NODE:
+      vty->node = CONFIG_NODE;
+      break;
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+      vty->node = BGP_NODE;
+      break;
+    case KEYCHAIN_KEY_NODE:
+      vty->node = KEYCHAIN_NODE;
+      break;
+    default:
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+/* quit is alias of exit. */
+ALIAS (config_exit,
+       config_quit_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+       
+/* End of configuration. */
+DEFUN (config_end,
+       config_end_cmd,
+       "end",
+       "End current mode and change to enable mode.")
+{
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      /* Nothing to do. */
+      break;
+    case CONFIG_NODE:
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case BGP_NODE:
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+    case RMAP_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case KEYCHAIN_NODE:
+    case KEYCHAIN_KEY_NODE:
+    case MASC_NODE:
+    case VTY_NODE:
+      vty_config_unlock (vty);
+      vty->node = ENABLE_NODE;
+      break;
+    default:
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+/* Show version. */
+DEFUN (show_version,
+       show_version_cmd,
+       "show version",
+       SHOW_STR
+       "Displays zebra version\n")
+{
+  vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
+          host_name,
+          VTY_NEWLINE);
+  vty_out (vty, "Copyright 1996-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);
+  install_element (node, &show_running_config_cmd);
+}
+
+/* Initialize command interface. Install basic nodes and commands. */
+void
+cmd_init (int terminal)
+{
+  /* Allocate initial top vector of commands. */
+  cmdvec = vector_init (VECTOR_MIN_SIZE);
+
+  /* Default host value settings. */
+  host.name = NULL;
+  host.password = NULL;
+  host.enable = NULL;
+  host.logfile = NULL;
+  host.config = NULL;
+  host.lines = -1;
+  host.motd = default_motd;
+
+  /* Install top nodes. */
+  install_node (&view_node, NULL);
+  install_node (&enable_node, NULL);
+  install_node (&auth_node, NULL);
+  install_node (&auth_enable_node, NULL);
+  install_node (&config_node, config_write_host);
+
+  /* Each node's basic commands. */
+  install_element (VIEW_NODE, &show_version_cmd);
+  if (terminal)
+    {
+      install_element (VIEW_NODE, &config_list_cmd);
+      install_element (VIEW_NODE, &config_exit_cmd);
+      install_element (VIEW_NODE, &config_quit_cmd);
+      install_element (VIEW_NODE, &config_help_cmd);
+      install_element (VIEW_NODE, &config_enable_cmd);
+      install_element (VIEW_NODE, &config_terminal_length_cmd);
+      install_element (VIEW_NODE, &config_terminal_no_length_cmd);
+    }
+
+  if (terminal)
+    {
+      install_default (ENABLE_NODE);
+      install_element (ENABLE_NODE, &config_disable_cmd);
+      install_element (ENABLE_NODE, &config_terminal_cmd);
+      install_element (ENABLE_NODE, &copy_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/lib/command.h b/lib/command.h
new file mode 100644 (file)
index 0000000..3009b26
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Zebra configuration command interface routine
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_COMMAND_H
+#define _ZEBRA_COMMAND_H
+
+#include "vector.h"
+#include "vty.h"
+
+/* Host configuration variable */
+struct host
+{
+  /* Host name of this router. */
+  char *name;
+
+  /* Password for vty interface. */
+  char *password;
+  char *password_encrypt;
+
+  /* Enable password */
+  char *enable;
+  char *enable_encrypt;
+
+  /* System wide terminal lines. */
+  int lines;
+
+  /* Log filename. */
+  char *logfile;
+
+  /* Log stdout. */
+  u_char log_stdout;
+
+  /* Log syslog. */
+  u_char log_syslog;
+  
+  /* config file name of this host */
+  char *config;
+
+  /* Flags for services */
+  int advanced;
+  int encrypt;
+
+  /* Banner configuration. */
+  char *motd;
+};
+
+/* There are some command levels which called from command node. */
+enum node_type 
+{
+  AUTH_NODE,                   /* Authentication mode of vty interface. */
+  VIEW_NODE,                   /* View node. Default mode of vty interface. */
+  AUTH_ENABLE_NODE,            /* Authentication mode for change enable. */
+  ENABLE_NODE,                 /* Enable node. */
+  CONFIG_NODE,                 /* Config node. Default mode of config file. */
+  DEBUG_NODE,                  /* Debug node. */
+  AAA_NODE,                    /* AAA node. */
+  KEYCHAIN_NODE,               /* Key-chain node. */
+  KEYCHAIN_KEY_NODE,           /* Key-chain key node. */
+  INTERFACE_NODE,              /* Interface mode node. */
+  ZEBRA_NODE,                  /* zebra connection node. */
+  TABLE_NODE,                  /* rtm_table selection node. */
+  RIP_NODE,                    /* RIP protocol mode node. */ 
+  RIPNG_NODE,                  /* RIPng protocol mode node. */
+  BGP_NODE,                    /* BGP protocol mode which includes BGP4+ */
+  BGP_VPNV4_NODE,              /* BGP MPLS-VPN PE exchange. */
+  BGP_IPV4_NODE,               /* BGP IPv4 unicast address family.  */
+  BGP_IPV4M_NODE,              /* BGP IPv4 multicast address family.  */
+  BGP_IPV6_NODE,               /* BGP IPv6 address family */
+  OSPF_NODE,                   /* OSPF protocol mode */
+  OSPF6_NODE,                  /* OSPF protocol for IPv6 mode */
+  MASC_NODE,                   /* MASC for multicast.  */
+  IRDP_NODE,                   /* ICMP Router Discovery Protocol mode. */ 
+  IP_NODE,                     /* Static ip route node. */
+  ACCESS_NODE,                 /* Access list node. */
+  PREFIX_NODE,                 /* Prefix list node. */
+  ACCESS_IPV6_NODE,            /* Access list node. */
+  PREFIX_IPV6_NODE,            /* Prefix list node. */
+  AS_LIST_NODE,                        /* AS list node. */
+  COMMUNITY_LIST_NODE,         /* Community list node. */
+  RMAP_NODE,                   /* Route map node. */
+  SMUX_NODE,                   /* SNMP configuration node. */
+  DUMP_NODE,                   /* Packet dump node. */
+  FORWARDING_NODE,             /* IP forwarding node. */
+  VTY_NODE                     /* Vty node. */
+};
+
+/* Node which has some commands and prompt string and configuration
+   function pointer . */
+struct cmd_node 
+{
+  /* Node index. */
+  enum node_type node;         
+
+  /* Prompt character at vty interface. */
+  char *prompt;                        
+
+  /* Is this node's configuration goes to vtysh ? */
+  int vtysh;
+  
+  /* Node's configuration write function */
+  int (*func) (struct vty *);
+
+  /* Vector of this node's command list. */
+  vector cmd_vector;   
+};
+
+/* Structure of command element. */
+struct cmd_element 
+{
+  char *string;                        /* Command specification by string. */
+  int (*func) (struct cmd_element *, struct vty *, int, char **);
+  char *doc;                   /* Documentation of this command. */
+  int daemon;                   /* Daemon to which this command belong. */
+  vector strvec;               /* Pointing out each description vector. */
+  int cmdsize;                 /* Command index count. */
+  char *config;                        /* Configuration string */
+  vector subconfig;            /* Sub configuration string */
+};
+
+/* Command description structure. */
+struct desc
+{
+  char *cmd;                   /* Command string. */
+  char *str;                   /* Command's description. */
+};
+
+/* Return value of the commands. */
+#define CMD_SUCCESS              0
+#define CMD_WARNING              1
+#define CMD_ERR_NO_MATCH         2
+#define CMD_ERR_AMBIGUOUS        3
+#define CMD_ERR_INCOMPLETE       4
+#define CMD_ERR_EXEED_ARGC_MAX   5
+#define CMD_ERR_NOTHING_TODO     6
+#define CMD_COMPLETE_FULL_MATCH  7
+#define CMD_COMPLETE_MATCH       8
+#define CMD_COMPLETE_LIST_MATCH  9
+#define CMD_SUCCESS_DAEMON      10
+
+/* Argc max counts. */
+#define CMD_ARGC_MAX   25
+
+/* Turn off these macros when uisng cpp with extract.pl */
+#ifndef VTYSH_EXTRACT_PL  
+
+/* DEFUN for vty command interafce. Little bit hacky ;-). */
+#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
+  int funcname (struct cmd_element *, struct vty *, int, char **); \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    funcname, \
+    helpstr \
+  }; \
+  int funcname \
+  (struct cmd_element *self, struct vty *vty, int argc, char **argv)
+
+/* DEFUN_NOSH for commands that vtysh should ignore */
+#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
+  DEFUN(funcname, cmdname, cmdstr, helpstr)
+
+/* DEFSH for vtysh. */
+#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    NULL, \
+    helpstr, \
+    daemon \
+  }; \
+
+/* DEFUN + DEFSH */
+#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
+  int funcname (struct cmd_element *, struct vty *, int, char **); \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    funcname, \
+    helpstr, \
+    daemon \
+  }; \
+  int funcname \
+  (struct cmd_element *self, struct vty *vty, int argc, char **argv)
+
+/* ALIAS macro which define existing command's alias. */
+#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    funcname, \
+    helpstr \
+  };
+
+#endif /* VTYSH_EXTRACT_PL */
+
+/* Some macroes */
+#define CMD_OPTION(S)   ((S[0]) == '[')
+#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<'))
+#define CMD_VARARG(S)   ((S[0]) == '.')
+#define CMD_RANGE(S)   ((S[0] == '<'))
+
+#define CMD_IPV4(S)       ((strcmp ((S), "A.B.C.D") == 0))
+#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0))
+#define CMD_IPV6(S)        ((strcmp ((S), "X:X::X:X") == 0))
+#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0))
+
+/* Common descriptions. */
+#define SHOW_STR "Show running system information\n"
+#define IP_STR "IP information\n"
+#define IPV6_STR "IPv6 information\n"
+#define NO_STR "Negate a command or set its defaults\n"
+#define CLEAR_STR "Reset functions\n"
+#define RIP_STR "RIP information\n"
+#define BGP_STR "BGP information\n"
+#define OSPF_STR "OSPF information\n"
+#define NEIGHBOR_STR "Specify neighbor router\n"
+#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
+#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
+#define ROUTER_STR "Enable a routing process\n"
+#define AS_STR "AS number\n"
+#define MBGP_STR "MBGP information\n"
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+#define OUT_STR "Filter outgoing routing updates\n"
+#define IN_STR  "Filter incoming routing updates\n"
+#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
+#define OSPF6_NUMBER_STR "Specify by number\n"
+#define INTERFACE_STR "Interface infomation\n"
+#define IFNAME_STR "Interface name(e.g. ep0)\n"
+#define IP6_STR "IPv6 Information\n"
+#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
+#define OSPF6_ROUTER_STR "Enable a routing process\n"
+#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
+#define SECONDS_STR "<1-65535> Seconds\n"
+#define ROUTE_STR "Routing Table\n"
+#define PREFIX_LIST_STR "Build a prefix list\n"
+#define OSPF6_DUMP_TYPE_LIST \
+"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
+
+#define CONF_BACKUP_EXT ".sav"
+
+/* IPv4 only machine should not accept IPv6 address for peer's IP
+   address.  So we replace VTY command string like below. */
+#ifdef HAVE_IPV6
+#define NEIGHBOR_CMD       "neighbor (A.B.C.D|X:X::X:X) "
+#define NO_NEIGHBOR_CMD    "no neighbor (A.B.C.D|X:X::X:X) "
+#define NEIGHBOR_ADDR_STR  "Neighbor address\nIPv6 address\n"
+#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+#else
+#define NEIGHBOR_CMD       "neighbor A.B.C.D "
+#define NO_NEIGHBOR_CMD    "no neighbor A.B.C.D "
+#define NEIGHBOR_ADDR_STR  "Neighbor address\n"
+#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|WORD) "
+#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|WORD) "
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
+#endif /* HAVE_IPV6 */
+
+/* Prototypes. */
+void install_node (struct cmd_node *, int (*) (struct vty *));
+void install_default (enum node_type);
+void install_element (enum node_type, struct cmd_element *);
+void sort_node ();
+
+char *argv_concat (char **, int, int);
+vector cmd_make_strvec (char *);
+void cmd_free_strvec (vector);
+vector cmd_describe_command ();
+char **cmd_complete_command ();
+char *cmd_prompt (enum node_type);
+int config_from_file (struct vty *, FILE *);
+int cmd_execute_command (vector, struct vty *, struct cmd_element **);
+int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
+void config_replace_string (struct cmd_element *, char *, ...);
+void cmd_init (int);
+
+/* Export typical functions. */
+extern struct cmd_element config_end_cmd;
+extern struct cmd_element config_exit_cmd;
+extern struct cmd_element config_quit_cmd;
+extern struct cmd_element config_help_cmd;
+extern struct cmd_element config_list_cmd;
+int config_exit (struct cmd_element *, struct vty *, int, char **);
+int config_help (struct cmd_element *, struct vty *, int, char **);
+char *host_config_file ();
+void host_config_set (char *);
+
+#endif /* _ZEBRA_COMMAND_H */
diff --git a/lib/daemon.c b/lib/daemon.c
new file mode 100644 (file)
index 0000000..dfd26b3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Daemonize routine
+ * Copyright (C) 1997, 1999 Kunihiro Ishiguro
+ * 
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifndef HAVE_DAEMON
+
+/* Daemonize myself. */
+int
+daemon (int nochdir, int noclose)
+{
+  pid_t pid;
+
+  pid = fork ();
+
+  /* In case of fork is error. */
+  if (pid < 0)
+    {
+      perror ("fork");
+      return -1;
+    }
+
+  /* In case of this is parent process. */
+  if (pid != 0)
+    exit (0);
+
+  /* Become session leader and get pid. */
+  pid = setsid();
+
+  if (pid < -1)
+    {
+      perror ("setsid");
+      return -1;
+    }
+
+  /* Change directory to root. */
+  if (! nochdir)
+    chdir ("/");
+
+  /* File descriptor close. */
+  if (! noclose)
+    {
+      int fd;
+
+      fd = open ("/dev/null", O_RDWR, 0);
+      if (fd != -1)
+       {
+         dup2 (fd, STDIN_FILENO);
+         dup2 (fd, STDOUT_FILENO);
+         dup2 (fd, STDERR_FILENO);
+         if (fd > 2)
+           close (fd);
+       }
+    }
+
+  umask (0027);
+
+  return 0;
+}
+
+#endif /* HAVE_DAEMON */
diff --git a/lib/distribute.c b/lib/distribute.c
new file mode 100644 (file)
index 0000000..d5893a5
--- /dev/null
@@ -0,0 +1,709 @@
+/* Distribute list functions
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "filter.h"
+#include "command.h"
+#include "distribute.h"
+#include "memory.h"
+
+/* Hash of distribute list. */
+struct hash *disthash;
+
+/* Hook functions. */
+void (*distribute_add_hook) (struct distribute *);
+void (*distribute_delete_hook) (struct distribute *);
+\f
+struct distribute *
+distribute_new ()
+{
+  struct distribute *new;
+
+  new = XMALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute));
+  memset (new, 0, sizeof (struct distribute));
+
+  return new;
+}
+
+/* Free distribute object. */
+void
+distribute_free (struct distribute *dist)
+{
+  if (dist->ifname)
+    free (dist->ifname);
+
+  if (dist->list[DISTRIBUTE_IN])
+    free (dist->list[DISTRIBUTE_IN]);
+  if (dist->list[DISTRIBUTE_OUT])
+    free (dist->list[DISTRIBUTE_OUT]);
+
+  if (dist->prefix[DISTRIBUTE_IN])
+    free (dist->prefix[DISTRIBUTE_IN]);
+  if (dist->prefix[DISTRIBUTE_OUT])
+    free (dist->prefix[DISTRIBUTE_OUT]);
+
+  XFREE (MTYPE_DISTRIBUTE, dist);
+}
+
+/* Lookup interface's distribute list. */
+struct distribute *
+distribute_lookup (char *ifname)
+{
+  struct distribute key;
+  struct distribute *dist;
+
+  key.ifname = ifname;
+
+  dist = hash_lookup (disthash, &key);
+  
+  return dist;
+}
+
+void
+distribute_list_add_hook (void (*func) (struct distribute *))
+{
+  distribute_add_hook = func;
+}
+
+void
+distribute_list_delete_hook (void (*func) (struct distribute *))
+{
+  distribute_delete_hook = func;
+}
+
+void *
+distribute_hash_alloc (struct distribute *arg)
+{
+  struct distribute *dist;
+
+  dist = distribute_new ();
+  if (arg->ifname)
+    dist->ifname = strdup (arg->ifname);
+  else
+    dist->ifname = NULL;
+  return dist;
+}
+
+/* Make new distribute list and push into hash. */
+struct distribute *
+distribute_get (char *ifname)
+{
+  struct distribute key;
+
+  key.ifname = ifname;
+
+  return hash_get (disthash, &key, distribute_hash_alloc);
+}
+
+unsigned int
+distribute_hash_make (struct distribute *dist)
+{
+  unsigned int key;
+  int i;
+
+  key = 0;
+  if (dist->ifname)
+    for (i = 0; i < strlen (dist->ifname); i++)
+      key += dist->ifname[i];
+
+  return key;
+}
+
+/* If two distribute-list have same value then return 1 else return
+   0. This function is used by hash package. */
+int
+distribute_cmp (struct distribute *dist1, struct distribute *dist2)
+{
+  if (dist1->ifname && dist2->ifname)
+    if (strcmp (dist1->ifname, dist2->ifname) == 0)
+      return 1;
+  if (! dist1->ifname && ! dist2->ifname)
+    return 1;
+  return 0;
+}
+\f
+/* Set access-list name to the distribute list. */
+struct distribute *
+distribute_list_set (char *ifname, enum distribute_type type, char *alist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_get (ifname);
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (dist->list[DISTRIBUTE_IN])
+       free (dist->list[DISTRIBUTE_IN]);
+      dist->list[DISTRIBUTE_IN] = strdup (alist_name);
+    }
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (dist->list[DISTRIBUTE_OUT])
+       free (dist->list[DISTRIBUTE_OUT]);
+      dist->list[DISTRIBUTE_OUT] = strdup (alist_name);
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_add_hook) (dist);
+  
+  return dist;
+}
+
+/* Unset distribute-list.  If matched distribute-list exist then
+   return 1. */
+int
+distribute_list_unset (char *ifname, enum distribute_type type, 
+                      char *alist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifname);
+  if (!dist)
+    return 0;
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (!dist->list[DISTRIBUTE_IN])
+       return 0;
+      if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
+       return 0;
+
+      free (dist->list[DISTRIBUTE_IN]);
+      dist->list[DISTRIBUTE_IN] = NULL;      
+    }
+
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (!dist->list[DISTRIBUTE_OUT])
+       return 0;
+      if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
+       return 0;
+
+      free (dist->list[DISTRIBUTE_OUT]);
+      dist->list[DISTRIBUTE_OUT] = NULL;      
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_delete_hook) (dist);
+
+  /* If both out and in is NULL then free distribute list. */
+  if (dist->list[DISTRIBUTE_IN] == NULL &&
+      dist->list[DISTRIBUTE_OUT] == NULL &&
+      dist->prefix[DISTRIBUTE_IN] == NULL &&
+      dist->prefix[DISTRIBUTE_OUT] == NULL)
+    {
+      hash_release (disthash, dist);
+      distribute_free (dist);
+    }
+
+  return 1;
+}
+
+/* Set access-list name to the distribute list. */
+struct distribute *
+distribute_list_prefix_set (char *ifname, enum distribute_type type,
+                           char *plist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_get (ifname);
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (dist->prefix[DISTRIBUTE_IN])
+       free (dist->prefix[DISTRIBUTE_IN]);
+      dist->prefix[DISTRIBUTE_IN] = strdup (plist_name);
+    }
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (dist->prefix[DISTRIBUTE_OUT])
+       free (dist->prefix[DISTRIBUTE_OUT]);
+      dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name);
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_add_hook) (dist);
+  
+  return dist;
+}
+
+/* Unset distribute-list.  If matched distribute-list exist then
+   return 1. */
+int
+distribute_list_prefix_unset (char *ifname, enum distribute_type type,
+                             char *plist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifname);
+  if (!dist)
+    return 0;
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (!dist->prefix[DISTRIBUTE_IN])
+       return 0;
+      if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0)
+       return 0;
+
+      free (dist->prefix[DISTRIBUTE_IN]);
+      dist->prefix[DISTRIBUTE_IN] = NULL;      
+    }
+
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (!dist->prefix[DISTRIBUTE_OUT])
+       return 0;
+      if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0)
+       return 0;
+
+      free (dist->prefix[DISTRIBUTE_OUT]);
+      dist->prefix[DISTRIBUTE_OUT] = NULL;      
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_delete_hook) (dist);
+
+  /* If both out and in is NULL then free distribute list. */
+  if (dist->list[DISTRIBUTE_IN] == NULL &&
+      dist->list[DISTRIBUTE_OUT] == NULL &&
+      dist->prefix[DISTRIBUTE_IN] == NULL &&
+      dist->prefix[DISTRIBUTE_OUT] == NULL)
+    {
+      hash_release (disthash, dist);
+      distribute_free (dist);
+    }
+
+  return 1;
+}
+
+DEFUN (distribute_list_all,
+       distribute_list_all_cmd,
+       "distribute-list WORD (in|out)",
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_set (NULL, type, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_distribute_list_all,
+       no_distribute_list_all_cmd,
+       "no distribute-list WORD (in|out)",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_unset (NULL, type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (distribute_list,
+       distribute_list_cmd,
+       "distribute-list WORD (in|out) WORD",
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_set (argv[2], type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_districute_list, no_distribute_list_cmd,
+       "no distribute-list WORD (in|out) WORD",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_unset (argv[2], type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+DEFUN (districute_list_prefix_all,
+       distribute_list_prefix_all_cmd,
+       "distribute-list prefix WORD (in|out)",
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_prefix_set (NULL, type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_districute_list_prefix_all,
+       no_distribute_list_prefix_all_cmd,
+       "no distribute-list prefix WORD (in|out)",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_prefix_unset (NULL, type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
+       "distribute-list prefix WORD (in|out) WORD",
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_prefix_set (argv[2], type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
+       "no distribute-list prefix WORD (in|out) WORD",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_prefix_unset (argv[2], type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+int
+config_show_distribute (struct vty *vty)
+{
+  int i;
+  struct hash_backet *mp;
+  struct distribute *dist;
+
+  /* Output filter configuration. */
+  dist = distribute_lookup (NULL);
+  if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]))
+    {
+      vty_out (vty, "  Outgoing update filter list for all interface is");
+      if (dist->list[DISTRIBUTE_OUT])
+       vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
+      if (dist->prefix[DISTRIBUTE_OUT])
+       vty_out (vty, "%s (prefix-list) %s",
+                dist->list[DISTRIBUTE_OUT] ? "," : "",
+                dist->prefix[DISTRIBUTE_OUT]);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  else
+    vty_out (vty, "  Outgoing update filter list for all interface is not set%s", VTY_NEWLINE);
+
+  for (i = 0; i < disthash->size; i++)
+    for (mp = disthash->index[i]; mp; mp = mp->next)
+      {
+       dist = mp->data;
+       if (dist->ifname)
+         if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])
+           {
+             vty_out (vty, "    %s filtered by", dist->ifname);
+             if (dist->list[DISTRIBUTE_OUT])
+               vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
+             if (dist->prefix[DISTRIBUTE_OUT])
+               vty_out (vty, "%s (prefix-list) %s",
+                        dist->list[DISTRIBUTE_OUT] ? "," : "",
+                        dist->prefix[DISTRIBUTE_OUT]);
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+      }
+
+
+  /* Input filter configuration. */
+  dist = distribute_lookup (NULL);
+  if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]))
+    {
+      vty_out (vty, "  Incoming update filter list for all interface is");
+      if (dist->list[DISTRIBUTE_IN])
+       vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
+      if (dist->prefix[DISTRIBUTE_IN])
+       vty_out (vty, "%s (prefix-list) %s",
+                dist->list[DISTRIBUTE_IN] ? "," : "",
+                dist->prefix[DISTRIBUTE_IN]);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  else
+    vty_out (vty, "  Incoming update filter list for all interface is not set%s", VTY_NEWLINE);
+
+  for (i = 0; i < disthash->size; i++)
+    for (mp = disthash->index[i]; mp; mp = mp->next)
+      {
+       dist = mp->data;
+       if (dist->ifname)
+         if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])
+           {
+             vty_out (vty, "    %s filtered by", dist->ifname);
+             if (dist->list[DISTRIBUTE_IN])
+               vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
+             if (dist->prefix[DISTRIBUTE_IN])
+               vty_out (vty, "%s (prefix-list) %s",
+                        dist->list[DISTRIBUTE_IN] ? "," : "",
+                        dist->prefix[DISTRIBUTE_IN]);
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+      }
+  return 0;
+}
+
+/* Configuration write function. */
+int
+config_write_distribute (struct vty *vty)
+{
+  int i;
+  struct hash_backet *mp;
+  int write = 0;
+
+  for (i = 0; i < disthash->size; i++)
+    for (mp = disthash->index[i]; mp; mp = mp->next)
+      {
+       struct distribute *dist;
+
+       dist = mp->data;
+
+       if (dist->list[DISTRIBUTE_IN])
+         {
+           vty_out (vty, " distribute-list %s in %s%s", 
+                    dist->list[DISTRIBUTE_IN],
+                    dist->ifname ? dist->ifname : "",
+                    VTY_NEWLINE);
+           write++;
+         }
+
+       if (dist->list[DISTRIBUTE_OUT])
+         {
+           vty_out (vty, " distribute-list %s out %s%s", 
+
+                    dist->list[DISTRIBUTE_OUT],
+                    dist->ifname ? dist->ifname : "",
+                    VTY_NEWLINE);
+           write++;
+         }
+
+       if (dist->prefix[DISTRIBUTE_IN])
+         {
+           vty_out (vty, " distribute-list prefix %s in %s%s",
+                    dist->prefix[DISTRIBUTE_IN],
+                    dist->ifname ? dist->ifname : "",
+                    VTY_NEWLINE);
+           write++;
+         }
+
+       if (dist->prefix[DISTRIBUTE_OUT])
+         {
+           vty_out (vty, " distribute-list prefix %s out %s%s",
+                    dist->prefix[DISTRIBUTE_OUT],
+                    dist->ifname ? dist->ifname : "",
+                    VTY_NEWLINE);
+           write++;
+         }
+      }
+  return write;
+}
+
+/* Clear all distribute list. */
+void
+distribute_list_reset ()
+{
+  hash_clean (disthash, (void (*) (void *)) distribute_free);
+}
+
+/* Initialize distribute list related hash. */
+void
+distribute_list_init (int node)
+{
+  disthash = hash_create (distribute_hash_make, distribute_cmp);
+
+  install_element (node, &distribute_list_all_cmd);
+  install_element (node, &no_distribute_list_all_cmd);
+
+  install_element (node, &distribute_list_cmd);
+  install_element (node, &no_distribute_list_cmd);
+
+  install_element (node, &distribute_list_prefix_all_cmd);
+  install_element (node, &no_distribute_list_prefix_all_cmd);
+
+  install_element (node, &distribute_list_prefix_cmd);
+  install_element (node, &no_distribute_list_prefix_cmd);
+}
diff --git a/lib/distribute.h b/lib/distribute.h
new file mode 100644 (file)
index 0000000..330126b
--- /dev/null
@@ -0,0 +1,57 @@
+/* Distribute list functions header
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_DISTRIBUTE_H
+#define _ZEBRA_DISTRIBUTE_H
+
+/* Disctirubte list types. */
+enum distribute_type
+{
+  DISTRIBUTE_IN,
+  DISTRIBUTE_OUT,
+  DISTRIBUTE_MAX
+};
+
+struct distribute
+{
+  /* Name of the interface. */
+  char *ifname;
+
+  /* Filter name of `in' and `out' */
+  char *list[DISTRIBUTE_MAX];
+
+  /* prefix-list name of `in' and `out' */
+  char *prefix[DISTRIBUTE_MAX];
+};
+
+/* Prototypes for distribute-list. */
+void distribute_list_init (int);
+void distribute_list_reset (void);
+void distribute_list_add_hook (void (*) (struct distribute *));
+void distribute_list_delete_hook (void (*) (struct distribute *));
+struct distribute *distribute_lookup (char *);
+int config_write_distribute (struct vty *);
+int config_show_distribute (struct vty *);
+
+enum filter_type distribute_apply_in (struct interface *, struct prefix *);
+enum filter_type distribute_apply_out (struct interface *, struct prefix *);
+
+#endif /* _ZEBRA_DISTRIBUTE_H */
diff --git a/lib/filter.c b/lib/filter.c
new file mode 100644 (file)
index 0000000..a483ce2
--- /dev/null
@@ -0,0 +1,2058 @@
+/* Route filtering function.
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "memory.h"
+#include "command.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+struct filter_cisco
+{
+  /* Cisco access-list */
+  int extended;
+  struct in_addr addr;
+  struct in_addr addr_mask;
+  struct in_addr mask;
+  struct in_addr mask_mask;
+};
+
+struct filter_zebra
+{
+  /* If this filter is "exact" match then this flag is set. */
+  int exact;
+
+  /* Prefix information. */
+  struct prefix prefix;
+};
+
+/* Filter element of access list */
+struct filter
+{
+  /* For doubly linked list. */
+  struct filter *next;
+  struct filter *prev;
+
+  /* Filter type information. */
+  enum filter_type type;
+
+  /* Cisco access-list */
+  int cisco;
+
+  union
+    {
+      struct filter_cisco cfilter;
+      struct filter_zebra zfilter;
+    } u;
+};
+
+/* List of access_list. */
+struct access_list_list
+{
+  struct access_list *head;
+  struct access_list *tail;
+};
+
+/* Master structure of access_list. */
+struct access_master
+{
+  /* List of access_list which name is number. */
+  struct access_list_list num;
+
+  /* List of access_list which name is string. */
+  struct access_list_list str;
+
+  /* Hook function which is executed when new access_list is added. */
+  void (*add_hook) ();
+
+  /* Hook function which is executed when access_list is deleted. */
+  void (*delete_hook) ();
+};
+
+/* Static structure for IPv4 access_list's master. */
+static struct access_master access_master_ipv4 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  NULL,
+  NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure for IPv6 access_list's master. */
+static struct access_master access_master_ipv6 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  NULL,
+  NULL,
+};
+#endif /* HAVE_IPV6 */
+\f
+struct access_master *
+access_master_get (afi_t afi)
+{
+  if (afi == AFI_IP)
+    return &access_master_ipv4;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return &access_master_ipv6;
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* Allocate new filter structure. */
+struct filter *
+filter_new ()
+{
+  return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER,
+                                   sizeof (struct filter));
+}
+
+void
+filter_free (struct filter *filter)
+{
+  XFREE (MTYPE_ACCESS_FILTER, filter);
+}
+
+/* Return string of filter_type. */
+static char *
+filter_type_str (struct filter *filter)
+{
+  switch (filter->type)
+    {
+    case FILTER_PERMIT:
+      return "permit";
+      break;
+    case FILTER_DENY:
+      return "deny";
+      break;
+    case FILTER_DYNAMIC:
+      return "dynamic";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+/* If filter match to the prefix then return 1. */
+static int
+filter_match_cisco (struct filter *mfilter, struct prefix *p)
+{
+  struct filter_cisco *filter;
+  struct in_addr mask;
+  u_int32_t check_addr;
+  u_int32_t check_mask;
+
+  filter = &mfilter->u.cfilter;
+  check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
+
+  if (filter->extended)
+    {
+      masklen2ip (p->prefixlen, &mask);
+      check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
+
+      if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0
+          && memcmp (&check_mask, &filter->mask.s_addr, 4) == 0)
+       return 1;
+    }
+  else if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* If filter match to the prefix then return 1. */
+static int
+filter_match_zebra (struct filter *mfilter, struct prefix *p)
+{
+  struct filter_zebra *filter;
+
+  filter = &mfilter->u.zfilter;
+
+  if (filter->prefix.family == p->family)
+    {
+      if (filter->exact)
+       {
+         if (filter->prefix.prefixlen == p->prefixlen)
+           return prefix_match (&filter->prefix, p);
+         else
+           return 0;
+       }
+      else
+       return prefix_match (&filter->prefix, p);
+    }
+  else
+    return 0;
+}
+\f
+/* Allocate new access list structure. */
+struct access_list *
+access_list_new ()
+{
+  return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST,
+                                        sizeof (struct access_list));
+}
+
+/* Free allocated access_list. */
+void
+access_list_free (struct access_list *access)
+{
+  XFREE (MTYPE_ACCESS_LIST, access);
+}
+
+/* Delete access_list from access_master and free it. */
+void
+access_list_delete (struct access_list *access)
+{
+  struct filter *filter;
+  struct filter *next;
+  struct access_list_list *list;
+  struct access_master *master;
+
+  for (filter = access->head; filter; filter = next)
+    {
+      next = filter->next;
+      filter_free (filter);
+    }
+
+  master = access->master;
+
+  if (access->type == ACCESS_TYPE_NUMBER)
+    list = &master->num;
+  else
+    list = &master->str;
+
+  if (access->next)
+    access->next->prev = access->prev;
+  else
+    list->tail = access->prev;
+
+  if (access->prev)
+    access->prev->next = access->next;
+  else
+    list->head = access->next;
+
+  if (access->name)
+    XFREE (MTYPE_ACCESS_LIST_STR, access->name);
+
+  if (access->remark)
+    XFREE (MTYPE_TMP, access->remark);
+
+  access_list_free (access);
+}
+
+/* Insert new access list to list of access_list.  Each acceess_list
+   is sorted by the name. */
+struct access_list *
+access_list_insert (afi_t afi, char *name)
+{
+  int i;
+  long number;
+  struct access_list *access;
+  struct access_list *point;
+  struct access_list_list *alist;
+  struct access_master *master;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  /* Allocate new access_list and copy given name. */
+  access = access_list_new ();
+  access->name = XSTRDUP (MTYPE_ACCESS_LIST_STR, name);
+  access->master = master;
+
+  /* If name is made by all digit character.  We treat it as
+     number. */
+  for (number = 0, i = 0; i < strlen (name); i++)
+    {
+      if (isdigit ((int) name[i]))
+       number = (number * 10) + (name[i] - '0');
+      else
+       break;
+    }
+
+  /* In case of name is all digit character */
+  if (i == strlen (name))
+    {
+      access->type = ACCESS_TYPE_NUMBER;
+
+      /* Set access_list to number list. */
+      alist = &master->num;
+
+      for (point = alist->head; point; point = point->next)
+       if (atol (point->name) >= number)
+         break;
+    }
+  else
+    {
+      access->type = ACCESS_TYPE_STRING;
+
+      /* Set access_list to string list. */
+      alist = &master->str;
+  
+      /* Set point to insertion point. */
+      for (point = alist->head; point; point = point->next)
+       if (strcmp (point->name, name) >= 0)
+         break;
+    }
+
+  /* In case of this is the first element of master. */
+  if (alist->head == NULL)
+    {
+      alist->head = alist->tail = access;
+      return access;
+    }
+
+  /* In case of insertion is made at the tail of access_list. */
+  if (point == NULL)
+    {
+      access->prev = alist->tail;
+      alist->tail->next = access;
+      alist->tail = access;
+      return access;
+    }
+
+  /* In case of insertion is made at the head of access_list. */
+  if (point == alist->head)
+    {
+      access->next = alist->head;
+      alist->head->prev = access;
+      alist->head = access;
+      return access;
+    }
+
+  /* Insertion is made at middle of the access_list. */
+  access->next = point;
+  access->prev = point->prev;
+
+  if (point->prev)
+    point->prev->next = access;
+  point->prev = access;
+
+  return access;
+}
+
+/* Lookup access_list from list of access_list by name. */
+struct access_list *
+access_list_lookup (afi_t afi, char *name)
+{
+  struct access_list *access;
+  struct access_master *master;
+
+  if (name == NULL)
+    return NULL;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  for (access = master->num.head; access; access = access->next)
+    if (strcmp (access->name, name) == 0)
+      return access;
+
+  for (access = master->str.head; access; access = access->next)
+    if (strcmp (access->name, name) == 0)
+      return access;
+
+  return NULL;
+}
+
+/* Get access list from list of access_list.  If there isn't matched
+   access_list create new one and return it. */
+struct access_list *
+access_list_get (afi_t afi, char *name)
+{
+  struct access_list *access;
+
+  access = access_list_lookup (afi, name);
+  if (access == NULL)
+    access = access_list_insert (afi, name);
+  return access;
+}
+
+/* Apply access list to object (which should be struct prefix *). */
+enum filter_type
+access_list_apply (struct access_list *access, void *object)
+{
+  struct filter *filter;
+  struct prefix *p;
+
+  p = (struct prefix *) object;
+
+  if (access == NULL)
+    return FILTER_DENY;
+
+  for (filter = access->head; filter; filter = filter->next)
+    {
+      if (filter->cisco)
+       {
+         if (filter_match_cisco (filter, p))
+           return filter->type;
+       }
+      else
+       {
+         if (filter_match_zebra (filter, p))
+           return filter->type;
+       }
+    }
+
+  return FILTER_DENY;
+}
+
+/* Add hook function. */
+void
+access_list_add_hook (void (*func) (struct access_list *access))
+{
+  access_master_ipv4.add_hook = func;
+#ifdef HAVE_IPV6
+  access_master_ipv6.add_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Delete hook function. */
+void
+access_list_delete_hook (void (*func) (struct access_list *access))
+{
+  access_master_ipv4.delete_hook = func;
+#ifdef HAVE_IPV6
+  access_master_ipv6.delete_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Add new filter to the end of specified access_list. */
+void
+access_list_filter_add (struct access_list *access, struct filter *filter)
+{
+  filter->next = NULL;
+  filter->prev = access->tail;
+
+  if (access->tail)
+    access->tail->next = filter;
+  else
+    access->head = filter;
+  access->tail = filter;
+
+  /* Run hook function. */
+  if (access->master->add_hook)
+    (*access->master->add_hook) (access);
+}
+
+/* If access_list has no filter then return 1. */
+static int
+access_list_empty (struct access_list *access)
+{
+  if (access->head == NULL && access->tail == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+/* Delete filter from specified access_list.  If there is hook
+   function execute it. */
+void
+access_list_filter_delete (struct access_list *access, struct filter *filter)
+{
+  struct access_master *master;
+
+  master = access->master;
+
+  if (filter->next)
+    filter->next->prev = filter->prev;
+  else
+    access->tail = filter->prev;
+
+  if (filter->prev)
+    filter->prev->next = filter->next;
+  else
+    access->head = filter->next;
+
+  filter_free (filter);
+
+  /* If access_list becomes empty delete it from access_master. */
+  if (access_list_empty (access))
+    access_list_delete (access);
+
+  /* Run hook function. */
+  if (master->delete_hook)
+    (*master->delete_hook) (access);
+}
+\f
+/*
+  deny    Specify packets to reject
+  permit  Specify packets to forward
+  dynamic ?
+*/
+
+/*
+  Hostname or A.B.C.D  Address to match
+  any                  Any source host
+  host                 A single host address
+*/
+
+struct filter *
+filter_lookup_cisco (struct access_list *access, struct filter *mnew)
+{
+  struct filter *mfilter;
+  struct filter_cisco *filter;
+  struct filter_cisco *new;
+
+  new = &mnew->u.cfilter;
+
+  for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+    {
+      filter = &mfilter->u.cfilter;
+
+      if (filter->extended)
+       {
+         if (mfilter->type == mnew->type
+             && filter->addr.s_addr == new->addr.s_addr
+             && filter->addr_mask.s_addr == new->addr_mask.s_addr
+             && filter->mask.s_addr == new->mask.s_addr
+             && filter->mask_mask.s_addr == new->mask_mask.s_addr)
+           return mfilter;
+       }
+      else
+       {
+         if (mfilter->type == mnew->type
+             && filter->addr.s_addr == new->addr.s_addr
+             && filter->addr_mask.s_addr == new->addr_mask.s_addr)
+           return mfilter;
+       }
+    }
+
+  return NULL;
+}
+
+struct filter *
+filter_lookup_zebra (struct access_list *access, struct filter *mnew)
+{
+  struct filter *mfilter;
+  struct filter_zebra *filter;
+  struct filter_zebra *new;
+
+  new = &mnew->u.zfilter;
+
+  for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+    {
+      filter = &mfilter->u.zfilter;
+
+      if (filter->exact == new->exact
+         && mfilter->type == mnew->type
+         && prefix_same (&filter->prefix, &new->prefix))
+       return mfilter;
+    }
+  return NULL;
+}
+
+int
+vty_access_list_remark_unset (struct vty *vty, afi_t afi, char *name)
+{
+  struct access_list *access;
+
+  access = access_list_lookup (afi, name);
+  if (! access)
+    {
+      vty_out (vty, "%% access-list %s doesn't exist%s", name,
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (access->remark)
+    {
+      XFREE (MTYPE_TMP, access->remark);
+      access->remark = NULL;
+    }
+
+  if (access->head == NULL && access->tail == NULL && access->remark == NULL)
+    access_list_delete (access);
+
+  return CMD_SUCCESS;
+}
+
+int
+filter_set_cisco (struct vty *vty, char *name_str, char *type_str,
+                 char *addr_str, char *addr_mask_str,
+                 char *mask_str, char *mask_mask_str,
+                 int extended, int set)
+{
+  int ret;
+  enum filter_type type;
+  struct filter *mfilter;
+  struct filter_cisco *filter;
+  struct access_list *access;
+  struct in_addr addr;
+  struct in_addr addr_mask;
+  struct in_addr mask;
+  struct in_addr mask_mask;
+
+  /* Check of filter type. */
+  if (strncmp (type_str, "p", 1) == 0)
+    type = FILTER_PERMIT;
+  else if (strncmp (type_str, "d", 1) == 0)
+    type = FILTER_DENY;
+  else
+    {
+      vty_out (vty, "%% filter type must be permit or deny%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (addr_str, &addr);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%%Inconsistent address and mask%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (addr_mask_str, &addr_mask);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%%Inconsistent address and mask%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (extended)
+    {
+      ret = inet_aton (mask_str, &mask);
+      if (ret <= 0)
+       {
+         vty_out (vty, "%%Inconsistent address and mask%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      ret = inet_aton (mask_mask_str, &mask_mask);
+      if (ret <= 0)
+       {
+         vty_out (vty, "%%Inconsistent address and mask%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+
+  mfilter = filter_new();
+  mfilter->type = type;
+  mfilter->cisco = 1;
+  filter = &mfilter->u.cfilter;
+  filter->extended = extended;
+  filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr;
+  filter->addr_mask.s_addr = addr_mask.s_addr;
+
+  if (extended)
+    {
+      filter->mask.s_addr = mask.s_addr & ~mask_mask.s_addr;
+      filter->mask_mask.s_addr = mask_mask.s_addr;
+    }
+
+  /* Install new filter to the access_list. */
+  access = access_list_get (AFI_IP, name_str);
+
+  if (set)
+    {
+      if (filter_lookup_cisco (access, mfilter))
+       filter_free (mfilter);
+      else
+       access_list_filter_add (access, mfilter);
+    }
+  else
+    {
+      struct filter *delete_filter;
+
+      delete_filter = filter_lookup_cisco (access, mfilter);
+      if (delete_filter)
+       access_list_filter_delete (access, delete_filter);
+
+      filter_free (mfilter);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Standard access-list */
+DEFUN (access_list_standard,
+       access_list_standard_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n"
+       "Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3],
+                          NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_nomask,
+       access_list_standard_nomask_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+                          NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_host,
+       access_list_standard_host_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A single host address\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+                          NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_any,
+       access_list_standard_any_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) any",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any source host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", NULL, NULL, 0, 1);
+}
+
+DEFUN (no_access_list_standard,
+       no_access_list_standard_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n"
+       "Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3],
+                          NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_nomask,
+       no_access_list_standard_nomask_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+                          NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_host,
+       no_access_list_standard_host_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A single host address\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+                          NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_any,
+       no_access_list_standard_any_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any source host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", NULL, NULL, 0, 0);
+}
+
+/* Extended access-list */
+DEFUN (access_list_extended,
+       access_list_extended_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          argv[3], argv[4], argv[5], 1 ,1);
+}
+
+DEFUN (access_list_extended_mask_any,
+       access_list_extended_mask_any_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          argv[3], "0.0.0.0",
+                          "255.255.255.255", 1, 1);
+}
+
+DEFUN (access_list_extended_any_mask,
+       access_list_extended_any_mask_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", argv[2],
+                          argv[3], 1, 1);
+}
+
+DEFUN (access_list_extended_any_any,
+       access_list_extended_any_any_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", "0.0.0.0",
+                          "255.255.255.255", 1, 1);
+}
+
+DEFUN (access_list_extended_mask_host,
+       access_list_extended_mask_host_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          argv[3], argv[4],
+                          "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_host_mask,
+       access_list_extended_host_mask_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          "0.0.0.0", argv[3],
+                          argv[4], 1, 1);
+}
+
+DEFUN (access_list_extended_host_host,
+       access_list_extended_host_host_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          "0.0.0.0", argv[3],
+                          "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_any_host,
+       access_list_extended_any_host_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", argv[2],
+                          "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_host_any,
+       access_list_extended_host_any_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          "0.0.0.0", "0.0.0.0",
+                          "255.255.255.255", 1, 1);
+}
+
+DEFUN (no_access_list_extended,
+       no_access_list_extended_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          argv[3], argv[4], argv[5], 1, 0);
+}
+
+DEFUN (no_access_list_extended_mask_any,
+       no_access_list_extended_mask_any_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          argv[3], "0.0.0.0",
+                          "255.255.255.255", 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_mask,
+       no_access_list_extended_any_mask_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", argv[2],
+                          argv[3], 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_any,
+       no_access_list_extended_any_any_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", "0.0.0.0",
+                          "255.255.255.255", 1, 0);
+}
+
+DEFUN (no_access_list_extended_mask_host,
+       no_access_list_extended_mask_host_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          argv[3], argv[4],
+                          "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_mask,
+       no_access_list_extended_host_mask_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          "0.0.0.0", argv[3],
+                          argv[4], 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_host,
+       no_access_list_extended_host_host_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          "0.0.0.0", argv[3],
+                          "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_host,
+       no_access_list_extended_any_host_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+                          "255.255.255.255", argv[2],
+                          "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_any,
+       no_access_list_extended_host_any_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+                          "0.0.0.0", "0.0.0.0",
+                          "255.255.255.255", 1, 0);
+}
+
+int
+filter_set_zebra (struct vty *vty, char *name_str, char *type_str,
+                 afi_t afi, char *prefix_str, int exact, int set)
+{
+  int ret;
+  enum filter_type type;
+  struct filter *mfilter;
+  struct filter_zebra *filter;
+  struct access_list *access;
+  struct prefix p;
+
+  /* Check of filter type. */
+  if (strncmp (type_str, "p", 1) == 0)
+    type = FILTER_PERMIT;
+  else if (strncmp (type_str, "d", 1) == 0)
+    type = FILTER_DENY;
+  else
+    {
+      vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check string format of prefix and prefixlen. */
+  if (afi == AFI_IP)
+    {
+      ret = str2prefix_ipv4 (prefix_str, (struct prefix_ipv4 *)&p);
+      if (ret <= 0)
+       {
+         vty_out (vty, "IP address prefix/prefixlen is malformed%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      ret = str2prefix_ipv6 (prefix_str, (struct prefix_ipv6 *) &p);
+      if (ret <= 0)
+       {
+         vty_out (vty, "IPv6 address prefix/prefixlen is malformed%s",
+                  VTY_NEWLINE);
+                  return CMD_WARNING;
+       }
+    }
+#endif /* HAVE_IPV6 */
+  else
+    return CMD_WARNING;
+
+  mfilter = filter_new ();
+  mfilter->type = type;
+  filter = &mfilter->u.zfilter;
+  prefix_copy (&filter->prefix, &p);
+
+  /* "exact-match" */
+  if (exact)
+    filter->exact = 1;
+
+  /* Install new filter to the access_list. */
+  access = access_list_get (afi, name_str);
+
+  if (set)
+    {
+      if (filter_lookup_zebra (access, mfilter))
+       filter_free (mfilter);
+      else
+       access_list_filter_add (access, mfilter);
+    }
+  else
+    {
+      struct filter *delete_filter;
+
+      delete_filter = filter_lookup_zebra (access, mfilter);
+      if (delete_filter)
+        access_list_filter_delete (access, delete_filter);
+
+      filter_free (mfilter);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Zebra access-list */
+DEFUN (access_list,
+       access_list_cmd,
+       "access-list WORD (deny|permit) A.B.C.D/M",
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 1);
+}
+
+DEFUN (access_list_exact,
+       access_list_exact_cmd,
+       "access-list WORD (deny|permit) A.B.C.D/M exact-match",
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 1);
+}
+
+DEFUN (access_list_any,
+       access_list_any_cmd,
+       "access-list WORD (deny|permit) any",
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 1);
+}
+
+DEFUN (no_access_list,
+       no_access_list_cmd,
+       "no access-list WORD (deny|permit) A.B.C.D/M",
+       NO_STR
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 0);
+}
+
+DEFUN (no_access_list_exact,
+       no_access_list_exact_cmd,
+       "no access-list WORD (deny|permit) A.B.C.D/M exact-match",
+       NO_STR
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 0);
+}
+
+DEFUN (no_access_list_any,
+       no_access_list_any_cmd,
+       "no access-list WORD (deny|permit) any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 0);
+}
+
+DEFUN (no_access_list_all,
+       no_access_list_all_cmd,
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list name\n")
+{
+  struct access_list *access;
+  struct access_master *master;
+
+  /* Looking up access_list. */
+  access = access_list_lookup (AFI_IP, argv[0]);
+  if (access == NULL)
+    {
+      vty_out (vty, "%% access-list %s doesn't exist%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  master = access->master;
+
+  /* Delete all filter from access-list. */
+  access_list_delete (access);
+
+  /* Run hook function. */
+  if (master->delete_hook)
+    (*master->delete_hook) (access);
+  return CMD_SUCCESS;
+}
+
+DEFUN (access_list_remark,
+       access_list_remark_cmd,
+       "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+{
+  struct access_list *access;
+  struct buffer *b;
+  int i;
+
+  access = access_list_get (AFI_IP, argv[0]);
+
+  if (access->remark)
+    {
+      XFREE (MTYPE_TMP, access->remark);
+      access->remark = NULL;
+    }
+
+  /* Below is remark get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  access->remark = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_access_list_remark,
+       no_access_list_remark_cmd,
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n")
+{
+  return vty_access_list_remark_unset (vty, AFI_IP, argv[0]);
+}
+       
+ALIAS (no_access_list_remark,
+       no_access_list_remark_arg_cmd,
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_access_list,
+       ipv6_access_list_cmd,
+       "ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 1);
+}
+
+DEFUN (ipv6_access_list_exact,
+       ipv6_access_list_exact_cmd,
+       "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 1);
+}
+
+DEFUN (ipv6_access_list_any,
+       ipv6_access_list_any_cmd,
+       "ipv6 access-list WORD (deny|permit) any",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any prefixi to match\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 1);
+}
+
+DEFUN (no_ipv6_access_list,
+       no_ipv6_access_list_cmd,
+       "no ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 0);
+}
+
+DEFUN (no_ipv6_access_list_exact,
+       no_ipv6_access_list_exact_cmd,
+       "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 0);
+}
+
+DEFUN (no_ipv6_access_list_any,
+       no_ipv6_access_list_any_cmd,
+       "no ipv6 access-list WORD (deny|permit) any",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any prefixi to match\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 0);
+}
+
+
+DEFUN (no_ipv6_access_list_all,
+       no_ipv6_access_list_all_cmd,
+       "no ipv6 access-list WORD",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n")
+{
+  struct access_list *access;
+  struct access_master *master;
+
+  /* Looking up access_list. */
+  access = access_list_lookup (AFI_IP6, argv[0]);
+  if (access == NULL)
+    {
+      vty_out (vty, "%% access-list %s doesn't exist%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  master = access->master;
+
+  /* Delete all filter from access-list. */
+  access_list_delete (access);
+
+  /* Run hook function. */
+  if (master->delete_hook)
+    (*master->delete_hook) (access);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_access_list_remark,
+       ipv6_access_list_remark_cmd,
+       "ipv6 access-list WORD remark .LINE",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+{
+  struct access_list *access;
+  struct buffer *b;
+  int i;
+
+  access = access_list_get (AFI_IP6, argv[0]);
+
+  if (access->remark)
+    {
+      XFREE (MTYPE_TMP, access->remark);
+      access->remark = NULL;
+    }
+
+  /* Below is remark get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  access->remark = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_access_list_remark,
+       no_ipv6_access_list_remark_cmd,
+       "no ipv6 access-list WORD remark",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n")
+{
+  return vty_access_list_remark_unset (vty, AFI_IP6, argv[0]);
+}
+       
+ALIAS (no_ipv6_access_list_remark,
+       no_ipv6_access_list_remark_arg_cmd,
+       "no ipv6 access-list WORD remark .LINE",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+#endif /* HAVE_IPV6 */
+
+void config_write_access_zebra (struct vty *, struct filter *);
+void config_write_access_cisco (struct vty *, struct filter *);
+
+/* show access-list command. */
+int
+filter_show (struct vty *vty, char *name, afi_t afi)
+{
+  struct access_list *access;
+  struct access_master *master;
+  struct filter *mfilter;
+  struct filter_cisco *filter;
+  int write = 0;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return 0;
+
+  for (access = master->num.head; access; access = access->next)
+    {
+      if (name && strcmp (access->name, name) != 0)
+       continue;
+
+      write = 1;
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+       {
+         filter = &mfilter->u.cfilter;
+
+         if (write)
+           {
+             vty_out (vty, "%s IP%s access list %s%s",
+                      mfilter->cisco ? 
+                      (filter->extended ? "Extended" : "Standard") : "Zebra",
+                      afi == AFI_IP6 ? "v6" : "",
+                      access->name, VTY_NEWLINE);
+             write = 0;
+           }
+
+         vty_out (vty, "    %s%s", filter_type_str (mfilter),
+                  mfilter->type == FILTER_DENY ? "  " : "");
+
+         if (! mfilter->cisco)
+           config_write_access_zebra (vty, mfilter);
+         else if (filter->extended)
+           config_write_access_cisco (vty, mfilter);
+         else
+           {
+             if (filter->addr_mask.s_addr == 0xffffffff)
+               vty_out (vty, " any%s", VTY_NEWLINE);
+             else
+               {
+                 vty_out (vty, " %s", inet_ntoa (filter->addr));
+                 if (filter->addr_mask.s_addr != 0)
+                   vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask));
+                 vty_out (vty, "%s", VTY_NEWLINE);
+               }
+           }
+       }
+    }
+
+  for (access = master->str.head; access; access = access->next)
+    {
+      if (name && strcmp (access->name, name) != 0)
+       continue;
+
+      write = 1;
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+       {
+         filter = &mfilter->u.cfilter;
+
+         if (write)
+           {
+             vty_out (vty, "%s IP%s access list %s%s",
+                      mfilter->cisco ? 
+                      (filter->extended ? "Extended" : "Standard") : "Zebra",
+                      afi == AFI_IP6 ? "v6" : "",
+                      access->name, VTY_NEWLINE);
+             write = 0;
+           }
+
+         vty_out (vty, "    %s%s", filter_type_str (mfilter),
+                  mfilter->type == FILTER_DENY ? "  " : "");
+
+         if (! mfilter->cisco)
+           config_write_access_zebra (vty, mfilter);
+         else if (filter->extended)
+           config_write_access_cisco (vty, mfilter);
+         else
+           {
+             if (filter->addr_mask.s_addr == 0xffffffff)
+               vty_out (vty, " any%s", VTY_NEWLINE);
+             else
+               {
+                 vty_out (vty, " %s", inet_ntoa (filter->addr));
+                 if (filter->addr_mask.s_addr != 0)
+                   vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask));
+                 vty_out (vty, "%s", VTY_NEWLINE);
+               }
+           }
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_access_list,
+       show_ip_access_list_cmd,
+       "show ip access-list",
+       SHOW_STR
+       IP_STR
+       "List IP access lists\n")
+{
+  return filter_show (vty, NULL, AFI_IP);
+}
+
+DEFUN (show_ip_access_list_name,
+       show_ip_access_list_name_cmd,
+       "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+       SHOW_STR
+       IP_STR
+       "List IP access lists\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n")
+{
+  return filter_show (vty, argv[0], AFI_IP);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_ipv6_access_list,
+       show_ipv6_access_list_cmd,
+       "show ipv6 access-list",
+       SHOW_STR
+       IPV6_STR
+       "List IPv6 access lists\n")
+{
+  return filter_show (vty, NULL, AFI_IP6);
+}
+
+DEFUN (show_ipv6_access_list_name,
+       show_ipv6_access_list_name_cmd,
+       "show ipv6 access-list WORD",
+       SHOW_STR
+       IPV6_STR
+       "List IPv6 access lists\n"
+       "IPv6 zebra access-list\n")
+{
+  return filter_show (vty, argv[0], AFI_IP6);
+}
+#endif /* HAVE_IPV6 */
+
+void
+config_write_access_cisco (struct vty *vty, struct filter *mfilter)
+{
+  struct filter_cisco *filter;
+
+  filter = &mfilter->u.cfilter;
+
+  if (filter->extended)
+    {
+      vty_out (vty, " ip");
+      if (filter->addr_mask.s_addr == 0xffffffff)
+       vty_out (vty, " any");
+      else if (filter->addr_mask.s_addr == 0)
+       vty_out (vty, " host %s", inet_ntoa (filter->addr));
+      else
+       {
+         vty_out (vty, " %s", inet_ntoa (filter->addr));
+         vty_out (vty, " %s", inet_ntoa (filter->addr_mask));
+        }
+
+      if (filter->mask_mask.s_addr == 0xffffffff)
+       vty_out (vty, " any");
+      else if (filter->mask_mask.s_addr == 0)
+       vty_out (vty, " host %s", inet_ntoa (filter->mask));
+      else
+       {
+         vty_out (vty, " %s", inet_ntoa (filter->mask));
+         vty_out (vty, " %s", inet_ntoa (filter->mask_mask));
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  else
+    {
+      if (filter->addr_mask.s_addr == 0xffffffff)
+       vty_out (vty, " any%s", VTY_NEWLINE);
+      else
+       {
+         vty_out (vty, " %s", inet_ntoa (filter->addr));
+         if (filter->addr_mask.s_addr != 0)
+           vty_out (vty, " %s", inet_ntoa (filter->addr_mask));
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+    }
+}
+
+void
+config_write_access_zebra (struct vty *vty, struct filter *mfilter)
+{
+  struct filter_zebra *filter;
+  struct prefix *p;
+  char buf[BUFSIZ];
+
+  filter = &mfilter->u.zfilter;
+  p = &filter->prefix;
+
+  if (p->prefixlen == 0 && ! filter->exact)
+    vty_out (vty, " any");
+  else
+    vty_out (vty, " %s/%d%s",
+            inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+            p->prefixlen,
+            filter->exact ? " exact-match" : "");
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+config_write_access (struct vty *vty, afi_t afi)
+{
+  struct access_list *access;
+  struct access_master *master;
+  struct filter *mfilter;
+  int write = 0;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return 0;
+
+  for (access = master->num.head; access; access = access->next)
+    {
+      if (access->remark)
+       {
+         vty_out (vty, "%saccess-list %s remark %s%s",
+                  afi == AFI_IP ? "" : "ipv6 ",
+                  access->name, access->remark,
+                  VTY_NEWLINE);
+         write++;
+       }
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+       {
+         vty_out (vty, "%saccess-list %s %s",
+            afi == AFI_IP ? "" : "ipv6 ",
+            access->name,
+            filter_type_str (mfilter));
+
+         if (mfilter->cisco)
+           config_write_access_cisco (vty, mfilter);
+         else
+           config_write_access_zebra (vty, mfilter);
+
+         write++;
+       }
+    }
+
+  for (access = master->str.head; access; access = access->next)
+    {
+      if (access->remark)
+       {
+         vty_out (vty, "%saccess-list %s remark %s%s",
+                  afi == AFI_IP ? "" : "ipv6 ",
+                  access->name, access->remark,
+                  VTY_NEWLINE);
+         write++;
+       }
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+       {
+         vty_out (vty, "%saccess-list %s %s",
+            afi == AFI_IP ? "" : "ipv6 ",
+            access->name,
+            filter_type_str (mfilter));
+
+         if (mfilter->cisco)
+           config_write_access_cisco (vty, mfilter);
+         else
+           config_write_access_zebra (vty, mfilter);
+
+         write++;
+       }
+    }
+  return write;
+}
+
+/* Access-list node. */
+struct cmd_node access_node =
+{
+  ACCESS_NODE,
+  "",                          /* Access list has no interface. */
+  1
+};
+
+int
+config_write_access_ipv4 (struct vty *vty)
+{
+  return config_write_access (vty, AFI_IP);
+}
+
+void
+access_list_reset_ipv4 ()
+{
+  struct access_list *access;
+  struct access_list *next;
+  struct access_master *master;
+
+  master = access_master_get (AFI_IP);
+  if (master == NULL)
+    return;
+
+  for (access = master->num.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+  for (access = master->str.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+}
+
+/* Install vty related command. */
+void
+access_list_init_ipv4 ()
+{
+  install_node (&access_node, config_write_access_ipv4);
+
+  install_element (ENABLE_NODE, &show_ip_access_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_access_list_name_cmd);
+
+  /* Zebra access-list */
+  install_element (CONFIG_NODE, &access_list_cmd);
+  install_element (CONFIG_NODE, &access_list_exact_cmd);
+  install_element (CONFIG_NODE, &access_list_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_cmd);
+  install_element (CONFIG_NODE, &no_access_list_exact_cmd);
+  install_element (CONFIG_NODE, &no_access_list_any_cmd);
+
+  /* Standard access-list */
+  install_element (CONFIG_NODE, &access_list_standard_cmd);
+  install_element (CONFIG_NODE, &access_list_standard_nomask_cmd);
+  install_element (CONFIG_NODE, &access_list_standard_host_cmd);
+  install_element (CONFIG_NODE, &access_list_standard_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_any_cmd);
+
+  /* Extended access-list */
+  install_element (CONFIG_NODE, &access_list_extended_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_any_any_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_host_host_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_any_host_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_host_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd);
+
+  install_element (CONFIG_NODE, &access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_access_list_all_cmd);
+  install_element (CONFIG_NODE, &no_access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd);
+}
+
+#ifdef HAVE_IPV6
+struct cmd_node access_ipv6_node =
+{
+  ACCESS_IPV6_NODE,
+  "",
+  1
+};
+
+int
+config_write_access_ipv6 (struct vty *vty)
+{
+  return config_write_access (vty, AFI_IP6);
+}
+
+void
+access_list_reset_ipv6 ()
+{
+  struct access_list *access;
+  struct access_list *next;
+  struct access_master *master;
+
+  master = access_master_get (AFI_IP6);
+  if (master == NULL)
+    return;
+
+  for (access = master->num.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+  for (access = master->str.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+}
+
+void
+access_list_init_ipv6 ()
+{
+  install_node (&access_ipv6_node, config_write_access_ipv6);
+
+  install_element (ENABLE_NODE, &show_ipv6_access_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd);
+
+  install_element (CONFIG_NODE, &ipv6_access_list_cmd);
+  install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd);
+  install_element (CONFIG_NODE, &ipv6_access_list_any_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd);
+
+  install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd);
+  install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd);
+}
+#endif /* HAVE_IPV6 */
+
+void
+access_list_init ()
+{
+  access_list_init_ipv4 ();
+#ifdef HAVE_IPV6
+  access_list_init_ipv6();
+#endif /* HAVE_IPV6 */
+}
+
+void
+access_list_reset ()
+{
+  access_list_reset_ipv4 ();
+#ifdef HAVE_IPV6
+  access_list_reset_ipv6();
+#endif /* HAVE_IPV6 */
+}
diff --git a/lib/filter.h b/lib/filter.h
new file mode 100644 (file)
index 0000000..077ac2f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Route filtering function.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#ifndef _ZEBRA_FILTER_H
+#define _ZEBRA_FILTER_H
+
+#include "if.h"
+
+/* Filter type is made by `permit', `deny' and `dynamic'. */
+enum filter_type 
+{
+  FILTER_DENY,
+  FILTER_PERMIT,
+  FILTER_DYNAMIC
+};
+
+enum access_type
+{
+  ACCESS_TYPE_STRING,
+  ACCESS_TYPE_NUMBER
+};
+
+/* Access list */
+struct access_list
+{
+  char *name;
+  char *remark;
+
+  struct access_master *master;
+
+  enum access_type type;
+
+  struct access_list *next;
+  struct access_list *prev;
+
+  struct filter *head;
+  struct filter *tail;
+};
+
+/* Prototypes for access-list. */
+void access_list_init (void);
+void access_list_reset (void);
+void access_list_add_hook (void (*func)(struct access_list *));
+void access_list_delete_hook (void (*func)(struct access_list *));
+struct access_list *access_list_lookup (afi_t, char *);
+enum filter_type access_list_apply (struct access_list *, void *);
+
+#endif /* _ZEBRA_FILTER_H */
diff --git a/lib/getopt.c b/lib/getopt.c
new file mode 100644 (file)
index 0000000..426b29b
--- /dev/null
@@ -0,0 +1,1054 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper@gnu.org
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98
+       Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C Library.
+   Bugs can be reported to bug-glibc@gnu.org.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+\f
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+# ifdef HAVE_LIBINTL_H
+#  include <libintl.h>
+#  define _(msgid)     gettext (msgid)
+# else
+#  define _(msgid)     (msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index      strchr
+#else
+
+# if HAVE_STRING_H
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)                                               \
+    {                                                                        \
+      char __tmp = __getopt_nonoption_flags[ch1];                            \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];         \
+      __getopt_nonoption_flags[ch2] = __tmp;                                 \
+    }
+#else  /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+        presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+       nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+       {
+         memset (__mempcpy (new_str, __getopt_nonoption_flags,
+                            nonoption_flags_max_len),
+                 '\0', top + 1 - nonoption_flags_max_len);
+         nonoption_flags_max_len = top + 1;
+         __getopt_nonoption_flags = new_str;
+       }
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+       {
+         /* Bottom segment is the short one.  */
+         int len = middle - bottom;
+         register int i;
+
+         /* Swap it with the top part of the top segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[top - (middle - bottom) + i];
+             argv[top - (middle - bottom) + i] = tem;
+             SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+           }
+         /* Exclude the moved bottom segment from further swapping.  */
+         top -= len;
+       }
+      else
+       {
+         /* Top segment is the short one.  */
+         int len = top - middle;
+         register int i;
+
+         /* Swap it with the bottom part of the bottom segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[middle + i];
+             argv[middle + i] = tem;
+             SWAP_FLAGS (bottom + i, middle + i);
+           }
+         /* Exclude the moved top segment from further swapping.  */
+         bottom += len;
+       }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+       {
+         if (__getopt_nonoption_flags == NULL
+             || __getopt_nonoption_flags[0] == '\0')
+           nonoption_flags_max_len = -1;
+         else
+           {
+             const char *orig_str = __getopt_nonoption_flags;
+             int len = nonoption_flags_max_len = strlen (orig_str);
+             if (nonoption_flags_max_len < argc)
+               nonoption_flags_max_len = argc;
+             __getopt_nonoption_flags =
+               (char *) malloc (nonoption_flags_max_len);
+             if (__getopt_nonoption_flags == NULL)
+               nonoption_flags_max_len = -1;
+             else
+               memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+                       '\0', nonoption_flags_max_len - len);
+           }
+       }
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (optind == 0 || !__getopt_initialized)
+    {
+      if (optind == 0)
+       optind = 1;     /* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'              \
+                     || (optind < nonoption_flags_len                        \
+                         && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+        moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+       last_nonopt = optind;
+      if (first_nonopt > optind)
+       first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc && NONOPTION_P)
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* The special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return -1;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+       {
+         if (ordering == REQUIRE_ORDER)
+           return -1;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+         || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+       /* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+        or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+       if (!strncmp (p->name, nextchar, nameend - nextchar))
+         {
+           if ((unsigned int) (nameend - nextchar)
+               == (unsigned int) strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second or later nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         optopt = 0;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*nameend)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = nameend + 1;
+             else
+               {
+                 if (opterr)
+                    {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                        _("%s: option `--%s' doesn't allow an argument\n"),
+                        argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                        _("%s: option `%c%s' doesn't allow an argument\n"),
+                        argv[0], argv[optind - 1][0], pfound->name);
+                    }
+
+                 nextchar += strlen (nextchar);
+
+                 optopt = pfound->val;
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr,
+                          _("%s: option `%s' requires an argument\n"),
+                          argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 optopt = pfound->val;
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         optopt = 0;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+           if (posixly_correct)
+             /* 1003.2 specifies the format of this message.  */
+             fprintf (stderr, _("%s: illegal option -- %c\n"),
+                      argv[0], c);
+           else
+             fprintf (stderr, _("%s: invalid option -- %c\n"),
+                      argv[0], c);
+         }
+       optopt = c;
+       return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+       char *nameend;
+       const struct option *p;
+       const struct option *pfound = NULL;
+       int exact = 0;
+       int ambig = 0;
+       int indfound = 0;
+       int option_index;
+
+       /* This is an option that requires an argument.  */
+       if (*nextchar != '\0')
+         {
+           optarg = nextchar;
+           /* If we end this ARGV-element by taking the rest as an arg,
+              we must advance to the next element now.  */
+           optind++;
+         }
+       else if (optind == argc)
+         {
+           if (opterr)
+             {
+               /* 1003.2 specifies the format of this message.  */
+               fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+                        argv[0], c);
+             }
+           optopt = c;
+           if (optstring[0] == ':')
+             c = ':';
+           else
+             c = '?';
+           return c;
+         }
+       else
+         /* We already incremented `optind' once;
+            increment it again when taking next ARGV-elt as argument.  */
+         optarg = argv[optind++];
+
+       /* optarg is now the argument, see if it's in the
+          table of longopts.  */
+
+       for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+         /* Do nothing.  */ ;
+
+       /* Test all long options for either exact match
+          or abbreviated matches.  */
+       for (p = longopts, option_index = 0; p->name; p++, option_index++)
+         if (!strncmp (p->name, nextchar, nameend - nextchar))
+           {
+             if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+               {
+                 /* Exact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+                 exact = 1;
+                 break;
+               }
+             else if (pfound == NULL)
+               {
+                 /* First nonexact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+               }
+             else
+               /* Second or later nonexact match found.  */
+               ambig = 1;
+           }
+       if (ambig && !exact)
+         {
+           if (opterr)
+             fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+                      argv[0], argv[optind]);
+           nextchar += strlen (nextchar);
+           optind++;
+           return '?';
+         }
+       if (pfound != NULL)
+         {
+           option_index = indfound;
+           if (*nameend)
+             {
+               /* Don't test has_arg with >, because some C compilers don't
+                  allow it to be used on enums.  */
+               if (pfound->has_arg)
+                 optarg = nameend + 1;
+               else
+                 {
+                   if (opterr)
+                     fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+                              argv[0], pfound->name);
+
+                   nextchar += strlen (nextchar);
+                   return '?';
+                 }
+             }
+           else if (pfound->has_arg == 1)
+             {
+               if (optind < argc)
+                 optarg = argv[optind++];
+               else
+                 {
+                   if (opterr)
+                     fprintf (stderr,
+                              _("%s: option `%s' requires an argument\n"),
+                              argv[0], argv[optind - 1]);
+                   nextchar += strlen (nextchar);
+                   return optstring[0] == ':' ? ':' : '?';
+                 }
+             }
+           nextchar += strlen (nextchar);
+           if (longind != NULL)
+             *longind = option_index;
+           if (pfound->flag)
+             {
+               *(pfound->flag) = pfound->val;
+               return 0;
+             }
+           return pfound->val;
+         }
+         nextchar = NULL;
+         return 'W';   /* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = NULL;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 {
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr,
+                          _("%s: option requires an argument -- %c\n"),
+                          argv[0], c);
+                 }
+               optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* Not ELIDE_CODE.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getopt.h b/lib/getopt.h
new file mode 100644 (file)
index 0000000..fb30719
--- /dev/null
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C Library.
+   Bugs can be reported to bug-glibc@gnu.org.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define        no_argument             0
+#define required_argument      1
+#define optional_argument      2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* getopt.h */
diff --git a/lib/getopt1.c b/lib/getopt1.c
new file mode 100644 (file)
index 0000000..ff25737
--- /dev/null
@@ -0,0 +1,190 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+     Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C Library.
+   Bugs can be reported to bug-glibc@gnu.org.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == -1)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644 (file)
index 0000000..4097507
--- /dev/null
@@ -0,0 +1,182 @@
+/* Hash routine.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+
+/* Allocate a new hash.  */
+struct hash *
+hash_create_size (unsigned int size, 
+                 unsigned int (*hash_key) (), int (*hash_cmp) ())
+{
+  struct hash *hash;
+
+  hash = XMALLOC (MTYPE_HASH, sizeof (struct hash));
+  hash->index = XMALLOC (MTYPE_HASH_INDEX, 
+                        sizeof (struct hash_backet *) * size);
+  memset (hash->index, 0, sizeof (struct hash_backet *) * size);
+  hash->size = size;
+  hash->hash_key = hash_key;
+  hash->hash_cmp = hash_cmp;
+  hash->count = 0;
+
+  return hash;
+}
+
+/* Allocate a new hash with default hash size.  */
+struct hash *
+hash_create (unsigned int (*hash_key) (), int (*hash_cmp) ())
+{
+  return hash_create_size (HASHTABSIZE, hash_key, hash_cmp);
+}
+
+/* Utility function for hash_get().  When this function is specified
+   as alloc_func, return arugment as it is.  This function is used for
+   intern already allocated value.  */
+void *
+hash_alloc_intern (void *arg)
+{
+  return arg;
+}
+
+/* Lookup and return hash backet in hash.  If there is no
+   corresponding hash backet and alloc_func is specified, create new
+   hash backet.  */
+void *
+hash_get (struct hash *hash, void *data, void * (*alloc_func) ())
+{
+  unsigned int key;
+  unsigned int index;
+  void *newdata;
+  struct hash_backet *backet;
+
+  key = (*hash->hash_key) (data);
+  index = key % hash->size;
+
+  for (backet = hash->index[index]; backet != NULL; backet = backet->next) 
+    if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
+      return backet->data;
+
+  if (alloc_func)
+    {
+      newdata = (*alloc_func) (data);
+      if (newdata == NULL)
+       return NULL;
+
+      backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
+      backet->data = newdata;
+      backet->key = key;
+      backet->next = hash->index[index];
+      hash->index[index] = backet;
+      hash->count++;
+      return backet->data;
+    }
+  return NULL;
+}
+
+/* Hash lookup.  */
+void *
+hash_lookup (struct hash *hash, void *data)
+{
+  return hash_get (hash, data, NULL);
+}
+
+/* This function release registered value from specified hash.  When
+   release is successfully finished, return the data pointer in the
+   hash backet.  */
+void *
+hash_release (struct hash *hash, void *data)
+{
+  void *ret;
+  unsigned int key;
+  unsigned int index;
+  struct hash_backet *backet;
+  struct hash_backet *pp;
+
+  key = (*hash->hash_key) (data);
+  index = key % hash->size;
+
+  for (backet = pp = hash->index[index]; backet; backet = backet->next)
+    {
+      if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) 
+       {
+         if (backet == pp) 
+           hash->index[index] = backet->next;
+         else 
+           pp->next = backet->next;
+
+         ret = backet->data;
+         XFREE (MTYPE_HASH_BACKET, backet);
+         hash->count--;
+         return ret;
+       }
+      pp = backet;
+    }
+  return NULL;
+}
+
+/* Iterator function for hash.  */
+void
+hash_iterate (struct hash *hash, 
+             void (*func) (struct hash_backet *, void *), void *arg)
+{
+  int i;
+  struct hash_backet *hb;
+
+  for (i = 0; i < hash->size; i++)
+    for (hb = hash->index[i]; hb; hb = hb->next)
+      (*func) (hb, arg);
+}
+
+/* Clean up hash.  */
+void
+hash_clean (struct hash *hash, void (*free_func) (void *))
+{
+  int i;
+  struct hash_backet *hb;
+  struct hash_backet *next;
+
+  for (i = 0; i < hash->size; i++)
+    {
+      for (hb = hash->index[i]; hb; hb = next)
+       {
+         next = hb->next;
+             
+         if (free_func)
+           (*free_func) (hb->data);
+
+         XFREE (MTYPE_HASH_BACKET, hb);
+         hash->count--;
+       }
+      hash->index[i] = NULL;
+    }
+}
+
+/* Free hash memory.  You may call hash_clean before call this
+   function.  */
+void
+hash_free (struct hash *hash)
+{
+  XFREE (MTYPE_HASH_INDEX, hash->index);
+  XFREE (MTYPE_HASH, hash);
+}
diff --git a/lib/hash.h b/lib/hash.h
new file mode 100644 (file)
index 0000000..715e53b
--- /dev/null
@@ -0,0 +1,71 @@
+/* Hash routine.
+   Copyright (C) 1998 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; either version 2, or (at your
+option) any later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#ifndef _ZEBRA_HASH_H
+#define _ZEBRA_HASH_H
+
+/* Default hash table size.  */ 
+#define HASHTABSIZE     1024
+
+struct hash_backet
+{
+  /* Linked list.  */
+  struct hash_backet *next;
+
+  /* Hash key. */
+  unsigned int key;
+
+  /* Data.  */
+  void *data;
+};
+
+struct hash
+{
+  /* Hash backet. */
+  struct hash_backet **index;
+
+  /* Hash table size. */
+  unsigned int size;
+
+  /* Key make function. */
+  unsigned int (*hash_key) ();
+
+  /* Data compare function. */
+  int (*hash_cmp) ();
+
+  /* Backet alloc. */
+  unsigned long count;
+};
+
+struct hash *hash_create (unsigned int (*) (), int (*) ());
+struct hash *hash_create_size (unsigned int, unsigned int (*) (), int (*) ());
+
+void *hash_get (struct hash *, void *, void * (*) ());
+void *hash_alloc_intern (void *);
+void *hash_lookup (struct hash *, void *);
+void *hash_release (struct hash *, void *);
+
+void hash_iterate (struct hash *, 
+                  void (*) (struct hash_backet *, void *), void *);
+
+void hash_clean (struct hash *, void (*) (void *));
+void hash_free (struct hash *);
+
+#endif /* _ZEBRA_HASH_H */
diff --git a/lib/if.c b/lib/if.c
new file mode 100644 (file)
index 0000000..bbf22ab
--- /dev/null
+++ b/lib/if.c
@@ -0,0 +1,713 @@
+/* 
+ * Interface functions.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "zebra/connected.h"
+#include "memory.h"
+#include "table.h"
+#include "buffer.h"
+#include "str.h"
+#include "log.h"
+\f
+/* Master list of interfaces. */
+struct list *iflist;
+
+/* One for each program.  This structure is needed to store hooks. */
+struct if_master
+{
+  int (*if_new_hook) (struct interface *);
+  int (*if_delete_hook) (struct interface *);
+} if_master;
+\f
+/* Create new interface structure. */
+struct interface *
+if_new ()
+{
+  struct interface *ifp;
+
+  ifp = XMALLOC (MTYPE_IF, sizeof (struct interface));
+  memset (ifp, 0, sizeof (struct interface));
+  return ifp;
+}
+
+struct interface *
+if_create ()
+{
+  struct interface *ifp;
+
+  ifp = if_new ();
+  
+  listnode_add (iflist, ifp);
+  ifp->connected = list_new ();
+  ifp->connected->del = (void (*) (void *)) connected_free;
+
+  if (if_master.if_new_hook)
+    (*if_master.if_new_hook) (ifp);
+
+  return ifp;
+}
+
+/* Delete and free interface structure. */
+void
+if_delete (struct interface *ifp)
+{
+  listnode_delete (iflist, ifp);
+
+  if (if_master.if_delete_hook)
+    (*if_master.if_delete_hook) (ifp);
+
+  /* Free connected address list */
+  list_delete (ifp->connected);
+
+  XFREE (MTYPE_IF, ifp);
+}
+
+/* Add hook to interface master. */
+void
+if_add_hook (int type, int (*func)(struct interface *ifp))
+{
+  switch (type) {
+  case IF_NEW_HOOK:
+    if_master.if_new_hook = func;
+    break;
+  case IF_DELETE_HOOK:
+    if_master.if_delete_hook = func;
+    break;
+  default:
+    break;
+  }
+}
+
+/* Interface existance check by index. */
+struct interface *
+if_lookup_by_index (unsigned int index)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (ifp->ifindex == index)
+       return ifp;
+    }
+  return NULL;
+}
+
+char *
+ifindex2ifname (unsigned int index)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (ifp->ifindex == index)
+       return ifp->name;
+    }
+  return "unknown";
+}
+
+/* Interface existance check by interface name. */
+struct interface *
+if_lookup_by_name (char *name)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (strncmp (name, ifp->name, sizeof ifp->name) == 0)
+       return ifp;
+    }
+  return NULL;
+}
+
+/* Lookup interface by IPv4 address. */
+struct interface *
+if_lookup_exact_address (struct in_addr src)
+{
+  listnode node;
+  listnode cnode;
+  struct interface *ifp;
+  struct prefix *p;
+  struct connected *c;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         c = getdata (cnode);
+
+         p = c->address;
+
+         if (p && p->family == AF_INET)
+           {
+             if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
+               return ifp;
+           }         
+       }
+    }
+  return NULL;
+}
+
+/* Lookup interface by IPv4 address. */
+struct interface *
+if_lookup_address (struct in_addr src)
+{
+  listnode node;
+  struct prefix addr;
+  struct prefix best;
+  listnode cnode;
+  struct interface *ifp;
+  struct prefix *p;
+  struct connected *c;
+  struct interface *match;
+
+  /* Zero structures - get rid of rubbish from stack */
+  memset(&addr, 0, sizeof(addr));
+  memset(&best, 0, sizeof(best));
+
+  addr.family = AF_INET;
+  addr.u.prefix4 = src;
+  addr.prefixlen = IPV4_MAX_BITLEN;
+
+  match = NULL;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         c = getdata (cnode);
+
+         if (if_is_pointopoint (ifp))
+           {
+             p = c->address;
+
+             if (p && p->family == AF_INET)
+               {
+#ifdef OLD_RIB  /* PTP  links are conventionally identified 
+                    by the address of the far end - MAG */
+                 if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
+                   return ifp;
+#endif
+                 p = c->destination;
+                 if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src))
+                   return ifp;
+               }
+           }
+         else
+           {
+             p = c->address;
+
+             if (p->family == AF_INET)
+               {
+                 if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen)
+                   {
+                     best = *p;
+                     match = ifp;
+                   }
+               }
+           }
+       }
+    }
+  return match;
+}
+
+/* Get interface by name if given name interface doesn't exist create
+   one. */
+struct interface *
+if_get_by_name (char *name)
+{
+  struct interface *ifp;
+
+  ifp = if_lookup_by_name (name);
+  if (ifp == NULL)
+    {
+      ifp = if_create ();
+      strncpy (ifp->name, name, IFNAMSIZ);
+    }
+  return ifp;
+}
+
+/* Does interface up ? */
+int
+if_is_up (struct interface *ifp)
+{
+  return ifp->flags & IFF_UP;
+}
+
+/* Is this loopback interface ? */
+int
+if_is_loopback (struct interface *ifp)
+{
+  return ifp->flags & IFF_LOOPBACK;
+}
+
+/* Does this interface support broadcast ? */
+int
+if_is_broadcast (struct interface *ifp)
+{
+  return ifp->flags & IFF_BROADCAST;
+}
+
+/* Does this interface support broadcast ? */
+int
+if_is_pointopoint (struct interface *ifp)
+{
+  return ifp->flags & IFF_POINTOPOINT;
+}
+
+/* Does this interface support multicast ? */
+int
+if_is_multicast (struct interface *ifp)
+{
+  return ifp->flags & IFF_MULTICAST;
+}
+
+/* Printout flag information into log */
+const char *
+if_flag_dump (unsigned long flag)
+{
+  int separator = 0;
+  static char logbuf[BUFSIZ];
+
+#define IFF_OUT_LOG(X,STR) \
+  if ((X) && (flag & (X))) \
+    { \
+      if (separator) \
+       strlcat (logbuf, ",", BUFSIZ); \
+      else \
+       separator = 1; \
+      strlcat (logbuf, STR, BUFSIZ); \
+    }
+
+  strlcpy (logbuf, "  <", BUFSIZ);
+  IFF_OUT_LOG (IFF_UP, "UP");
+  IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST");
+  IFF_OUT_LOG (IFF_DEBUG, "DEBUG");
+  IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK");
+  IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT");
+  IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS");
+  IFF_OUT_LOG (IFF_RUNNING, "RUNNING");
+  IFF_OUT_LOG (IFF_NOARP, "NOARP");
+  IFF_OUT_LOG (IFF_PROMISC, "PROMISC");
+  IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI");
+  IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE");
+  IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX");
+  IFF_OUT_LOG (IFF_LINK0, "LINK0");
+  IFF_OUT_LOG (IFF_LINK1, "LINK1");
+  IFF_OUT_LOG (IFF_LINK2, "LINK2");
+  IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST");
+
+  strlcat (logbuf, ">", BUFSIZ);
+
+  return logbuf;
+}
+
+/* For debugging */
+void
+if_dump (struct interface *ifp)
+{
+  listnode node;
+
+  zlog_info ("Interface %s index %d metric %d mtu %d %s",
+            ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, 
+            if_flag_dump (ifp->flags));
+  
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    ;
+}
+
+/* Interface printing for all interface. */
+void
+if_dump_all ()
+{
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    if_dump (getdata (node));
+}
+
+DEFUN (interface_desc, 
+       interface_desc_cmd,
+       "description .LINE",
+       "Interface specific description\n"
+       "Characters describing this interface\n")
+{
+  int i;
+  struct interface *ifp;
+  struct buffer *b;
+
+  if (argc == 0)
+    return CMD_SUCCESS;
+
+  ifp = vty->index;
+  if (ifp->desc)
+    XFREE (0, ifp->desc);
+
+  b = buffer_new (1024);
+  for (i = 0; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  ifp->desc = buffer_getstr (b);
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_interface_desc, 
+       no_interface_desc_cmd,
+       "no description",
+       NO_STR
+       "Interface specific description\n")
+{
+  struct interface *ifp;
+
+  ifp = vty->index;
+  if (ifp->desc)
+    XFREE (0, ifp->desc);
+  ifp->desc = NULL;
+
+  return CMD_SUCCESS;
+}
+
+
+/* See also wrapper function zebra_interface() in zebra/interface.c */
+DEFUN (interface,
+       interface_cmd,
+       "interface IFNAME",
+       "Select an interface to configure\n"
+       "Interface's name\n")
+{
+  struct interface *ifp;
+
+  ifp = if_lookup_by_name (argv[0]);
+
+  if (ifp == NULL)
+    {
+      ifp = if_create ();
+      strncpy (ifp->name, argv[0], INTERFACE_NAMSIZ);
+    }
+  vty->index = ifp;
+  vty->node = INTERFACE_NODE;
+
+  return CMD_SUCCESS;
+}
+
+/* For debug purpose. */
+DEFUN (show_address,
+       show_address_cmd,
+       "show address",
+       SHOW_STR
+       "address\n")
+{
+  listnode node;
+  listnode node2;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (node2 = listhead (ifp->connected); node2; nextnode (node2))
+       {
+         ifc = getdata (node2);
+         p = ifc->address;
+
+         if (p->family == AF_INET)
+           vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
+                    VTY_NEWLINE);
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Allocate connected structure. */
+struct connected *
+connected_new ()
+{
+  struct connected *new = XMALLOC (MTYPE_CONNECTED, sizeof (struct connected));
+  memset (new, 0, sizeof (struct connected));
+  return new;
+}
+
+/* Free connected structure. */
+void
+connected_free (struct connected *connected)
+{
+  if (connected->address)
+    prefix_free (connected->address);
+
+  if (connected->destination)
+    prefix_free (connected->destination);
+
+  if (connected->label)
+    free (connected->label);
+
+  XFREE (MTYPE_CONNECTED, connected);
+}
+
+/* Print if_addr structure. */
+void
+connected_log (struct connected *connected, char *str)
+{
+  struct prefix *p;
+  struct interface *ifp;
+  char logbuf[BUFSIZ];
+  char buf[BUFSIZ];
+  
+  ifp = connected->ifp;
+  p = connected->address;
+
+  snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", 
+           str, ifp->name, prefix_family_str (p),
+           inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+           p->prefixlen);
+
+  p = connected->destination;
+  if (p)
+    {
+      strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+              BUFSIZ - strlen(logbuf));
+    }
+  zlog (NULL, LOG_INFO, logbuf);
+}
+
+/* If two connected address has same prefix return 1. */
+int
+connected_same_prefix (struct prefix *p1, struct prefix *p2)
+{
+  if (p1->family == p2->family)
+    {
+      if (p1->family == AF_INET &&
+         IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4))
+       return 1;
+#ifdef HAVE_IPV6
+      if (p1->family == AF_INET6 &&
+         IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6))
+       return 1;
+#endif /* HAVE_IPV6 */
+    }
+  return 0;
+}
+
+struct connected *
+connected_delete_by_prefix (struct interface *ifp, struct prefix *p)
+{
+  struct listnode *node;
+  struct listnode *next;
+  struct connected *ifc;
+
+  /* In case of same prefix come, replace it with new one. */
+  for (node = listhead (ifp->connected); node; node = next)
+    {
+      ifc = getdata (node);
+      next = node->next;
+
+      if (connected_same_prefix (ifc->address, p))
+       {
+         listnode_delete (ifp->connected, ifc);
+         return ifc;
+       }
+    }
+  return NULL;
+}
+
+/* Check the connected information is PtP style or not.  */
+int
+ifc_pointopoint (struct connected *ifc)
+{
+  struct prefix *p;
+  int ptp = 0;
+
+  /* When interface has PtP flag.  */
+  if (if_is_pointopoint (ifc->ifp))
+    return 1;
+
+  /* RFC3021 PtP check.  */
+  p = ifc->address;
+
+  if (p->family == AF_INET)
+    ptp = (p->prefixlen >= IPV4_MAX_PREFIXLEN - 1);
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    ptp = (p->prefixlen >= IPV6_MAX_PREFIXLEN - 1);
+#endif /* HAVE_IPV6 */
+
+  return ptp;
+}
+
+#ifndef HAVE_IF_NAMETOINDEX
+unsigned int
+if_nametoindex (const char *name)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (strcmp (ifp->name, name) == 0)
+       return ifp->ifindex;
+    }
+  return 0;
+}
+#endif
+
+#ifndef HAVE_IF_INDEXTONAME
+char *
+if_indextoname (unsigned int ifindex, char *name)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (ifp->ifindex == ifindex)
+       {
+         memcpy (name, ifp->name, IFNAMSIZ);
+         return ifp->name;
+       }
+    }
+  return NULL;
+}
+#endif
+\f
+/* Interface looking up by interface's address. */
+
+/* Interface's IPv4 address reverse lookup table. */
+struct route_table *ifaddr_ipv4_table;
+/* struct route_table *ifaddr_ipv6_table; */
+
+void
+ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *ifaddr;
+
+  rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p);
+  if (rn)
+    {
+      route_unlock_node (rn);
+      zlog_info ("ifaddr_ipv4_add(): address %s is already added",
+                inet_ntoa (*ifaddr));
+      return;
+    }
+  rn->info = ifp;
+}
+
+void
+ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *ifaddr;
+
+  rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
+  if (! rn)
+    {
+      zlog_info ("ifaddr_ipv4_delete(): can't find address %s",
+                inet_ntoa (*ifaddr));
+      return;
+    }
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+}
+
+/* Lookup interface by interface's IP address or interface index. */
+struct interface *
+ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex)
+{
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  struct interface *ifp;
+  listnode node;
+
+  if (addr)
+    {
+      p.family = AF_INET;
+      p.prefixlen = IPV4_MAX_PREFIXLEN;
+      p.prefix = *addr;
+
+      rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
+      if (! rn)
+       return NULL;
+      
+      ifp = rn->info;
+      route_unlock_node (rn);
+      return ifp;
+    }
+  else
+    {
+      for (node = listhead (iflist); node; nextnode (node))
+       {
+         ifp = getdata (node);
+
+         if (ifp->ifindex == ifindex)
+           return ifp;
+       }
+    }
+  return NULL;
+}
+
+/* Initialize interface list. */
+void
+if_init ()
+{
+  iflist = list_new ();
+  ifaddr_ipv4_table = route_table_init ();
+
+  if (iflist)
+    return;
+
+  memset (&if_master, 0, sizeof if_master);
+}
diff --git a/lib/if.h b/lib/if.h
new file mode 100644 (file)
index 0000000..3896d18
--- /dev/null
+++ b/lib/if.h
@@ -0,0 +1,222 @@
+/* Interface related header.
+   Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; either version 2, or (at your
+option) any later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#ifndef _ZEBRA_IF_H
+#define _ZEBRA_IF_H
+
+#include "linklist.h"
+
+/*
+  Interface name length.
+
+   Linux define value in /usr/include/linux/if.h.
+   #define IFNAMSIZ        16
+
+   FreeBSD define value in /usr/include/net/if.h.
+   #define IFNAMSIZ        16
+*/
+
+#define INTERFACE_NAMSIZ      20
+#define INTERFACE_HWADDR_MAX  20
+
+/* Internal If indexes start at 0xFFFFFFFF and go down to 1 greater
+   than this */
+#define IFINDEX_INTERNBASE 0x80000000
+
+#ifdef HAVE_PROC_NET_DEV
+struct if_stats
+{
+  unsigned long rx_packets;   /* total packets received       */
+  unsigned long tx_packets;   /* total packets transmitted    */
+  unsigned long rx_bytes;     /* total bytes received         */
+  unsigned long tx_bytes;     /* total bytes transmitted      */
+  unsigned long rx_errors;    /* bad packets received         */
+  unsigned long tx_errors;    /* packet transmit problems     */
+  unsigned long rx_dropped;   /* no space in linux buffers    */
+  unsigned long tx_dropped;   /* no space available in linux  */
+  unsigned long rx_multicast; /* multicast packets received   */
+  unsigned long rx_compressed;
+  unsigned long tx_compressed;
+  unsigned long collisions;
+
+  /* detailed rx_errors: */
+  unsigned long rx_length_errors;
+  unsigned long rx_over_errors;       /* receiver ring buff overflow  */
+  unsigned long rx_crc_errors;        /* recved pkt with crc error    */
+  unsigned long rx_frame_errors;      /* recv'd frame alignment error */
+  unsigned long rx_fifo_errors;       /* recv'r fifo overrun          */
+  unsigned long rx_missed_errors;     /* receiver missed packet     */
+  /* detailed tx_errors */
+  unsigned long tx_aborted_errors;
+  unsigned long tx_carrier_errors;
+  unsigned long tx_fifo_errors;
+  unsigned long tx_heartbeat_errors;
+  unsigned long tx_window_errors;
+};
+#endif /* HAVE_PROC_NET_DEV */
+
+/* Interface structure */
+struct interface 
+{
+  /* Interface name. */
+  char name[INTERFACE_NAMSIZ + 1];
+
+  /* Interface index. */
+  unsigned int ifindex;
+
+  /* Zebra internal interface status */
+  u_char status;
+#define ZEBRA_INTERFACE_ACTIVE     (1 << 0)
+#define ZEBRA_INTERFACE_SUB        (1 << 1)
+  
+  /* Interface flags. */
+  unsigned long flags;
+
+  /* Interface metric */
+  int metric;
+
+  /* Interface MTU. */
+  int mtu;
+
+  /* Hardware address. */
+#ifdef HAVE_SOCKADDR_DL
+  struct sockaddr_dl sdl;
+#else
+  unsigned short hw_type;
+  u_char hw_addr[INTERFACE_HWADDR_MAX];
+  int hw_addr_len;
+#endif /* HAVE_SOCKADDR_DL */
+
+  /* interface bandwidth, kbits */
+  unsigned int bandwidth;
+  
+  /* description of the interface. */
+  char *desc;                  
+
+  /* Distribute list. */
+  void *distribute_in;
+  void *distribute_out;
+
+  /* Connected address list. */
+  list connected;
+
+  /* Daemon specific interface data pointer. */
+  void *info;
+
+  /* Statistics fileds. */
+#ifdef HAVE_PROC_NET_DEV
+  struct if_stats stats;
+#endif /* HAVE_PROC_NET_DEV */  
+#ifdef HAVE_NET_RT_IFLIST
+  struct if_data stats;
+#endif /* HAVE_NET_RT_IFLIST */
+};
+
+/* Connected address structure. */
+struct connected
+{
+  /* Attached interface. */
+  struct interface *ifp;
+
+  /* Flags for configuration. */
+  u_char conf;
+#define ZEBRA_IFC_REAL         (1 << 0)
+#define ZEBRA_IFC_CONFIGURED   (1 << 1)
+
+  /* Flags for connected address. */
+  u_char flags;
+#define ZEBRA_IFA_SECONDARY   (1 << 0)
+
+  /* Address of connected network. */
+  struct prefix *address;
+  struct prefix *destination;
+
+  /* Label for Linux 2.2.X and upper. */
+  char *label;
+};
+
+/* Interface hook sort. */
+#define IF_NEW_HOOK   0
+#define IF_DELETE_HOOK 1
+
+/* There are some interface flags which are only supported by some
+   operating system. */
+
+#ifndef IFF_NOTRAILERS
+#define IFF_NOTRAILERS 0x0
+#endif /* IFF_NOTRAILERS */
+#ifndef IFF_OACTIVE
+#define IFF_OACTIVE 0x0
+#endif /* IFF_OACTIVE */
+#ifndef IFF_SIMPLEX
+#define IFF_SIMPLEX 0x0
+#endif /* IFF_SIMPLEX */
+#ifndef IFF_LINK0
+#define IFF_LINK0 0x0
+#endif /* IFF_LINK0 */
+#ifndef IFF_LINK1
+#define IFF_LINK1 0x0
+#endif /* IFF_LINK1 */
+#ifndef IFF_LINK2
+#define IFF_LINK2 0x0
+#endif /* IFF_LINK2 */
+
+/* Prototypes. */
+struct interface *if_new (void);
+struct interface *if_create (void);
+struct interface *if_lookup_by_index (unsigned int);
+struct interface *if_lookup_by_name (char *);
+struct interface *if_lookup_exact_address (struct in_addr);
+struct interface *if_lookup_address (struct in_addr);
+struct interface *if_get_by_name (char *);
+void if_delete (struct interface *);
+int if_is_up (struct interface *);
+int if_is_loopback (struct interface *);
+int if_is_broadcast (struct interface *);
+int if_is_pointopoint (struct interface *);
+int if_is_multicast (struct interface *);
+void if_add_hook (int, int (*)(struct interface *));
+void if_init ();
+void if_dump_all ();
+char *ifindex2ifname (unsigned int);
+
+/* Connected address functions. */
+struct connected *connected_new ();
+void connected_free (struct connected *);
+void connected_add (struct interface *, struct connected *);
+struct connected  *connected_delete_by_prefix (struct interface *, struct prefix *);
+int ifc_pointopoint (struct connected *);
+
+#ifndef HAVE_IF_NAMETOINDEX
+unsigned int if_nametoindex (const char *);
+#endif
+#ifndef HAVE_IF_INDEXTONAME
+char *if_indextoname (unsigned int, char *);
+#endif
+
+/* Exported variables. */
+extern list iflist;
+extern struct cmd_element interface_desc_cmd;
+extern struct cmd_element no_interface_desc_cmd;
+extern struct cmd_element interface_cmd;
+extern struct cmd_element interface_pseudo_cmd;
+extern struct cmd_element no_interface_pseudo_cmd;
+
+#endif /* _ZEBRA_IF_H */
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
new file mode 100644 (file)
index 0000000..d3031fa
--- /dev/null
@@ -0,0 +1,305 @@
+/* route-map for interface.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "command.h"
+#include "memory.h"
+#include "if.h"
+#include "if_rmap.h"
+
+struct hash *ifrmaphash;
+
+/* Hook functions. */
+void (*if_rmap_add_hook) (struct if_rmap *) = NULL;
+void (*if_rmap_delete_hook) (struct if_rmap *) = NULL;
+\f
+struct if_rmap *
+if_rmap_new ()
+{
+  struct if_rmap *new;
+
+  new = XCALLOC (MTYPE_IF_RMAP, sizeof (struct if_rmap));
+
+  return new;
+}
+
+void
+if_rmap_free (struct if_rmap *if_rmap)
+{
+  if (if_rmap->ifname)
+    free (if_rmap->ifname);
+
+  if (if_rmap->routemap[IF_RMAP_IN])
+    free (if_rmap->routemap[IF_RMAP_IN]);
+  if (if_rmap->routemap[IF_RMAP_OUT])
+    free (if_rmap->routemap[IF_RMAP_OUT]);
+
+  XFREE (MTYPE_IF_RMAP, if_rmap);
+}
+
+struct if_rmap *
+if_rmap_lookup (char *ifname)
+{
+  struct if_rmap key;
+  struct if_rmap *if_rmap;
+
+  key.ifname = ifname;
+
+  if_rmap = hash_lookup (ifrmaphash, &key);
+  
+  return if_rmap;
+}
+
+void
+if_rmap_hook_add (void (*func) (struct if_rmap *))
+{
+  if_rmap_add_hook = func;
+}
+
+void
+if_rmap_hook_delete (void (*func) (struct if_rmap *))
+{
+  if_rmap_delete_hook = func;
+}
+
+void *
+if_rmap_hash_alloc (struct if_rmap *arg)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_new ();
+  if_rmap->ifname = strdup (arg->ifname);
+
+  return if_rmap;
+}
+
+struct if_rmap *
+if_rmap_get (char *ifname)
+{
+  struct if_rmap key;
+
+  key.ifname = ifname;
+
+  return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc);
+}
+
+unsigned int
+if_rmap_hash_make (struct if_rmap *if_rmap)
+{
+  unsigned int key;
+  int i;
+
+  key = 0;
+  for (i = 0; i < strlen (if_rmap->ifname); i++)
+    key += if_rmap->ifname[i];
+
+  return key;
+}
+
+int
+if_rmap_hash_cmp (struct if_rmap *if_rmap1, struct if_rmap *if_rmap2)
+{
+  if (strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0)
+    return 1;
+  return 0;
+}
+\f
+struct if_rmap *
+if_rmap_set (char *ifname, enum if_rmap_type type, char *routemap_name)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_get (ifname);
+
+  if (type == IF_RMAP_IN)
+    {
+      if (if_rmap->routemap[IF_RMAP_IN])
+       free (if_rmap->routemap[IF_RMAP_IN]);
+      if_rmap->routemap[IF_RMAP_IN] = strdup (routemap_name);
+    }
+  if (type == IF_RMAP_OUT)
+    {
+      if (if_rmap->routemap[IF_RMAP_OUT])
+       free (if_rmap->routemap[IF_RMAP_OUT]);
+      if_rmap->routemap[IF_RMAP_OUT] = strdup (routemap_name);
+    }
+
+  if (if_rmap_add_hook)
+    (*if_rmap_add_hook) (if_rmap);
+  
+  return if_rmap;
+}
+
+int
+if_rmap_unset (char *ifname, enum if_rmap_type type, char *routemap_name)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_lookup (ifname);
+  if (!if_rmap)
+    return 0;
+
+  if (type == IF_RMAP_IN)
+    {
+      if (!if_rmap->routemap[IF_RMAP_IN])
+       return 0;
+      if (strcmp (if_rmap->routemap[IF_RMAP_IN], routemap_name) != 0)
+       return 0;
+
+      free (if_rmap->routemap[IF_RMAP_IN]);
+      if_rmap->routemap[IF_RMAP_IN] = NULL;      
+    }
+
+  if (type == IF_RMAP_OUT)
+    {
+      if (!if_rmap->routemap[IF_RMAP_OUT])
+       return 0;
+      if (strcmp (if_rmap->routemap[IF_RMAP_OUT], routemap_name) != 0)
+       return 0;
+
+      free (if_rmap->routemap[IF_RMAP_OUT]);
+      if_rmap->routemap[IF_RMAP_OUT] = NULL;      
+    }
+
+  if (if_rmap_delete_hook)
+    (*if_rmap_delete_hook) (if_rmap);
+
+  if (if_rmap->routemap[IF_RMAP_IN] == NULL &&
+      if_rmap->routemap[IF_RMAP_OUT] == NULL)
+    {
+      hash_release (ifrmaphash, if_rmap);
+      if_rmap_free (if_rmap);
+    }
+
+  return 1;
+}
+
+DEFUN (if_rmap,
+       if_rmap_cmd,
+       "route-map RMAP_NAME (in|out) IFNAME",
+       "Route map set\n"
+       "Route map name\n"
+       "Route map set for input filtering\n"
+       "Route map set for output filtering\n"
+       "Route map interface name\n")
+{
+  enum if_rmap_type type;
+  struct if_rmap *if_rmap;
+
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = IF_RMAP_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = IF_RMAP_OUT;
+  else
+    {
+      vty_out (vty, "route-map direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if_rmap = if_rmap_set (argv[2], type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_if_rmap,
+       no_if_rmap_cmd,
+       "no route-map ROUTEMAP_NAME (in|out) IFNAME",
+       NO_STR
+       "Route map unset\n"
+       "Route map name\n"
+       "Route map for input filtering\n"
+       "Route map for output filtering\n"
+       "Route map interface name\n")
+{
+  int ret;
+  enum if_rmap_type type;
+
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = IF_RMAP_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = IF_RMAP_OUT;
+  else
+    {
+      vty_out (vty, "route-map direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = if_rmap_unset (argv[2], type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "route-map doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+\f
+/* Configuration write function. */
+int
+config_write_if_rmap (struct vty *vty)
+{
+  int i;
+  struct hash_backet *mp;
+  int write = 0;
+
+  for (i = 0; i < ifrmaphash->size; i++)
+    for (mp = ifrmaphash->index[i]; mp; mp = mp->next)
+      {
+       struct if_rmap *if_rmap;
+
+       if_rmap = mp->data;
+
+       if (if_rmap->routemap[IF_RMAP_IN])
+         {
+           vty_out (vty, " route-map %s in %s%s", 
+                    if_rmap->routemap[IF_RMAP_IN],
+                    if_rmap->ifname,
+                    VTY_NEWLINE);
+           write++;
+         }
+
+       if (if_rmap->routemap[IF_RMAP_OUT])
+         {
+           vty_out (vty, " route-map %s out %s%s", 
+                    if_rmap->routemap[IF_RMAP_OUT],
+                    if_rmap->ifname,
+                    VTY_NEWLINE);
+           write++;
+         }
+      }
+  return write;
+}
+
+void
+if_rmap_reset ()
+{
+  hash_clean (ifrmaphash, (void (*) (void *)) if_rmap_free);
+}
+
+void
+if_rmap_init (int node)
+{
+  ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp);
+
+  install_element (node, &if_rmap_cmd);
+  install_element (node, &no_if_rmap_cmd);
+}
diff --git a/lib/if_rmap.h b/lib/if_rmap.h
new file mode 100644 (file)
index 0000000..a9355ab
--- /dev/null
@@ -0,0 +1,47 @@
+/* route-map for interface.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_IF_RMAP_H
+#define _ZEBRA_IF_RMAP_H
+
+enum if_rmap_type
+{
+  IF_RMAP_IN,
+  IF_RMAP_OUT,
+  IF_RMAP_MAX
+};
+
+struct if_rmap
+{
+  /* Name of the interface. */
+  char *ifname;
+
+  char *routemap[IF_RMAP_MAX];
+};
+
+void if_rmap_init (int);
+void if_rmap_reset (void);
+void if_rmap_hook_add (void (*) (struct if_rmap *));
+void if_rmap_hook_delete (void (*) (struct if_rmap *));
+struct if_rmap *if_rmap_lookup (char *);
+int config_write_if_rmap (struct vty *);
+
+#endif /* _ZEBRA_IF_RMAP_H */
diff --git a/lib/keychain.c b/lib/keychain.c
new file mode 100644 (file)
index 0000000..dbf431a
--- /dev/null
@@ -0,0 +1,1001 @@
+/* key-chain for authentication.
+   Copyright (C) 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; either version 2, or (at your
+option) any later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "linklist.h"
+#include "keychain.h"
+
+/* Master list of key chain. */
+struct list *keychain_list;
+
+struct keychain *
+keychain_new ()
+{
+  struct keychain *new;
+  new = XMALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain));
+  memset (new, 0, sizeof (struct keychain));
+  return new;
+}
+
+void
+keychain_free (struct keychain *keychain)
+{
+  XFREE (MTYPE_KEYCHAIN, keychain);
+}
+
+struct key *
+key_new ()
+{
+  struct key *new;
+  new = XMALLOC (MTYPE_KEY, sizeof (struct key));
+  memset (new, 0, sizeof (struct key));
+  return new;
+}
+
+void
+key_free (struct key *key)
+{
+  XFREE (MTYPE_KEY, key);
+}
+
+struct keychain *
+keychain_lookup (char *name)
+{
+  struct listnode *nn;
+  struct keychain *keychain;
+
+  if (name == NULL)
+    return NULL;
+
+  LIST_LOOP (keychain_list, keychain, nn)
+    {
+      if (strcmp (keychain->name, name) == 0)
+       return keychain;
+    }
+  return NULL;
+}
+
+int
+key_cmp_func (struct key *k1, struct key *k2)
+{
+  if (k1->index > k2->index)
+    return 1;
+  if (k1->index < k2->index)
+    return -1;
+  return 0;
+}
+
+void
+key_delete_func (struct key *key)
+{
+  if (key->string)
+    free (key->string);
+  key_free (key);
+}
+
+struct keychain *
+keychain_get (char *name)
+{
+  struct keychain *keychain;
+
+  keychain = keychain_lookup (name);
+
+  if (keychain)
+    return keychain;
+
+  keychain = keychain_new ();
+  keychain->name = strdup (name);
+  keychain->key = list_new ();
+  keychain->key->cmp = (int (*)(void *, void *)) key_cmp_func;
+  keychain->key->del = (void (*)(void *)) key_delete_func;
+  listnode_add (keychain_list, keychain);
+
+  return keychain;
+}
+
+void
+keychain_delete (struct keychain *keychain)
+{
+  if (keychain->name)
+    free (keychain->name);
+
+  list_delete (keychain->key);
+  listnode_delete (keychain_list, keychain);
+  keychain_free (keychain);
+}
+
+struct key *
+key_lookup (struct keychain *keychain, u_int32_t index)
+{
+  struct listnode *nn;
+  struct key *key;
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->index == index)
+       return key;
+    }
+  return NULL;
+}
+
+struct key *
+key_lookup_for_accept (struct keychain *keychain, u_int32_t index)
+{
+  struct listnode *nn;
+  struct key *key;
+  time_t now;
+
+  now = time (NULL);
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->index >= index)
+       {
+         if (key->accept.start == 0)
+           return key;
+
+         if (key->accept.start <= now)
+           if (key->accept.end >= now || key->accept.end == -1)
+             return key;
+       }
+    }
+  return NULL;
+}
+
+struct key *
+key_match_for_accept (struct keychain *keychain, char *auth_str)
+{
+  struct listnode *nn;
+  struct key *key;
+  time_t now;
+
+  now = time (NULL);
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->accept.start == 0 ||
+         (key->accept.start <= now &&
+          (key->accept.end >= now || key->accept.end == -1)))
+       if (strncmp (key->string, auth_str, 16) == 0)
+         return key;
+    }
+  return NULL;
+}
+
+struct key *
+key_lookup_for_send (struct keychain *keychain)
+{
+  struct listnode *nn;
+  struct key *key;
+  time_t now;
+
+  now = time (NULL);
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->send.start == 0)
+       return key;
+
+      if (key->send.start <= now)
+       if (key->send.end >= now || key->send.end == -1)
+         return key;
+    }
+  return NULL;
+}
+
+struct key *
+key_get (struct keychain *keychain, u_int32_t index)
+{
+  struct key *key;
+
+  key = key_lookup (keychain, index);
+
+  if (key)
+    return key;
+
+  key = key_new ();
+  key->index = index;
+  listnode_add_sort (keychain->key, key);
+
+  return key;
+}
+
+void
+key_delete (struct keychain *keychain, struct key *key)
+{
+  listnode_delete (keychain->key, key);
+
+  if (key->string)
+    free (key->string);
+  key_free (key);
+}
+\f
+DEFUN (key_chain,
+       key_chain_cmd,
+       "key chain WORD",
+       "Authentication key management\n"
+       "Key-chain management\n"
+       "Key-chain name\n")
+{
+  struct keychain *keychain;
+
+  keychain = keychain_get (argv[0]);
+  vty->index = keychain;
+  vty->node = KEYCHAIN_NODE;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_key_chain,
+       no_key_chain_cmd,
+       "no key chain WORD",
+       NO_STR
+       "Authentication key management\n"
+       "Key-chain management\n"
+       "Key-chain name\n")
+{
+  struct keychain *keychain;
+
+  keychain = keychain_lookup (argv[0]);
+
+  if (! keychain)
+    {
+      vty_out (vty, "Can't find keychain %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  keychain_delete (keychain);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (key,
+       key_cmd,
+       "key <0-2147483647>",
+       "Configure a key\n"
+       "Key identifier number\n")
+{
+  struct keychain *keychain;
+  struct key *key;
+  u_int32_t index;
+  char *endptr = NULL;
+
+  keychain = vty->index;
+
+  index = strtoul (argv[0], &endptr, 10);
+  if (index == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "Key identifier number error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  key = key_get (keychain, index);
+  vty->index_sub = key;
+  vty->node = KEYCHAIN_KEY_NODE;
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_key,
+       no_key_cmd,
+       "no key <0-2147483647>",
+       NO_STR
+       "Delete a key\n"
+       "Key identifier number\n")
+{
+  struct keychain *keychain;
+  struct key *key;
+  u_int32_t index;
+  char *endptr = NULL;
+  
+  keychain = vty->index;
+
+  index = strtoul (argv[0], &endptr, 10);
+  if (index == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "Key identifier number error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  key = key_lookup (keychain, index);
+  if (! key)
+    {
+      vty_out (vty, "Can't find key %d%s", index, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  key_delete (keychain, key);
+
+  vty->node = KEYCHAIN_NODE;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (key_string,
+       key_string_cmd,
+       "key-string LINE",
+       "Set key string\n"
+       "The key\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  if (key->string)
+    free (key->string);
+  key->string = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_key_string,
+       no_key_string_cmd,
+       "no key-string [LINE]",
+       NO_STR
+       "Unset key string\n"
+       "The key\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  if (key->string)
+    {
+      free (key->string);
+      key->string = NULL;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Convert HH:MM:SS MON DAY YEAR to time_t value.  -1 is returned when
+   given string is malformed. */
+time_t 
+key_str2time(char *time_str, char *day_str, char *month_str, char *year_str)
+{
+  int i = 0;
+  char *colon;
+  struct tm tm;
+  time_t time;
+  int sec, min, hour;
+  int day, month, year;
+  char *endptr = NULL;
+
+  char *month_name[] = 
+  {
+    "January",
+    "February",
+    "March",
+    "April",
+    "May",
+    "June",
+    "July",
+    "August",
+    "September",
+    "October",
+    "November",
+    "December",
+    NULL
+  };
+
+  /* Check hour field of time_str. */
+  colon = strchr (time_str, ':');
+  if (colon == NULL)
+    return -1;
+  *colon = '\0';
+
+  /* Hour must be between 0 and 23. */
+  hour = strtoul (time_str, &endptr, 10);
+  if (hour == ULONG_MAX || *endptr != '\0' || hour < 0 || hour > 23)
+    return -1;
+
+  /* Check min field of time_str. */
+  time_str = colon + 1;
+  colon = strchr (time_str, ':');
+  if (*time_str == '\0' || colon == NULL)
+    return -1;
+  *colon = '\0';
+
+  /* Min must be between 0 and 59. */
+  min = strtoul (time_str, &endptr, 10);
+  if (min == ULONG_MAX || *endptr != '\0' || min < 0 || min > 59)
+    return -1;
+
+  /* Check sec field of time_str. */
+  time_str = colon + 1;
+  if (*time_str == '\0')
+    return -1;
+  
+  /* Sec must be between 0 and 59. */
+  sec = strtoul (time_str, &endptr, 10);
+  if (sec == ULONG_MAX || *endptr != '\0' || sec < 0 || sec > 59)
+    return -1;
+  
+  /* Check day_str.  Day must be <1-31>. */
+  day = strtoul (day_str, &endptr, 10);
+  if (day == ULONG_MAX || *endptr != '\0' || day < 0 || day > 31)
+    return -1;
+
+  /* Check month_str.  Month must match month_name. */
+  month = 0;
+  if (strlen (month_str) >= 3)
+    for (i = 0; month_name[i]; i++)
+      if (strncmp (month_str, month_name[i], strlen (month_str)) == 0)
+       {
+         month = i;
+         break;
+       }
+  if (! month_name[i])
+    return -1;
+
+  /* Check year_str.  Year must be <1993-2035>. */
+  year = strtoul (year_str, &endptr, 10);
+  if (year == ULONG_MAX || *endptr != '\0' || year < 1993 || year > 2035)
+    return -1;
+  
+  memset (&tm, 0, sizeof (struct tm));
+  tm.tm_sec = sec;
+  tm.tm_min = min;
+  tm.tm_hour = hour;
+  tm.tm_mon = month;
+  tm.tm_mday = day;
+  tm.tm_year = year - 1900;
+    
+  time = mktime (&tm);
+
+  return time;
+}
+
+int
+key_lifetime_set (struct vty *vty, struct key_range *krange, char *stime_str,
+                 char *sday_str, char *smonth_str, char *syear_str,
+                 char *etime_str, char *eday_str, char *emonth_str,
+                 char *eyear_str)
+{
+  time_t time_start;
+  time_t time_end;
+    
+  time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str);
+  if (time_start < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  time_end = key_str2time (etime_str, eday_str, emonth_str, eyear_str);
+
+  if (time_end < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (time_end <= time_start)
+    {
+      vty_out (vty, "Expire time is not later than start time%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  krange->start = time_start;
+  krange->end = time_end;
+
+  return CMD_SUCCESS;
+}
+
+int
+key_lifetime_duration_set (struct vty *vty, struct key_range *krange,
+                          char *stime_str, char *sday_str, char *smonth_str,
+                          char *syear_str, char *duration_str)
+{
+  time_t time_start;
+  u_int32_t duration;
+  char *endptr = NULL;
+    
+  time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str);
+  if (time_start < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  krange->start = time_start;
+
+  duration = strtoul (duration_str, &endptr, 10);
+  if (duration == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "Malformed duration%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  krange->duration = 1;
+  krange->end = time_start + duration;
+
+  return CMD_SUCCESS;
+}
+
+int
+key_lifetime_infinite_set (struct vty *vty, struct key_range *krange,
+                          char *stime_str, char *sday_str, char *smonth_str,
+                          char *syear_str)
+{
+  time_t time_start;
+    
+  time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str);
+  if (time_start < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  krange->start = time_start;
+
+  krange->end = -1;
+
+  return CMD_SUCCESS;
+}
+\f
+DEFUN (accept_lifetime_day_month_day_month,
+       accept_lifetime_day_month_day_month_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2],
+                          argv[3], argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (accept_lifetime_day_month_month_day,
+       accept_lifetime_day_month_month_day_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2],
+                          argv[3], argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (accept_lifetime_month_day_day_month,
+       accept_lifetime_month_day_day_month_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1],
+                          argv[3], argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (accept_lifetime_month_day_month_day,
+       accept_lifetime_month_day_month_day_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1],
+                          argv[3], argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (accept_lifetime_infinite_day_month,
+       accept_lifetime_infinite_day_month_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[1],
+                                   argv[2], argv[3]);
+}
+
+DEFUN (accept_lifetime_infinite_month_day,
+       accept_lifetime_infinite_month_day_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[2],
+                                   argv[1], argv[3]);
+}
+
+DEFUN (accept_lifetime_duration_day_month,
+       accept_lifetime_duration_day_month_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[1],
+                                   argv[2], argv[3], argv[4]);
+}
+
+DEFUN (accept_lifetime_duration_month_day,
+       accept_lifetime_duration_month_day_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[2],
+                                   argv[1], argv[3], argv[4]);
+}
+\f
+DEFUN (send_lifetime_day_month_day_month,
+       send_lifetime_day_month_day_month_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3],
+                          argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (send_lifetime_day_month_month_day,
+       send_lifetime_day_month_month_day_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3],
+                          argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (send_lifetime_month_day_day_month,
+       send_lifetime_month_day_day_month_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3],
+                          argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (send_lifetime_month_day_month_day,
+       send_lifetime_month_day_month_day_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3],
+                          argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (send_lifetime_infinite_day_month,
+       send_lifetime_infinite_day_month_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[1], argv[2],
+                                   argv[3]);
+}
+
+DEFUN (send_lifetime_infinite_month_day,
+       send_lifetime_infinite_month_day_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[2], argv[1],
+                                   argv[3]);
+}
+
+DEFUN (send_lifetime_duration_day_month,
+       send_lifetime_duration_day_month_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->send, argv[0], argv[1], argv[2],
+                                   argv[3], argv[4]);
+}
+
+DEFUN (send_lifetime_duration_month_day,
+       send_lifetime_duration_month_day_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->send, argv[0], argv[2], argv[1],
+                                   argv[3], argv[4]);
+}
+\f
+struct cmd_node keychain_node =
+{
+  KEYCHAIN_NODE,
+  "%s(config-keychain)# ",
+  1
+};
+
+struct cmd_node keychain_key_node =
+{
+  KEYCHAIN_KEY_NODE,
+  "%s(config-keychain-key)# ",
+  1
+};
+
+int
+keychain_strftime (char *buf, int bufsiz, time_t *time)
+{
+  struct tm *tm;
+  size_t len;
+
+  tm = localtime (time);
+
+  len = strftime (buf, bufsiz, "%T %b %d %Y", tm);
+
+  return len;
+}
+
+int
+keychain_config_write (struct vty *vty)
+{
+  struct keychain *keychain;
+  struct key *key;
+  struct listnode *nn;
+  struct listnode *nm;
+  char buf[BUFSIZ];
+
+  LIST_LOOP (keychain_list, keychain, nn)
+    {
+      vty_out (vty, "key chain %s%s", keychain->name, VTY_NEWLINE);
+      
+      LIST_LOOP (keychain->key, key, nm)
+       {
+         vty_out (vty, " key %d%s", key->index, VTY_NEWLINE);
+
+         if (key->string)
+           vty_out (vty, "  key-string %s%s", key->string, VTY_NEWLINE);
+
+         if (key->accept.start)
+           {
+             keychain_strftime (buf, BUFSIZ, &key->accept.start);
+             vty_out (vty, "  accept-lifetime %s", buf);
+
+             if (key->accept.end == -1)
+               vty_out (vty, " infinite");
+             else if (key->accept.duration)
+               vty_out (vty, " duration %ld",
+                        key->accept.end - key->accept.start);
+             else
+               {
+                 keychain_strftime (buf, BUFSIZ, &key->accept.end);
+                 vty_out (vty, " %s", buf);
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+
+         if (key->send.start)
+           {
+             keychain_strftime (buf, BUFSIZ, &key->send.start);
+             vty_out (vty, "  send-lifetime %s", buf);
+
+             if (key->send.end == -1)
+               vty_out (vty, " infinite");
+             else if (key->send.duration)
+               vty_out (vty, " duration %ld", key->send.end - key->send.start);
+             else
+               {
+                 keychain_strftime (buf, BUFSIZ, &key->send.end);
+                 vty_out (vty, " %s", buf);
+               }
+             vty_out (vty, "%s", VTY_NEWLINE);
+           }
+       }
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+keychain_init ()
+{
+  keychain_list = list_new ();
+
+  install_node (&keychain_node, keychain_config_write);
+  install_node (&keychain_key_node, NULL);
+
+  install_default (KEYCHAIN_NODE);
+  install_default (KEYCHAIN_KEY_NODE);
+
+  install_element (CONFIG_NODE, &key_chain_cmd);
+  install_element (CONFIG_NODE, &no_key_chain_cmd);
+  install_element (KEYCHAIN_NODE, &key_cmd);
+  install_element (KEYCHAIN_NODE, &no_key_cmd);
+
+  install_element (KEYCHAIN_NODE, &key_chain_cmd);
+  install_element (KEYCHAIN_NODE, &no_key_chain_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &key_string_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &key_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd);
+}
diff --git a/lib/keychain.h b/lib/keychain.h
new file mode 100644 (file)
index 0000000..0cfa3d5
--- /dev/null
@@ -0,0 +1,56 @@
+/* key-chain for authentication.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_KEYCHAIN_H
+#define _ZEBRA_KEYCHAIN_H
+
+struct keychain
+{
+  char *name;
+
+  struct list *key;
+};
+
+struct key_range
+{
+  time_t start;
+  time_t end;
+
+  u_char duration;
+};
+
+struct key
+{
+  u_int32_t index;
+
+  char *string;
+
+  struct key_range send;
+  struct key_range accept;
+};
+
+void keychain_init ();
+struct keychain *keychain_lookup (char *);
+struct key *key_lookup_for_accept (struct keychain *, u_int32_t);
+struct key *key_match_for_accept (struct keychain *, char *);
+struct key *key_lookup_for_send (struct keychain *);
+
+#endif /* _ZEBRA_KEYCHAIN_H */
diff --git a/lib/linklist.c b/lib/linklist.c
new file mode 100644 (file)
index 0000000..5a2b696
--- /dev/null
@@ -0,0 +1,312 @@
+/* Generic linked list routine.
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "memory.h"
+\f
+/* Allocate new list. */
+struct list *
+list_new ()
+{
+  struct list *new;
+
+  new = XMALLOC (MTYPE_LINK_LIST, sizeof (struct list));
+  memset (new, 0, sizeof (struct list));
+  return new;
+}
+
+/* Free list. */
+void
+list_free (struct list *l)
+{
+  XFREE (MTYPE_LINK_LIST, l);
+}
+
+/* Allocate new listnode.  Internal use only. */
+static struct listnode *
+listnode_new ()
+{
+  struct listnode *node;
+
+  node = XMALLOC (MTYPE_LINK_NODE, sizeof (struct listnode));
+  memset (node, 0, sizeof (struct listnode));
+  return node;
+}
+
+/* Free listnode. */
+static void
+listnode_free (struct listnode *node)
+{
+  XFREE (MTYPE_LINK_NODE, node);
+}
+\f
+/* Add new data to the list. */
+void
+listnode_add (struct list *list, void *val)
+{
+  struct listnode *node;
+
+  node = listnode_new ();
+
+  node->prev = list->tail;
+  node->data = val;
+
+  if (list->head == NULL)
+    list->head = node;
+  else
+    list->tail->next = node;
+  list->tail = node;
+
+  list->count++;
+}
+
+/* Add new node with sort function. */
+void
+listnode_add_sort (struct list *list, void *val)
+{
+  struct listnode *n;
+  struct listnode *new;
+
+  new = listnode_new ();
+  new->data = val;
+
+  if (list->cmp)
+    {
+      for (n = list->head; n; n = n->next)
+       {
+         if ((*list->cmp) (val, n->data) < 0)
+           {       
+             new->next = n;
+             new->prev = n->prev;
+
+             if (n->prev)
+               n->prev->next = new;
+             else
+               list->head = new;
+             n->prev = new;
+             list->count++;
+             return;
+           }
+       }
+    }
+
+  new->prev = list->tail;
+
+  if (list->tail)
+    list->tail->next = new;
+  else
+    list->head = new;
+
+  list->tail = new;
+  list->count++;
+}
+
+void
+listnode_add_after (struct list *list, struct listnode *pp, void *val)
+{
+  struct listnode *nn;
+
+  nn = listnode_new ();
+  nn->data = val;
+
+  if (pp == NULL)
+    {
+      if (list->head)
+       list->head->prev = nn;
+      else
+       list->tail = nn;
+
+      nn->next = list->head;
+      nn->prev = pp;
+
+      list->head = nn;
+    }
+  else
+    {
+      if (pp->next)
+       pp->next->prev = nn;
+      else
+       list->tail = nn;
+
+      nn->next = pp->next;
+      nn->prev = pp;
+
+      pp->next = nn;
+    }
+}
+
+
+/* Delete specific date pointer from the list. */
+void
+listnode_delete (struct list *list, void *val)
+{
+  struct listnode *node;
+
+  for (node = list->head; node; node = node->next)
+    {
+      if (node->data == val)
+       {
+         if (node->prev)
+           node->prev->next = node->next;
+         else
+           list->head = node->next;
+
+         if (node->next)
+           node->next->prev = node->prev;
+         else
+           list->tail = node->prev;
+
+         list->count--;
+         listnode_free (node);
+         return;
+       }
+    }
+}
+
+/* Return first node's data if it is there.  */
+void *
+listnode_head (struct list *list)
+{
+  struct listnode *node;
+
+  node = list->head;
+
+  if (node)
+    return node->data;
+  return NULL;
+}
+
+/* Delete all listnode from the list. */
+void
+list_delete_all_node (struct list *list)
+{
+  struct listnode *node;
+  struct listnode *next;
+
+  for (node = list->head; node; node = next)
+    {
+      next = node->next;
+      if (list->del)
+       (*list->del) (node->data);
+      listnode_free (node);
+    }
+  list->head = list->tail = NULL;
+  list->count = 0;
+}
+
+/* Delete all listnode then free list itself. */
+void
+list_delete (struct list *list)
+{
+  struct listnode *node;
+  struct listnode *next;
+
+  for (node = list->head; node; node = next)
+    {
+      next = node->next;
+      if (list->del)
+       (*list->del) (node->data);
+      listnode_free (node);
+    }
+  list_free (list);
+}
+
+/* Lookup the node which has given data. */
+struct listnode *
+listnode_lookup (struct list *list, void *data)
+{
+  listnode node;
+
+  for (node = list->head; node; nextnode (node))
+    if (data == getdata (node))
+      return node;
+  return NULL;
+}
+\f
+/* Delete the node from list.  For ospfd and ospf6d. */
+void
+list_delete_node (list list, listnode node)
+{
+  if (node->prev)
+    node->prev->next = node->next;
+  else
+    list->head = node->next;
+  if (node->next)
+    node->next->prev = node->prev;
+  else
+    list->tail = node->prev;
+  list->count--;
+  listnode_free (node);
+}
+\f
+/* ospf_spf.c */
+void
+list_add_node_prev (list list, listnode current, void *val)
+{
+  struct listnode *node;
+
+  node = listnode_new ();
+  node->next = current;
+  node->data = val;
+
+  if (current->prev == NULL)
+    list->head = node;
+  else
+    current->prev->next = node;
+
+  node->prev = current->prev;
+  current->prev = node;
+
+  list->count++;
+}
+
+/* ospf_spf.c */
+void
+list_add_node_next (list list, listnode current, void *val)
+{
+  struct listnode *node;
+
+  node = listnode_new ();
+  node->prev = current;
+  node->data = val;
+
+  if (current->next == NULL)
+    list->tail = node;
+  else
+    current->next->prev = node;
+
+  node->next = current->next;
+  current->next = node;
+
+  list->count++;
+}
+
+/* ospf_spf.c */
+void
+list_add_list (struct list *l, struct list *m)
+{
+  struct listnode *n;
+
+  for (n = listhead (m); n; nextnode (n))
+    listnode_add (l, n->data);
+}
diff --git a/lib/linklist.h b/lib/linklist.h
new file mode 100644 (file)
index 0000000..a91947c
--- /dev/null
@@ -0,0 +1,101 @@
+/* Generic linked list
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_LINKLIST_H
+#define _ZEBRA_LINKLIST_H
+
+typedef struct list *list;
+typedef struct listnode *listnode;
+
+struct listnode 
+{
+  struct listnode *next;
+  struct listnode *prev;
+  void *data;
+};
+
+struct list 
+{
+  struct listnode *head;
+  struct listnode *tail;
+  unsigned int count;
+  int (*cmp) (void *val1, void *val2);
+  void (*del) (void *val);
+};
+
+#define nextnode(X) ((X) = (X)->next)
+#define listhead(X) ((X)->head)
+#define listcount(X) ((X)->count)
+#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
+#define getdata(X) ((X)->data)
+
+/* Prototypes. */
+struct list *list_new();
+void list_free (struct list *);
+
+void listnode_add (struct list *, void *);
+void listnode_add_sort (struct list *, void *);
+void listnode_add_after (struct list *, struct listnode *, void *);
+void listnode_delete (struct list *, void *);
+struct listnode *listnode_lookup (struct list *, void *);
+void *listnode_head (struct list *);
+
+void list_delete (struct list *);
+void list_delete_all_node (struct list *);
+
+/* For ospfd and ospf6d. */
+void list_delete_node (list, listnode);
+
+/* For ospf_spf.c */
+void list_add_node_prev (list, listnode, void *);
+void list_add_node_next (list, listnode, void *);
+void list_add_list (list, list);
+
+/* List iteration macro. */
+#define LIST_LOOP(L,V,N) \
+  for ((N) = (L)->head; (N); (N) = (N)->next) \
+    if (((V) = (N)->data) != NULL)
+
+/* List node add macro.  */
+#define LISTNODE_ADD(L,N) \
+  do { \
+    (N)->prev = (L)->tail; \
+    if ((L)->head == NULL) \
+      (L)->head = (N); \
+    else \
+      (L)->tail->next = (N); \
+    (L)->tail = (N); \
+  } while (0)
+
+/* List node delete macro.  */
+#define LISTNODE_DELETE(L,N) \
+  do { \
+    if ((N)->prev) \
+      (N)->prev->next = (N)->next; \
+    else \
+      (L)->head = (N)->next; \
+    if ((N)->next) \
+      (N)->next->prev = (N)->prev; \
+    else \
+      (L)->tail = (N)->prev; \
+  } while (0)
+
+#endif /* _ZEBRA_LINKLIST_H */
diff --git a/lib/log.c b/lib/log.c
new file mode 100644 (file)
index 0000000..9c67642
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,483 @@
+/* Logging of zebra
+ * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <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",
+  "MASC",
+  NULL,
+};
+
+const char *zlog_priority[] =
+{
+  "emergencies",
+  "alerts",
+  "critical",
+  "errors",
+  "warnings",
+  "notifications",
+  "informational",
+  "debugging",
+  NULL,
+};
+  
+
+\f
+/* 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);
+}
+\f
+/* 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]);
+}
+
+\f
+/* 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;
+}
+\f
+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);
+}
+\f
+/* Message lookup function. */
+char *
+lookup (struct message *mes, int key)
+{
+  struct message *pnt;
+
+  for (pnt = mes; pnt->key != 0; pnt++) 
+    if (pnt->key == key) 
+      return pnt->str;
+
+  return "";
+}
+
+/* Very old hacky version of message lookup function.  Still partly
+   used in bgpd and ospfd. */
+char *
+mes_lookup (struct message *meslist, int max, int index)
+{
+  if (index < 0 || index >= max) 
+    {
+      zlog_err ("message index out of bound: %d", max);
+      return NULL;
+    }
+  return meslist[index].str;
+}
diff --git a/lib/log.h b/lib/log.h
new file mode 100644 (file)
index 0000000..69919b4
--- /dev/null
+++ b/lib/log.h
@@ -0,0 +1,128 @@
+/* Zebra logging funcions.
+ * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_LOG_H
+#define _ZEBRA_LOG_H
+
+#include <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_MASC
+} zlog_proto_t;
+
+struct zlog 
+{
+  const char *ident;
+  zlog_proto_t protocol;
+  int flags;
+  FILE *fp;
+  char *filename;
+  int syslog;
+  int stat;
+  int connected;
+  int maskpri;         /* as per syslog setlogmask */
+  int priority;                /* as per syslog priority */
+  int facility;                /* as per syslog facility */
+  int record_priority;
+};
+
+/* Message structure. */
+struct message
+{
+  int key;
+  char *str;
+};
+
+/* Default logging strucutre. */
+extern struct zlog *zlog_default;
+
+/* Open zlog function */
+struct zlog *openzlog (const char *, int, zlog_proto_t, int, int);
+
+/* Close zlog function. */
+void closezlog (struct zlog *zl);
+
+/* GCC have printf type attribute check.  */
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* __GNUC__ */
+
+/* Generic function for zlog. */
+void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+
+/* Handy zlog functions. */
+void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/* For bgpd's peer oriented log. */
+void plog_err (struct zlog *, const char *format, ...);
+void plog_warn (struct zlog *, const char *format, ...);
+void plog_info (struct zlog *, const char *format, ...);
+void plog_notice (struct zlog *, const char *format, ...);
+void plog_debug (struct zlog *, const char *format, ...);
+
+/* Set zlog flags. */
+void zlog_set_flag (struct zlog *zl, int flags);
+void zlog_reset_flag (struct zlog *zl, int flags);
+
+/* Set zlog filename. */
+int zlog_set_file (struct zlog *zl, int flags, char *filename);
+int zlog_reset_file (struct zlog *zl);
+
+/* Rotate log. */
+int zlog_rotate ();
+
+/* For hackey massage lookup and check */
+#define LOOKUP(x, y) mes_lookup(x, x ## _max, y)
+
+char *lookup (struct message *, int);
+char *mes_lookup (struct message *meslist, int max, int index);
+
+extern const char *zlog_priority[];
+
+#endif /* _ZEBRA_LOG_H */
diff --git a/lib/md5-gnu.h b/lib/md5-gnu.h
new file mode 100644 (file)
index 0000000..dacc1ae
--- /dev/null
@@ -0,0 +1,156 @@
+/* Declaration of functions and data types used for MD5 sum computing
+   library functions.
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+   to determine an unsigned integral type that is 32 bits wide.  An
+   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+   doing that would require that the configure script compile and *run*
+   the resulting executable.  Locally running cross-compiled executables
+   is usually not possible.  */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+#else
+# if defined __STDC__ && __STDC__
+#  define UINT_MAX_32_BITS 4294967295U
+# else
+#  define UINT_MAX_32_BITS 0xFFFFFFFF
+# endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+   This should be valid for all systems GNU cares about because
+   that doesn't include 16-bit systems, and only modern systems
+   (that certainly have <limits.h>) have 64+-bit integral types.  */
+
+# ifndef UINT_MAX
+#  define UINT_MAX UINT_MAX_32_BITS
+# endif
+
+# if UINT_MAX == UINT_MAX_32_BITS
+   typedef unsigned int md5_uint32;
+# else
+#  if USHRT_MAX == UINT_MAX_32_BITS
+    typedef unsigned short md5_uint32;
+#  else
+#   if ULONG_MAX == UINT_MAX_32_BITS
+     typedef unsigned long md5_uint32;
+#   else
+     /* The following line is intended to evoke an error.
+        Using #error is not portable enough.  */
+     "Cannot determine unsigned 32-bit data type."
+#   endif
+#  endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+# define __P(x) x
+#else
+# define __P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps.  */
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+extern void __md5_init_ctx __P ((struct md5_ctx *ctx));
+extern void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void __md5_process_block __P ((const void *buffer, size_t len,
+                                     struct md5_ctx *ctx));
+extern void md5_process_block __P ((const void *buffer, size_t len,
+                                   struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void __md5_process_bytes __P ((const void *buffer, size_t len,
+                                     struct md5_ctx *ctx));
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+                                   struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 16 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+extern int __md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *__md5_buffer __P ((const char *buffer, size_t len,
+                               void *resblock));
+extern void *md5_buffer __P ((const char *buffer, size_t len,
+                             void *resblock));
+
+#endif /* md5.h */
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644 (file)
index 0000000..2068c46
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,447 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+   according to the definition of MD5 in RFC 1321 from April 1992.
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+#  define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include "md5-gnu.h"
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+   protected using leading __ and use weak aliases.  */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_read_ctx __md5_read_ctx
+# define md5_stream __md5_stream
+# define md5_buffer __md5_buffer
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n)                                                       \
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+void
+md5_init_ctx (ctx)
+     struct md5_ctx *ctx;
+{
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result
+   must be in little endian byte order.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_read_ctx (ctx, resbuf)
+     const struct md5_ctx *ctx;
+     void *resbuf;
+{
+  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+  return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_finish_ctx (ctx, resbuf)
+     struct md5_ctx *ctx;
+     void *resbuf;
+{
+  /* Take yet unprocessed bytes into account.  */
+  md5_uint32 bytes = ctx->buflen;
+  size_t pad;
+
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
+
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+  memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+                                                       (ctx->total[0] >> 29));
+
+  /* Process last bytes.  */
+  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+  return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+md5_stream (stream, resblock)
+     FILE *stream;
+     void *resblock;
+{
+  /* Important: BLOCKSIZE must be a multiple of 64.  */
+#define BLOCKSIZE 4096
+  struct md5_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
+
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+        computation function processes the whole buffer so that with the
+        next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
+
+      /* Read block.  Take care for partial reads.  */
+      do
+       {
+         n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+         sum += n;
+       }
+      while (sum < BLOCKSIZE && n != 0);
+      if (n == 0 && ferror (stream))
+        return 1;
+
+      /* If end of file is reached, end the loop.  */
+      if (n == 0)
+       break;
+
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+                       BLOCKSIZE % 64 == 0
+       */
+      md5_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+  /* Add the last bytes if necessary.  */
+  if (sum > 0)
+    md5_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  md5_finish_ctx (&ctx, resblock);
+  return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+void *
+md5_buffer (buffer, len, resblock)
+     const char *buffer;
+     size_t len;
+     void *resblock;
+{
+  struct md5_ctx ctx;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
+
+  /* Process whole buffer but last len % 64 bytes.  */
+  md5_process_bytes (buffer, len, &ctx);
+
+  /* Put result in desired memory area.  */
+  return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (buffer, len, ctx)
+     const void *buffer;
+     size_t len;
+     struct md5_ctx *ctx;
+{
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0)
+    {
+      size_t left_over = ctx->buflen;
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+      memcpy (&ctx->buffer[left_over], buffer, add);
+      ctx->buflen += add;
+
+      if (left_over + add > 64)
+       {
+         md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+         /* The regions in the following copy operation cannot overlap.  */
+         memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+                 (left_over + add) & 63);
+         ctx->buflen = (left_over + add) & 63;
+       }
+
+      buffer = (const char *) buffer + add;
+      len -= add;
+    }
+
+  /* Process available complete blocks.  */
+  if (len > 64)
+    {
+      md5_process_block (buffer, len & ~63, ctx);
+      buffer = (const char *) buffer + (len & ~63);
+      len &= 63;
+    }
+
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0)
+    {
+      memcpy (ctx->buffer, buffer, len);
+      ctx->buflen = len;
+    }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+   and defined in the RFC 1321.  The first function is a little bit optimized
+   (as found in Colin Plumbs public domain implementation).  */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.  */
+
+void
+md5_process_block (buffer, len, ctx)
+     const void *buffer;
+     size_t len;
+     struct md5_ctx *ctx;
+{
+  md5_uint32 correct_words[16];
+  const md5_uint32 *words = buffer;
+  size_t nwords = len / sizeof (md5_uint32);
+  const md5_uint32 *endp = words + nwords;
+  md5_uint32 A = ctx->A;
+  md5_uint32 B = ctx->B;
+  md5_uint32 C = ctx->C;
+  md5_uint32 D = ctx->D;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+  /* Process all bytes in the buffer with 64 bytes in each round of
+     the loop.  */
+  while (words < endp)
+    {
+      md5_uint32 *cwp = correct_words;
+      md5_uint32 A_save = A;
+      md5_uint32 B_save = B;
+      md5_uint32 C_save = C;
+      md5_uint32 D_save = D;
+
+      /* First round: using the given function, the context and a constant
+        the next context is computed.  Because the algorithms processing
+        unit is a 32-bit word and it is determined to work on words in
+        little endian byte order we perhaps have to change the byte order
+        before the computation.  To reduce the work for the next steps
+        we store the swapped words in the array CORRECT_WORDS.  */
+
+#define OP(a, b, c, d, s, T)                                           \
+      do                                                               \
+        {                                                              \
+         a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;             \
+         ++words;                                                      \
+         CYCLIC (a, s);                                                \
+         a += b;                                                       \
+        }                                                              \
+      while (0)
+
+      /* It is unfortunate that C does not provide an operator for
+        cyclic rotation.  Hope the C compiler is smart enough.  */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+      /* Before we start, one word to the strange constants.
+        They are defined in RFC 1321 as
+
+        T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+       */
+
+      /* Round 1.  */
+      OP (A, B, C, D,  7, 0xd76aa478);
+      OP (D, A, B, C, 12, 0xe8c7b756);
+      OP (C, D, A, B, 17, 0x242070db);
+      OP (B, C, D, A, 22, 0xc1bdceee);
+      OP (A, B, C, D,  7, 0xf57c0faf);
+      OP (D, A, B, C, 12, 0x4787c62a);
+      OP (C, D, A, B, 17, 0xa8304613);
+      OP (B, C, D, A, 22, 0xfd469501);
+      OP (A, B, C, D,  7, 0x698098d8);
+      OP (D, A, B, C, 12, 0x8b44f7af);
+      OP (C, D, A, B, 17, 0xffff5bb1);
+      OP (B, C, D, A, 22, 0x895cd7be);
+      OP (A, B, C, D,  7, 0x6b901122);
+      OP (D, A, B, C, 12, 0xfd987193);
+      OP (C, D, A, B, 17, 0xa679438e);
+      OP (B, C, D, A, 22, 0x49b40821);
+
+      /* For the second to fourth round we have the possibly swapped words
+        in CORRECT_WORDS.  Redefine the macro to take an additional first
+        argument specifying the function to use.  */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T)                                     \
+      do                                                               \
+       {                                                               \
+         a += f (b, c, d) + correct_words[k] + T;                      \
+         CYCLIC (a, s);                                                \
+         a += b;                                                       \
+       }                                                               \
+      while (0)
+
+      /* Round 2.  */
+      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
+      OP (FG, D, A, B, C,  6,  9, 0xc040b340);
+      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
+      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
+      OP (FG, D, A, B, C, 10,  9, 0x02441453);
+      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
+      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
+      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
+      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
+      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
+      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
+      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
+      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
+      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+      /* Round 3.  */
+      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
+      OP (FH, D, A, B, C,  8, 11, 0x8771f681);
+      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
+      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
+      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
+      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
+      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
+      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
+      OP (FH, B, C, D, A,  6, 23, 0x04881d05);
+      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
+      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);
+
+      /* Round 4.  */
+      OP (FI, A, B, C, D,  0,  6, 0xf4292244);
+      OP (FI, D, A, B, C,  7, 10, 0x432aff97);
+      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
+      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
+      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
+      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
+      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
+      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+      OP (FI, C, D, A, B,  6, 15, 0xa3014314);
+      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
+      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
+      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);
+
+      /* Add the starting values of the context.  */
+      A += A_save;
+      B += B_save;
+      C += C_save;
+      D += D_save;
+    }
+
+  /* Put checksum in context given as argument.  */
+  ctx->A = A;
+  ctx->B = B;
+  ctx->C = C;
+  ctx->D = D;
+}
+
+
+#ifdef _LIBC
+/* Define weak aliases.  */
+# undef md5_init_ctx
+weak_alias (__md5_init_ctx, md5_init_ctx)
+# undef md5_process_block
+weak_alias (__md5_process_block, md5_process_block)
+# undef md5_process_bytes
+weak_alias (__md5_process_bytes, md5_process_bytes)
+# undef md5_finish_ctx
+weak_alias (__md5_finish_ctx, md5_finish_ctx)
+# undef md5_read_ctx
+weak_alias (__md5_read_ctx, md5_read_ctx)
+# undef md5_stream
+weak_alias (__md5_stream, md5_stream)
+# undef md5_buffer
+weak_alias (__md5_buffer, md5_buffer)
+#endif
diff --git a/lib/memory.c b/lib/memory.c
new file mode 100644 (file)
index 0000000..bf142dc
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Memory management routine
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+void alloc_inc (int);
+void alloc_dec (int);
+\f
+struct message mstr [] =
+{
+  { MTYPE_THREAD, "thread" },
+  { MTYPE_THREAD_MASTER, "thread_master" },
+  { MTYPE_VECTOR, "vector" },
+  { MTYPE_VECTOR_INDEX, "vector_index" },
+  { MTYPE_IF, "interface" },
+  { 0, NULL },
+};
+\f
+/* 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;
+}
+\f
+#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--;
+}
+\f
+/* Looking up memory status from vty interface. */
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+
+/* For pretty printng of memory allocate information. */
+struct memory_list
+{
+  int index;
+  char *format;
+};
+
+struct memory_list memory_list_lib[] =
+{
+  { MTYPE_TMP,                "Temporary memory" },
+  { MTYPE_ROUTE_TABLE,        "Route table     " },
+  { MTYPE_ROUTE_NODE,         "Route node      " },
+  { MTYPE_RIB,                "RIB             " },
+  { MTYPE_NEXTHOP,            "Nexthop         " },
+  { MTYPE_LINK_LIST,          "Link List       " },
+  { MTYPE_LINK_NODE,          "Link Node       " },
+  { MTYPE_HASH,               "Hash            " },
+  { MTYPE_HASH_BACKET,        "Hash Bucket     " },
+  { MTYPE_ACCESS_LIST,        "Access List     " },
+  { MTYPE_ACCESS_LIST_STR,    "Access List Str " },
+  { MTYPE_ACCESS_FILTER,      "Access Filter   " },
+  { MTYPE_PREFIX_LIST,        "Prefix List     " },
+  { MTYPE_PREFIX_LIST_STR,    "Prefix List Str " },
+  { MTYPE_PREFIX_LIST_ENTRY,  "Prefix List Entry "},
+  { MTYPE_ROUTE_MAP,          "Route map       " },
+  { MTYPE_ROUTE_MAP_NAME,     "Route map name  " },
+  { MTYPE_ROUTE_MAP_INDEX,    "Route map index " },
+  { MTYPE_ROUTE_MAP_RULE,     "Route map rule  " },
+  { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
+  { MTYPE_DESC,               "Command desc    " },
+  { MTYPE_BUFFER,             "Buffer          " },
+  { MTYPE_BUFFER_DATA,        "Buffer data     " },
+  { MTYPE_STREAM,             "Stream          " },
+  { MTYPE_KEYCHAIN,           "Key chain       " },
+  { MTYPE_KEY,                "Key             " },
+  { MTYPE_VTY,                "VTY             " },
+  { -1, NULL }
+};
+
+struct memory_list memory_list_bgp[] =
+{
+  { MTYPE_BGP_PEER,               "BGP peer" },
+  { MTYPE_ATTR,                   "BGP attribute" },
+  { MTYPE_AS_PATH,                "BGP aspath" },
+  { MTYPE_AS_SEG,                 "BGP aspath seg" },
+  { MTYPE_AS_STR,                 "BGP aspath str" },
+  { 0, NULL },
+  { MTYPE_BGP_TABLE,              "BGP table" },
+  { MTYPE_BGP_NODE,               "BGP node" },
+  { MTYPE_BGP_ADVERTISE_ATTR,     "BGP adv attr" },
+  { MTYPE_BGP_ADVERTISE,          "BGP adv" },
+  { MTYPE_BGP_ADJ_IN,             "BGP adj in" },
+  { MTYPE_BGP_ADJ_OUT,            "BGP adj out" },
+  { 0, NULL },
+  { MTYPE_AS_LIST,                "BGP AS list" },
+  { MTYPE_AS_FILTER,              "BGP AS filter" },
+  { MTYPE_AS_FILTER_STR,          "BGP AS filter str" },
+  { 0, NULL },
+  { MTYPE_COMMUNITY,              "community" },
+  { MTYPE_COMMUNITY_VAL,          "community val" },
+  { MTYPE_COMMUNITY_STR,          "community str" },
+  { 0, NULL },
+  { MTYPE_ECOMMUNITY,             "extcommunity" },
+  { MTYPE_ECOMMUNITY_VAL,         "extcommunity val" },
+  { MTYPE_ECOMMUNITY_STR,         "extcommunity str" },
+  { 0, NULL },
+  { MTYPE_COMMUNITY_LIST,         "community-list" },
+  { MTYPE_COMMUNITY_LIST_NAME,    "community-list name" },
+  { MTYPE_COMMUNITY_LIST_ENTRY,   "community-list entry" },
+  { MTYPE_COMMUNITY_LIST_CONFIG,  "community-list config" },
+  { 0, NULL },
+  { MTYPE_CLUSTER,                "Cluster list" },
+  { MTYPE_CLUSTER_VAL,            "Cluster list val" },
+  { 0, NULL },
+  { MTYPE_TRANSIT,                "BGP transit attr" },
+  { MTYPE_TRANSIT_VAL,            "BGP transit val" },
+  { 0, NULL },
+  { MTYPE_BGP_DISTANCE,           "BGP distance" },
+  { MTYPE_BGP_NEXTHOP_CACHE,      "BGP nexthop" },
+  { MTYPE_BGP_CONFED_LIST,        "BGP confed list" },
+  { MTYPE_PEER_UPDATE_SOURCE,     "peer update if" },
+  { MTYPE_BGP_DAMP_INFO,          "Dampening info" },
+  { MTYPE_BGP_REGEXP,             "BGP regexp" },
+  { -1, NULL }
+};
+
+struct memory_list memory_list_rip[] =
+{
+  { MTYPE_RIP,                "RIP structure   " },
+  { MTYPE_RIP_INFO,           "RIP route info  " },
+  { MTYPE_RIP_INTERFACE,      "RIP interface   " },
+  { MTYPE_RIP_PEER,           "RIP peer        " },
+  { MTYPE_RIP_OFFSET_LIST,    "RIP offset list " },
+  { MTYPE_RIP_DISTANCE,       "RIP distance    " },
+  { -1, NULL }
+};
+
+struct memory_list memory_list_ospf[] =
+{
+  { MTYPE_OSPF_TOP,           "OSPF top        " },
+  { MTYPE_OSPF_AREA,          "OSPF area       " },
+  { MTYPE_OSPF_AREA_RANGE,    "OSPF area range " },
+  { MTYPE_OSPF_NETWORK,       "OSPF network    " },
+#ifdef NBMA_ENABLE
+  { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " },
+#endif  /* NBMA_ENABLE */
+  { MTYPE_OSPF_IF,            "OSPF interface  " },
+  { MTYPE_OSPF_NEIGHBOR,      "OSPF neighbor   " },
+  { MTYPE_OSPF_ROUTE,         "OSPF route      " },
+  { MTYPE_OSPF_TMP,           "OSPF tmp mem    " },
+  { MTYPE_OSPF_LSA,           "OSPF LSA        " },
+  { MTYPE_OSPF_LSA_DATA,      "OSPF LSA data   " },
+  { MTYPE_OSPF_LSDB,          "OSPF LSDB       " },
+  { MTYPE_OSPF_PACKET,        "OSPF packet     " },
+  { MTYPE_OSPF_FIFO,          "OSPF FIFO queue " },
+  { MTYPE_OSPF_VERTEX,        "OSPF vertex     " },
+  { MTYPE_OSPF_NEXTHOP,       "OSPF nexthop    " },
+  { MTYPE_OSPF_PATH,         "OSPF path       " },
+  { MTYPE_OSPF_VL_DATA,       "OSPF VL data    " },
+  { MTYPE_OSPF_CRYPT_KEY,     "OSPF crypt key  " },
+  { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info  " },
+  { MTYPE_OSPF_DISTANCE,      "OSPF distance   " },
+  { MTYPE_OSPF_IF_INFO,       "OSPF if info    " },
+  { MTYPE_OSPF_IF_PARAMS,     "OSPF if params  " },
+  { -1, NULL },
+};
+
+struct memory_list memory_list_ospf6[] =
+{
+  { MTYPE_OSPF6_TOP,          "OSPF6 top         " },
+  { MTYPE_OSPF6_AREA,         "OSPF6 area        " },
+  { MTYPE_OSPF6_IF,           "OSPF6 interface   " },
+  { MTYPE_OSPF6_NEIGHBOR,     "OSPF6 neighbor    " },
+  { MTYPE_OSPF6_ROUTE,        "OSPF6 route       " },
+  { MTYPE_OSPF6_PREFIX,       "OSPF6 prefix      " },
+  { MTYPE_OSPF6_MESSAGE,      "OSPF6 message     " },
+  { MTYPE_OSPF6_LSA,          "OSPF6 LSA         " },
+  { MTYPE_OSPF6_LSA_SUMMARY,  "OSPF6 LSA summary " },
+  { MTYPE_OSPF6_LSDB,         "OSPF6 LSA database" },
+  { MTYPE_OSPF6_VERTEX,       "OSPF6 vertex      " },
+  { MTYPE_OSPF6_SPFTREE,      "OSPF6 SPF tree    " },
+  { MTYPE_OSPF6_NEXTHOP,      "OSPF6 nexthop     " },
+  { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info   " },
+  { MTYPE_OSPF6_OTHER,        "OSPF6 other       " },
+  { -1, NULL },
+};
+
+struct memory_list memory_list_separator[] =
+{
+  { 0, NULL},
+  {-1, NULL}
+};
+
+void
+show_memory_vty (struct vty *vty, struct memory_list *list)
+{
+  struct memory_list *m;
+
+  for (m = list; m->index >= 0; m++)
+    if (m->index == 0)
+      vty_out (vty, "-----------------------------\r\n");
+    else
+      vty_out (vty, "%-22s: %5ld\r\n", m->format, mstat[m->index].alloc);
+}
+
+DEFUN (show_memory_all,
+       show_memory_all_cmd,
+       "show memory all",
+       "Show running system information\n"
+       "Memory statistics\n"
+       "All memory statistics\n")
+{
+  show_memory_vty (vty, memory_list_lib);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_rip);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_ospf);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_ospf6);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_memory_all,
+       show_memory_cmd,
+       "show memory",
+       "Show running system information\n"
+       "Memory statistics\n")
+
+DEFUN (show_memory_lib,
+       show_memory_lib_cmd,
+       "show memory lib",
+       SHOW_STR
+       "Memory statistics\n"
+       "Library memory\n")
+{
+  show_memory_vty (vty, memory_list_lib);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_rip,
+       show_memory_rip_cmd,
+       "show memory rip",
+       SHOW_STR
+       "Memory statistics\n"
+       "RIP memory\n")
+{
+  show_memory_vty (vty, memory_list_rip);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_bgp,
+       show_memory_bgp_cmd,
+       "show memory bgp",
+       SHOW_STR
+       "Memory statistics\n"
+       "BGP memory\n")
+{
+  show_memory_vty (vty, memory_list_bgp);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_ospf,
+       show_memory_ospf_cmd,
+       "show memory ospf",
+       SHOW_STR
+       "Memory statistics\n"
+       "OSPF memory\n")
+{
+  show_memory_vty (vty, memory_list_ospf);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_ospf6,
+       show_memory_ospf6_cmd,
+       "show memory ospf6",
+       SHOW_STR
+       "Memory statistics\n"
+       "OSPF6 memory\n")
+{
+  show_memory_vty (vty, memory_list_ospf6);
+  return CMD_SUCCESS;
+}
+
+void
+memory_init ()
+{
+  install_element (VIEW_NODE, &show_memory_cmd);
+  install_element (VIEW_NODE, &show_memory_all_cmd);
+  install_element (VIEW_NODE, &show_memory_lib_cmd);
+  install_element (VIEW_NODE, &show_memory_rip_cmd);
+  install_element (VIEW_NODE, &show_memory_bgp_cmd);
+  install_element (VIEW_NODE, &show_memory_ospf_cmd);
+  install_element (VIEW_NODE, &show_memory_ospf6_cmd);
+
+  install_element (ENABLE_NODE, &show_memory_cmd);
+  install_element (ENABLE_NODE, &show_memory_all_cmd);
+  install_element (ENABLE_NODE, &show_memory_lib_cmd);
+  install_element (ENABLE_NODE, &show_memory_rip_cmd);
+  install_element (ENABLE_NODE, &show_memory_bgp_cmd);
+  install_element (ENABLE_NODE, &show_memory_ospf_cmd);
+  install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
+}
diff --git a/lib/memory.h b/lib/memory.h
new file mode 100644 (file)
index 0000000..52e3bc1
--- /dev/null
@@ -0,0 +1,245 @@
+/* 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_BGP,
+  MTYPE_BGP_PEER,
+  MTYPE_PEER_GROUP,
+  MTYPE_PEER_DESC,
+  MTYPE_PEER_UPDATE_SOURCE,
+  MTYPE_BGP_STATIC,
+  MTYPE_BGP_AGGREGATE,
+  MTYPE_BGP_CONFED_LIST,
+  MTYPE_BGP_NEXTHOP_CACHE,
+  MTYPE_BGP_DAMP_INFO,
+  MTYPE_BGP_DAMP_ARRAY,
+  MTYPE_BGP_ANNOUNCE,
+  MTYPE_BGP_ATTR_QUEUE,
+  MTYPE_BGP_ROUTE_QUEUE,
+  MTYPE_BGP_DISTANCE,
+  MTYPE_BGP_ROUTE,
+  MTYPE_BGP_TABLE,
+  MTYPE_BGP_NODE,
+  MTYPE_BGP_ADVERTISE_ATTR,
+  MTYPE_BGP_ADVERTISE,
+  MTYPE_BGP_ADJ_IN,
+  MTYPE_BGP_ADJ_OUT,
+  MTYPE_BGP_REGEXP,
+  MTYPE_AS_FILTER,
+  MTYPE_AS_FILTER_STR,
+  MTYPE_AS_LIST,
+
+  MTYPE_COMMUNITY,
+  MTYPE_COMMUNITY_VAL,
+  MTYPE_COMMUNITY_STR,
+
+  MTYPE_ECOMMUNITY,
+  MTYPE_ECOMMUNITY_VAL,
+  MTYPE_ECOMMUNITY_STR,
+
+  /* community-list and extcommunity-list.  */
+  MTYPE_COMMUNITY_LIST_HANDLER,
+  MTYPE_COMMUNITY_LIST,
+  MTYPE_COMMUNITY_LIST_NAME,
+  MTYPE_COMMUNITY_LIST_ENTRY,
+  MTYPE_COMMUNITY_LIST_CONFIG,
+
+  MTYPE_RIP,
+  MTYPE_RIP_INTERFACE,
+  MTYPE_RIP_DISTANCE,
+  MTYPE_RIP_OFFSET_LIST,
+  MTYPE_RIP_INFO,
+  MTYPE_RIP_PEER,
+  MTYPE_KEYCHAIN,
+  MTYPE_KEY,
+
+  MTYPE_VTYSH_CONFIG,
+  MTYPE_VTYSH_CONFIG_LINE,
+
+  MTYPE_VRF,
+  MTYPE_VRF_NAME,
+
+  MTYPE_MAX
+};
+
+#ifdef MEMORY_LOG
+#define XMALLOC(mtype, size) \
+  mtype_zmalloc (__FILE__, __LINE__, (mtype), (size))
+#define XCALLOC(mtype, size) \
+  mtype_zcalloc (__FILE__, __LINE__, (mtype), (size))
+#define XREALLOC(mtype, ptr, size)  \
+  mtype_zrealloc (__FILE__, __LINE__, (mtype), (ptr), (size))
+#define XFREE(mtype, ptr) \
+  mtype_zfree (__FILE__, __LINE__, (mtype), (ptr))
+#define XSTRDUP(mtype, str) \
+  mtype_zstrdup (__FILE__, __LINE__, (mtype), (str))
+#else
+#define XMALLOC(mtype, size)       zmalloc ((mtype), (size))
+#define XCALLOC(mtype, size)       zcalloc ((mtype), (size))
+#define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size))
+#define XFREE(mtype, ptr)          zfree ((mtype), (ptr))
+#define XSTRDUP(mtype, str)        zstrdup ((mtype), (str))
+#endif /* MEMORY_LOG */
+
+/* Prototypes of memory function. */
+void *zmalloc (int type, size_t size);
+void *zcalloc (int type, size_t size);
+void *zrealloc (int type, void *ptr, size_t size);
+void  zfree (int type, void *ptr);
+char *zstrdup (int type, char *str);
+
+void *mtype_zmalloc (const char *file,
+                    int line,
+                    int type,
+                    size_t size);
+
+void *mtype_zcalloc (const char *file,
+                    int line,
+                    int type,
+                    size_t num,
+                    size_t size);
+
+void *mtype_zrealloc (const char *file,
+                    int line,
+                    int type, 
+                    void *ptr,
+                    size_t size);
+
+void mtype_zfree (const char *file,
+                 int line,
+                 int type,
+                 void *ptr);
+
+char *mtype_zstrdup (const char *file,
+                    int line,
+                    int type,
+                    char *str);
+void memory_init ();
+
+#endif /* _ZEBRA_MEMORY_H */
diff --git a/lib/network.c b/lib/network.c
new file mode 100644 (file)
index 0000000..b68761b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Network library.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* Read nbytes from fd and store into ptr. */
+int
+readn (int fd, char *ptr, int nbytes)
+{
+  int nleft;
+  int nread;
+
+  nleft = nbytes;
+
+  while (nleft > 0) 
+    {
+      nread = read (fd, ptr, nleft);
+
+      if (nread < 0) 
+       return (nread);
+      else
+       if (nread == 0) 
+         break;
+
+      nleft -= nread;
+      ptr += nread;
+    }
+
+  return nbytes - nleft;
+}  
+
+/* Write nbytes from ptr to fd. */
+int
+writen(int fd, char *ptr, int nbytes)
+{
+  int nleft;
+  int nwritten;
+
+  nleft = nbytes;
+
+  while (nleft > 0) 
+    {
+      nwritten = write(fd, ptr, nleft);
+      
+      if (nwritten <= 0) 
+       return (nwritten);
+
+      nleft -= nwritten;
+      ptr += nwritten;
+    }
+  return nbytes - nleft;
+}
diff --git a/lib/network.h b/lib/network.h
new file mode 100644 (file)
index 0000000..a021295
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Network library header.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_NETWORK_H
+#define _ZEBRA_NETWORK_H
+
+int readn (int, char *, int);
+int writen (int, char *, int);
+
+#endif /* _ZEBRA_NETWORK_H */
diff --git a/lib/pid_output.c b/lib/pid_output.c
new file mode 100644 (file)
index 0000000..4146244
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Process id output.
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+pid_t
+pid_output (char *path)
+{
+  FILE *fp;
+  pid_t pid;
+
+  pid = getpid();
+
+  fp = fopen (path, "w");
+  if (fp != NULL) 
+    {
+      fprintf (fp, "%d\n", (int) pid);
+      fclose (fp);
+      return -1;
+    }
+  return pid;
+}
+
+pid_t
+pid_output_lock (char *path)
+{
+  int tmp;
+  int fd;
+  pid_t pid;
+  char buf[16], *p;
+
+  pid = getpid ();
+
+  fd = open (path, O_RDWR | O_CREAT | O_EXCL, 0644);
+  if (fd < 0)
+    {
+      fd = open (path, O_RDONLY);
+      if (fd < 0)
+        fprintf (stderr, "Can't creat pid lock file, exit\n");
+      else
+        {
+          read (fd, buf, sizeof (buf));
+          if ((p = index (buf, '\n')) != NULL)
+            *p = 0;
+          fprintf (stderr, "Another process(%s) running, exit\n", buf);
+        }
+      exit (-1);
+    }
+  else
+    {
+      sprintf (buf, "%d\n", (int) pid);
+      tmp = write (fd, buf, strlen (buf));
+      close (fd);
+    }
+
+  return pid;
+}
+
diff --git a/lib/plist.c b/lib/plist.c
new file mode 100644 (file)
index 0000000..c2aeea5
--- /dev/null
@@ -0,0 +1,2881 @@
+/* Prefix list functions.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "plist.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+/* Each prefix-list's entry. */
+struct prefix_list_entry
+{
+  int seq;
+
+  int le;
+  int ge;
+
+  enum prefix_list_type type;
+
+  int any;
+  struct prefix prefix;
+
+  unsigned long refcnt;
+  unsigned long hitcnt;
+
+  struct prefix_list_entry *next;
+  struct prefix_list_entry *prev;
+};
+
+/* List of struct prefix_list. */
+struct prefix_list_list
+{
+  struct prefix_list *head;
+  struct prefix_list *tail;
+};
+
+/* Master structure of prefix_list. */
+struct prefix_master
+{
+  /* List of prefix_list which name is number. */
+  struct prefix_list_list num;
+
+  /* List of prefix_list which name is string. */
+  struct prefix_list_list str;
+
+  /* Whether sequential number is used. */
+  int seqnum;
+
+  /* The latest update. */
+  struct prefix_list *recent;
+
+  /* Hook function which is executed when new prefix_list is added. */
+  void (*add_hook) ();
+
+  /* Hook function which is executed when prefix_list is deleted. */
+  void (*delete_hook) ();
+};
+
+/* Static structure of IPv4 prefix_list's master. */
+static struct prefix_master prefix_master_ipv4 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  1,
+  NULL,
+  NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure of IPv6 prefix-list's master. */
+static struct prefix_master prefix_master_ipv6 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  1,
+  NULL,
+  NULL,
+};
+#endif /* HAVE_IPV6*/
+
+/* Static structure of BGP ORF prefix_list's master. */
+static struct prefix_master prefix_master_orf = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  1,
+  NULL,
+  NULL,
+};
+\f
+struct prefix_master *
+prefix_master_get (afi_t afi)
+{
+  if (afi == AFI_IP)
+    return &prefix_master_ipv4;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return &prefix_master_ipv6;
+#endif /* HAVE_IPV6 */
+  else if (afi == AFI_ORF_PREFIX)
+    return &prefix_master_orf;
+  return NULL;
+}
+
+/* Lookup prefix_list from list of prefix_list by name. */
+struct prefix_list *
+prefix_list_lookup (afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+  struct prefix_master *master;
+
+  if (name == NULL)
+    return NULL;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  for (plist = master->num.head; plist; plist = plist->next)
+    if (strcmp (plist->name, name) == 0)
+      return plist;
+
+  for (plist = master->str.head; plist; plist = plist->next)
+    if (strcmp (plist->name, name) == 0)
+      return plist;
+
+  return NULL;
+}
+
+struct prefix_list *
+prefix_list_new ()
+{
+  struct prefix_list *new;
+
+  new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list));
+  return new;
+}
+
+void
+prefix_list_free (struct prefix_list *plist)
+{
+  XFREE (MTYPE_PREFIX_LIST, plist);
+}
+
+struct prefix_list_entry *
+prefix_list_entry_new ()
+{
+  struct prefix_list_entry *new;
+
+  new = XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry));
+  return new;
+}
+
+void
+prefix_list_entry_free (struct prefix_list_entry *pentry)
+{
+  XFREE (MTYPE_PREFIX_LIST_ENTRY, pentry);
+}
+
+/* Insert new prefix list to list of prefix_list.  Each prefix_list
+   is sorted by the name. */
+struct prefix_list *
+prefix_list_insert (afi_t afi, char *name)
+{
+  int i;
+  long number;
+  struct prefix_list *plist;
+  struct prefix_list *point;
+  struct prefix_list_list *list;
+  struct prefix_master *master;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  /* Allocate new prefix_list and copy given name. */
+  plist = prefix_list_new ();
+  plist->name = XSTRDUP (MTYPE_PREFIX_LIST_STR, name);
+  plist->master = master;
+
+  /* If name is made by all digit character.  We treat it as
+     number. */
+  for (number = 0, i = 0; i < strlen (name); i++)
+    {
+      if (isdigit ((int) name[i]))
+       number = (number * 10) + (name[i] - '0');
+      else
+       break;
+    }
+
+  /* In case of name is all digit character */
+  if (i == strlen (name))
+    {
+      plist->type = PREFIX_TYPE_NUMBER;
+
+      /* Set prefix_list to number list. */
+      list = &master->num;
+
+      for (point = list->head; point; point = point->next)
+       if (atol (point->name) >= number)
+         break;
+    }
+  else
+    {
+      plist->type = PREFIX_TYPE_STRING;
+
+      /* Set prefix_list to string list. */
+      list = &master->str;
+  
+      /* Set point to insertion point. */
+      for (point = list->head; point; point = point->next)
+       if (strcmp (point->name, name) >= 0)
+         break;
+    }
+
+  /* In case of this is the first element of master. */
+  if (list->head == NULL)
+    {
+      list->head = list->tail = plist;
+      return plist;
+    }
+
+  /* In case of insertion is made at the tail of access_list. */
+  if (point == NULL)
+    {
+      plist->prev = list->tail;
+      list->tail->next = plist;
+      list->tail = plist;
+      return plist;
+    }
+
+  /* In case of insertion is made at the head of access_list. */
+  if (point == list->head)
+    {
+      plist->next = list->head;
+      list->head->prev = plist;
+      list->head = plist;
+      return plist;
+    }
+
+  /* Insertion is made at middle of the access_list. */
+  plist->next = point;
+  plist->prev = point->prev;
+
+  if (point->prev)
+    point->prev->next = plist;
+  point->prev = plist;
+
+  return plist;
+}
+
+struct prefix_list *
+prefix_list_get (afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (afi, name);
+
+  if (plist == NULL)
+    plist = prefix_list_insert (afi, name);
+  return plist;
+}
+
+/* Delete prefix-list from prefix_list_master and free it. */
+void
+prefix_list_delete (struct prefix_list *plist)
+{
+  struct prefix_list_list *list;
+  struct prefix_master *master;
+  struct prefix_list_entry *pentry;
+  struct prefix_list_entry *next;
+
+  /* If prefix-list contain prefix_list_entry free all of it. */
+  for (pentry = plist->head; pentry; pentry = next)
+    {
+      next = pentry->next;
+      prefix_list_entry_free (pentry);
+      plist->count--;
+    }
+
+  master = plist->master;
+
+  if (plist->type == PREFIX_TYPE_NUMBER)
+    list = &master->num;
+  else
+    list = &master->str;
+
+  if (plist->next)
+    plist->next->prev = plist->prev;
+  else
+    list->tail = plist->prev;
+
+  if (plist->prev)
+    plist->prev->next = plist->next;
+  else
+    list->head = plist->next;
+
+  if (plist->desc)
+    XFREE (MTYPE_TMP, plist->desc);
+
+  /* Make sure master's recent changed prefix-list information is
+     cleared. */
+  master->recent = NULL;
+
+  if (plist->name)
+    XFREE (MTYPE_PREFIX_LIST_STR, plist->name);
+
+  prefix_list_free (plist);
+
+  if (master->delete_hook)
+    (*master->delete_hook) ();
+}
+
+struct prefix_list_entry *
+prefix_list_entry_make (struct prefix *prefix, enum prefix_list_type type,
+                       int seq, int le, int ge, int any)
+{
+  struct prefix_list_entry *pentry;
+
+  pentry = prefix_list_entry_new ();
+
+  if (any)
+    pentry->any = 1;
+
+  prefix_copy (&pentry->prefix, prefix);
+  pentry->type = type;
+  pentry->seq = seq;
+  pentry->le = le;
+  pentry->ge = ge;
+
+  return pentry;
+}
+
+/* Add hook function. */
+void
+prefix_list_add_hook (void (*func) (struct prefix_list *plist))
+{
+  prefix_master_ipv4.add_hook = func;
+#ifdef HAVE_IPV6
+  prefix_master_ipv6.add_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Delete hook function. */
+void
+prefix_list_delete_hook (void (*func) (struct prefix_list *plist))
+{
+  prefix_master_ipv4.delete_hook = func;
+#ifdef HAVE_IPV6
+  prefix_master_ipv6.delete_hook = func;
+#endif /* HAVE_IPVt6 */
+}
+
+/* Calculate new sequential number. */
+int
+prefix_new_seq_get (struct prefix_list *plist)
+{
+  int maxseq;
+  int newseq;
+  struct prefix_list_entry *pentry;
+
+  maxseq = newseq = 0;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      if (maxseq < pentry->seq)
+       maxseq = pentry->seq;
+    }
+
+  newseq = ((maxseq / 5) * 5) + 5;
+  
+  return newseq;
+}
+
+/* Return prefix list entry which has same seq number. */
+struct prefix_list_entry *
+prefix_seq_check (struct prefix_list *plist, int seq)
+{
+  struct prefix_list_entry *pentry;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    if (pentry->seq == seq)
+      return pentry;
+  return NULL;
+}
+
+struct prefix_list_entry *
+prefix_list_entry_lookup (struct prefix_list *plist, struct prefix *prefix,
+                         enum prefix_list_type type, int seq, int le, int ge)
+{
+  struct prefix_list_entry *pentry;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    if (prefix_same (&pentry->prefix, prefix) && pentry->type == type)
+      {
+       if (seq >= 0 && pentry->seq != seq)
+         continue;
+
+       if (pentry->le != le)
+         continue;
+       if (pentry->ge != ge)
+         continue;
+
+       return pentry;
+      }
+
+  return NULL;
+}
+
+void
+prefix_list_entry_delete (struct prefix_list *plist, 
+                         struct prefix_list_entry *pentry,
+                         int update_list)
+{
+  if (plist == NULL || pentry == NULL)
+    return;
+  if (pentry->prev)
+    pentry->prev->next = pentry->next;
+  else
+    plist->head = pentry->next;
+  if (pentry->next)
+    pentry->next->prev = pentry->prev;
+  else
+    plist->tail = pentry->prev;
+
+  prefix_list_entry_free (pentry);
+
+  plist->count--;
+
+  if (update_list)
+    {
+      if (plist->master->delete_hook)
+       (*plist->master->delete_hook) (plist);
+
+      if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
+       prefix_list_delete (plist);
+      else
+       plist->master->recent = plist;
+    }
+}
+
+void
+prefix_list_entry_add (struct prefix_list *plist,
+                      struct prefix_list_entry *pentry)
+{
+  struct prefix_list_entry *replace;
+  struct prefix_list_entry *point;
+
+  /* Automatic asignment of seq no. */
+  if (pentry->seq == -1)
+    pentry->seq = prefix_new_seq_get (plist);
+
+  /* Is there any same seq prefix list entry? */
+  replace = prefix_seq_check (plist, pentry->seq);
+  if (replace)
+    prefix_list_entry_delete (plist, replace, 0);
+
+  /* Check insert point. */
+  for (point = plist->head; point; point = point->next)
+    if (point->seq >= pentry->seq)
+      break;
+
+  /* In case of this is the first element of the list. */
+  pentry->next = point;
+
+  if (point)
+    {
+      if (point->prev)
+       point->prev->next = pentry;
+      else
+       plist->head = pentry;
+
+      pentry->prev = point->prev;
+      point->prev = pentry;
+    }
+  else
+    {
+      if (plist->tail)
+       plist->tail->next = pentry;
+      else
+       plist->head = pentry;
+
+      pentry->prev = plist->tail;
+      plist->tail = pentry;
+    }
+
+  /* Increment count. */
+  plist->count++;
+
+  /* Run hook function. */
+  if (plist->master->add_hook)
+    (*plist->master->add_hook) (plist);
+
+  plist->master->recent = plist;
+}
+
+/* Return string of prefix_list_type. */
+static char *
+prefix_list_type_str (struct prefix_list_entry *pentry)
+{
+  switch (pentry->type)
+    {
+    case PREFIX_PERMIT:
+      return "permit";
+      break;
+    case PREFIX_DENY:
+      return "deny";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+int
+prefix_list_entry_match (struct prefix_list_entry *pentry, struct prefix *p)
+{
+  int ret;
+
+  ret = prefix_match (&pentry->prefix, p);
+  if (! ret)
+    return 0;
+  
+  /* In case of le nor ge is specified, exact match is performed. */
+  if (! pentry->le && ! pentry->ge)
+    {
+      if (pentry->prefix.prefixlen != p->prefixlen)
+       return 0;
+    }
+  else
+    {  
+      if (pentry->le)
+       if (p->prefixlen > pentry->le)
+         return 0;
+
+      if (pentry->ge)
+       if (p->prefixlen < pentry->ge)
+         return 0;
+    }
+  return 1;
+}
+
+enum prefix_list_type
+prefix_list_apply (struct prefix_list *plist, void *object)
+{
+  struct prefix_list_entry *pentry;
+  struct prefix *p;
+
+  p = (struct prefix *) object;
+
+  if (plist == NULL)
+    return PREFIX_DENY;
+
+  if (plist->count == 0)
+    return PREFIX_PERMIT;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      pentry->refcnt++;
+      if (prefix_list_entry_match (pentry, p))
+       {
+         pentry->hitcnt++;
+         return pentry->type;
+       }
+    }
+
+  return PREFIX_DENY;
+}
+
+void
+prefix_list_print (struct prefix_list *plist)
+{
+  struct prefix_list_entry *pentry;
+
+  if (plist == NULL)
+    return;
+
+  printf ("ip prefix-list %s: %d entries\n", plist->name, plist->count);
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      if (pentry->any)
+       printf ("any %s\n", prefix_list_type_str (pentry));
+      else
+       {
+         struct prefix *p;
+         char buf[BUFSIZ];
+         
+         p = &pentry->prefix;
+         
+         printf ("  seq %d %s %s/%d", 
+                 pentry->seq,
+                 prefix_list_type_str (pentry),
+                 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                 p->prefixlen);
+         if (pentry->ge)
+           printf (" ge %d", pentry->ge);
+         if (pentry->le)
+           printf (" le %d", pentry->le);
+         printf ("\n");
+       }
+    }
+}
+\f
+/* Retrun 1 when plist already include pentry policy. */
+struct prefix_list_entry *
+prefix_entry_dup_check (struct prefix_list *plist,
+                       struct prefix_list_entry *new)
+{
+  struct prefix_list_entry *pentry;
+  int seq = 0;
+
+  if (new->seq == -1)
+    seq = prefix_new_seq_get (plist);
+  else
+    seq = new->seq;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      if (prefix_same (&pentry->prefix, &new->prefix)
+         && pentry->type == new->type
+         && pentry->le == new->le
+         && pentry->ge == new->ge
+         && pentry->seq != seq)
+       return pentry;
+    }
+  return NULL;
+}
+
+int
+vty_invalid_prefix_range (struct vty *vty, char *prefix)
+{
+  vty_out (vty, "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value%s",
+           prefix, VTY_NEWLINE);
+  return CMD_WARNING;
+}
+
+int
+vty_prefix_list_install (struct vty *vty, afi_t afi,
+                        char *name, char *seq, char *typestr,
+                        char *prefix, char *ge, char *le)
+{
+  int ret;
+  enum prefix_list_type type;
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix_list_entry *dup;
+  struct prefix p;
+  int any = 0;
+  int seqnum = -1;
+  int lenum = 0;
+  int genum = 0;
+
+  /* Sequential number. */
+  if (seq)
+    seqnum = atoi (seq);
+
+  /* ge and le number */
+  if (ge)
+    genum = atoi (ge);
+  if (le)
+    lenum = atoi (le);
+
+  /* Check filter type. */
+  if (strncmp ("permit", typestr, 1) == 0)
+    type = PREFIX_PERMIT;
+  else if (strncmp ("deny", typestr, 1) == 0)
+    type = PREFIX_DENY;
+  else
+    {
+      vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* "any" is special token for matching any IPv4 addresses.  */
+  if (afi == AFI_IP)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+       {
+         ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p);
+         genum = 0;
+         lenum = IPV4_MAX_BITLEN;
+         any = 1;
+       }
+      else
+       ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p);
+
+      if (ret <= 0)
+       {
+         vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+       {
+         ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p);
+         genum = 0;
+         lenum = IPV6_MAX_BITLEN;
+         any = 1;
+       }
+      else
+       ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p);
+
+      if (ret <= 0)
+       {
+         vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+#endif /* HAVE_IPV6 */
+
+  /* ge and le check. */
+  if (genum && genum <= p.prefixlen)
+    return vty_invalid_prefix_range (vty, prefix);
+
+  if (lenum && lenum <= p.prefixlen)
+    return vty_invalid_prefix_range (vty, prefix);
+
+  if (lenum && genum > lenum)
+    return vty_invalid_prefix_range (vty, prefix);
+
+  if (genum && lenum == (afi == AFI_IP ? 32 : 128))
+    lenum = 0;
+
+  /* Get prefix_list with name. */
+  plist = prefix_list_get (afi, name);
+
+  /* Make prefix entry. */
+  pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any);
+    
+  /* Check same policy. */
+  dup = prefix_entry_dup_check (plist, pentry);
+
+  if (dup)
+    {
+      prefix_list_entry_free (pentry);
+      vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s",
+              VTY_NEWLINE);
+      vty_out (vty, "   seq %d %s %s", dup->seq, typestr, prefix);
+      if (! any && genum)
+       vty_out (vty, " ge %d", genum);
+      if (! any && lenum)
+       vty_out (vty, " le %d", lenum);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Install new filter to the access_list. */
+  prefix_list_entry_add (plist, pentry);
+
+  return CMD_SUCCESS;
+}
+
+int
+vty_prefix_list_uninstall (struct vty *vty, afi_t afi,
+                          char *name, char *seq, char *typestr,
+                          char *prefix, char *ge, char *le)
+{
+  int ret;
+  enum prefix_list_type type;
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix p;
+  int seqnum = -1;
+  int lenum = 0;
+  int genum = 0;
+
+  /* Check prefix list name. */
+  plist = prefix_list_lookup (afi, name);
+  if (! plist)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Only prefix-list name specified, delete the entire prefix-list. */
+  if (seq == NULL && typestr == NULL && prefix == NULL && 
+      ge == NULL && le == NULL)
+    {
+      prefix_list_delete (plist);
+      return CMD_SUCCESS;
+    }
+
+  /* Check sequence number. */
+  if (seq)
+    seqnum = atoi (seq);
+
+  /* ge and le number */
+  if (ge)
+    genum = atoi (ge);
+  if (le)
+    lenum = atoi (le);
+
+  /* Check of filter type. */
+  if (strncmp ("permit", typestr, 1) == 0)
+    type = PREFIX_PERMIT;
+  else if (strncmp ("deny", typestr, 1) == 0)
+    type = PREFIX_DENY;
+  else
+    {
+      vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* "any" is special token for matching any IPv4 addresses.  */
+  if (afi == AFI_IP)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+       {
+         ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p);
+         genum = 0;
+         lenum = IPV4_MAX_BITLEN;
+       }
+      else
+       ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p);
+
+      if (ret <= 0)
+       {
+         vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+       {
+         ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p);
+         genum = 0;
+         lenum = IPV6_MAX_BITLEN;
+       }
+      else
+       ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p);
+
+      if (ret <= 0)
+       {
+         vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+    }
+#endif /* HAVE_IPV6 */
+
+  /* Lookup prefix entry. */
+  pentry = prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum);
+
+  if (pentry == NULL)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Install new filter to the access_list. */
+  prefix_list_entry_delete (plist, pentry, 1);
+
+  return CMD_SUCCESS;
+}
+
+int
+vty_prefix_list_desc_unset (struct vty *vty, afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (afi, name);
+  if (! plist)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (plist->desc)
+    {
+      XFREE (MTYPE_TMP, plist->desc);
+      plist->desc = NULL;
+    }
+
+  if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
+    prefix_list_delete (plist);
+
+  return CMD_SUCCESS;
+}
+
+enum display_type
+{
+  normal_display,
+  summary_display,
+  detail_display,
+  sequential_display,
+  longer_display,
+  first_match_display
+};
+
+void
+vty_show_prefix_entry (struct vty *vty, afi_t afi, struct prefix_list *plist,
+                      struct prefix_master *master, enum display_type dtype,
+                      int seqnum)
+{
+  struct prefix_list_entry *pentry;
+
+  if (dtype == normal_display)
+    {
+      vty_out (vty, "ip%s prefix-list %s: %d entries%s",
+              afi == AFI_IP ? "" : "v6",
+              plist->name, plist->count, VTY_NEWLINE);
+      if (plist->desc)
+       vty_out (vty, "   Description: %s%s", plist->desc, VTY_NEWLINE);
+    }
+  else if (dtype == summary_display || dtype == detail_display)
+    {
+      vty_out (vty, "ip%s prefix-list %s:%s",
+              afi == AFI_IP ? "" : "v6", plist->name, VTY_NEWLINE);
+
+      if (plist->desc)
+       vty_out (vty, "   Description: %s%s", plist->desc, VTY_NEWLINE);
+
+      vty_out (vty, "   count: %d, range entries: %d, sequences: %d - %d%s",
+              plist->count, plist->rangecount, 
+              plist->head ? plist->head->seq : 0, 
+              plist->tail ? plist->tail->seq : 0,
+              VTY_NEWLINE);
+    }
+
+  if (dtype != summary_display)
+    {
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+       {
+         if (dtype == sequential_display && pentry->seq != seqnum)
+           continue;
+           
+         vty_out (vty, "   ");
+
+         if (master->seqnum)
+           vty_out (vty, "seq %d ", pentry->seq);
+
+         vty_out (vty, "%s ", prefix_list_type_str (pentry));
+
+         if (pentry->any)
+           vty_out (vty, "any");
+         else
+           {
+             struct prefix *p = &pentry->prefix;
+             char buf[BUFSIZ];
+
+             vty_out (vty, "%s/%d",
+                      inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                      p->prefixlen);
+
+             if (pentry->ge)
+               vty_out (vty, " ge %d", pentry->ge);
+             if (pentry->le)
+               vty_out (vty, " le %d", pentry->le);
+           }
+
+         if (dtype == detail_display || dtype == sequential_display)
+           vty_out (vty, " (hit count: %ld, refcount: %ld)", 
+                    pentry->hitcnt, pentry->refcnt);
+         
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+    }
+}
+
+int
+vty_show_prefix_list (struct vty *vty, afi_t afi, char *name,
+                     char *seq, enum display_type dtype)
+{
+  struct prefix_list *plist;
+  struct prefix_master *master;
+  int seqnum = 0;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return CMD_WARNING;
+
+  if (seq)
+    seqnum = atoi (seq);
+
+  if (name)
+    {
+      plist = prefix_list_lookup (afi, name);
+      if (! plist)
+       {
+         vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+    }
+  else
+    {
+      if (dtype == detail_display || dtype == summary_display)
+       {
+         if (master->recent)
+           vty_out (vty, "Prefix-list with the last deletion/insertion: %s%s",
+                    master->recent->name, VTY_NEWLINE);
+       }
+
+      for (plist = master->num.head; plist; plist = plist->next)
+       vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+
+      for (plist = master->str.head; plist; plist = plist->next)
+       vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, char *name, 
+                            char *prefix, enum display_type type)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix p;
+  int ret;
+  int match;
+
+  plist = prefix_list_lookup (afi, name);
+  if (! plist)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2prefix (prefix, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      match = 0;
+
+      if (type == normal_display || type == first_match_display)
+       if (prefix_same (&p, &pentry->prefix))
+         match = 1;
+
+      if (type == longer_display)
+       if (prefix_match (&p, &pentry->prefix))
+         match = 1;
+
+      if (match)
+       {
+         vty_out (vty, "   seq %d %s ", 
+                  pentry->seq,
+                  prefix_list_type_str (pentry));
+
+         if (pentry->any)
+           vty_out (vty, "any");
+         else
+           {
+             struct prefix *p = &pentry->prefix;
+             char buf[BUFSIZ];
+             
+             vty_out (vty, "%s/%d",
+                      inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                      p->prefixlen);
+
+             if (pentry->ge)
+               vty_out (vty, " ge %d", pentry->ge);
+             if (pentry->le)
+               vty_out (vty, " le %d", pentry->le);
+           }
+         
+         if (type == normal_display || type == first_match_display)
+           vty_out (vty, " (hit count: %ld, refcount: %ld)", 
+                    pentry->hitcnt, pentry->refcnt);
+
+         vty_out (vty, "%s", VTY_NEWLINE);
+
+         if (type == first_match_display)
+           return CMD_SUCCESS;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+int
+vty_clear_prefix_list (struct vty *vty, afi_t afi, char *name, char *prefix)
+{
+  struct prefix_master *master;
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  int ret;
+  struct prefix p;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return CMD_WARNING;
+
+  if (name == NULL && prefix == NULL)
+    {
+      for (plist = master->num.head; plist; plist = plist->next)
+       for (pentry = plist->head; pentry; pentry = pentry->next)
+         pentry->hitcnt = 0;
+
+      for (plist = master->str.head; plist; plist = plist->next)
+       for (pentry = plist->head; pentry; pentry = pentry->next)
+         pentry->hitcnt = 0;
+    }
+  else
+    {
+      plist = prefix_list_lookup (afi, name);
+      if (! plist)
+       {
+         vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      if (prefix)
+       {
+         ret = str2prefix (prefix, &p);
+         if (ret <= 0)
+           {
+             vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE);
+             return CMD_WARNING;
+           }
+       }
+
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+       {
+         if (prefix)
+           {
+             if (prefix_match (&pentry->prefix, &p))
+               pentry->hitcnt = 0;
+           }
+         else
+           pentry->hitcnt = 0;
+       }
+    }
+  return CMD_SUCCESS;
+}
+\f
+DEFUN (ip_prefix_list,
+       ip_prefix_list_cmd,
+       "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, 
+                                 argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ip_prefix_list_ge,
+       ip_prefix_list_ge_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], 
+                                argv[2], argv[3], NULL);
+}
+
+DEFUN (ip_prefix_list_ge_le,
+       ip_prefix_list_ge_le_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], 
+                                 argv[2], argv[3], argv[4]);
+}
+
+DEFUN (ip_prefix_list_le,
+       ip_prefix_list_le_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+                                 argv[2], NULL, argv[3]);
+}
+
+DEFUN (ip_prefix_list_le_ge,
+       ip_prefix_list_le_ge_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+                                 argv[2], argv[4], argv[3]);
+}
+
+DEFUN (ip_prefix_list_seq,
+       ip_prefix_list_seq_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                 argv[3], NULL, NULL);
+}
+
+DEFUN (ip_prefix_list_seq_ge,
+       ip_prefix_list_seq_ge_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                 argv[3], argv[4], NULL);
+}
+
+DEFUN (ip_prefix_list_seq_ge_le,
+       ip_prefix_list_seq_ge_le_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                 argv[3], argv[4], argv[5]);
+}
+
+DEFUN (ip_prefix_list_seq_le,
+       ip_prefix_list_seq_le_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                 argv[3], NULL, argv[4]);
+}
+
+DEFUN (ip_prefix_list_seq_le_ge,
+       ip_prefix_list_seq_le_ge_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                 argv[3], argv[5], argv[4]);
+}
+
+DEFUN (no_ip_prefix_list,
+       no_ip_prefix_list_cmd,
+       "no ip prefix-list WORD",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, NULL,
+                                   NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_prefix,
+       no_ip_prefix_list_prefix_cmd,
+       "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+                                   argv[2], NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_ge,
+       no_ip_prefix_list_ge_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+                                   argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ip_prefix_list_ge_le,
+       no_ip_prefix_list_ge_le_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+                                   argv[2], argv[3], argv[4]);
+}
+
+DEFUN (no_ip_prefix_list_le,
+       no_ip_prefix_list_le_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+                                   argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ip_prefix_list_le_ge,
+       no_ip_prefix_list_le_ge_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+                                   argv[2], argv[4], argv[3]);
+}
+
+DEFUN (no_ip_prefix_list_seq,
+       no_ip_prefix_list_seq_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                   argv[3], NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_seq_ge,
+       no_ip_prefix_list_seq_ge_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                   argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ip_prefix_list_seq_ge_le,
+       no_ip_prefix_list_seq_ge_le_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                   argv[3], argv[4], argv[5]);
+}
+
+DEFUN (no_ip_prefix_list_seq_le,
+       no_ip_prefix_list_seq_le_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                   argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ip_prefix_list_seq_le_ge,
+       no_ip_prefix_list_seq_le_ge_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+                                   argv[3], argv[5], argv[4]);
+}
+
+DEFUN (ip_prefix_list_sequence_number,
+       ip_prefix_list_sequence_number_cmd,
+       "ip prefix-list sequence-number",
+       IP_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv4.seqnum = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_prefix_list_sequence_number,
+       no_ip_prefix_list_sequence_number_cmd,
+       "no ip prefix-list sequence-number",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv4.seqnum = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_prefix_list_description,
+       ip_prefix_list_description_cmd,
+       "ip prefix-list WORD description .LINE",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+{
+  struct prefix_list *plist;
+  struct buffer *b;
+  int i;
+
+  plist = prefix_list_get (AFI_IP, argv[0]);
+  
+  if (plist->desc)
+    {
+      XFREE (MTYPE_TMP, plist->desc);
+      plist->desc = NULL;
+    }
+
+  /* Below is description get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  plist->desc = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_ip_prefix_list_description,
+       no_ip_prefix_list_description_cmd,
+       "no ip prefix-list WORD description",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n")
+{
+  return vty_prefix_list_desc_unset (vty, AFI_IP, argv[0]);
+}
+
+ALIAS (no_ip_prefix_list_description,
+       no_ip_prefix_list_description_arg_cmd,
+       "no ip prefix-list WORD description .LINE",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFUN (show_ip_prefix_list,
+       show_ip_prefix_list_cmd,
+       "show ip prefix-list",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR)
+{
+  return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, normal_display);
+}
+
+DEFUN (show_ip_prefix_list_name,
+       show_ip_prefix_list_name_cmd,
+       "show ip prefix-list WORD",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, normal_display);
+}
+
+DEFUN (show_ip_prefix_list_name_seq,
+       show_ip_prefix_list_name_seq_cmd,
+       "show ip prefix-list WORD seq <1-4294967295>",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], argv[1], sequential_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix,
+       show_ip_prefix_list_prefix_cmd,
+       "show ip prefix-list WORD A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], normal_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix_longer,
+       show_ip_prefix_list_prefix_longer_cmd,
+       "show ip prefix-list WORD A.B.C.D/M longer",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Lookup longer prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], longer_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix_first_match,
+       show_ip_prefix_list_prefix_first_match_cmd,
+       "show ip prefix-list WORD A.B.C.D/M first-match",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "First matched prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], first_match_display);
+}
+
+DEFUN (show_ip_prefix_list_summary,
+       show_ip_prefix_list_summary_cmd,
+       "show ip prefix-list summary",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, summary_display);
+}
+
+DEFUN (show_ip_prefix_list_summary_name,
+       show_ip_prefix_list_summary_name_cmd,
+       "show ip prefix-list summary WORD",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, summary_display);
+}
+
+
+DEFUN (show_ip_prefix_list_detail,
+       show_ip_prefix_list_detail_cmd,
+       "show ip prefix-list detail",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, detail_display);
+}
+
+DEFUN (show_ip_prefix_list_detail_name,
+       show_ip_prefix_list_detail_name_cmd,
+       "show ip prefix-list detail WORD",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, detail_display);
+}
+
+DEFUN (clear_ip_prefix_list,
+       clear_ip_prefix_list_cmd,
+       "clear ip prefix-list",
+       CLEAR_STR
+       IP_STR
+       PREFIX_LIST_STR)
+{
+  return vty_clear_prefix_list (vty, AFI_IP, NULL, NULL);
+}
+
+DEFUN (clear_ip_prefix_list_name,
+       clear_ip_prefix_list_name_cmd,
+       "clear ip prefix-list WORD",
+       CLEAR_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP, argv[0], NULL);
+}
+
+DEFUN (clear_ip_prefix_list_name_prefix,
+       clear_ip_prefix_list_name_prefix_cmd,
+       "clear ip prefix-list WORD A.B.C.D/M",
+       CLEAR_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]);
+}
+\f
+#ifdef HAVE_IPV6
+DEFUN (ipv6_prefix_list,
+       ipv6_prefix_list_cmd,
+       "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, 
+                                 argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ipv6_prefix_list_ge,
+       ipv6_prefix_list_ge_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], 
+                                argv[2], argv[3], NULL);
+}
+
+DEFUN (ipv6_prefix_list_ge_le,
+       ipv6_prefix_list_ge_le_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], 
+                                 argv[2], argv[3], argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_le,
+       ipv6_prefix_list_le_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                 argv[2], NULL, argv[3]);
+}
+
+DEFUN (ipv6_prefix_list_le_ge,
+       ipv6_prefix_list_le_ge_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                 argv[2], argv[4], argv[3]);
+}
+
+DEFUN (ipv6_prefix_list_seq,
+       ipv6_prefix_list_seq_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                 argv[3], NULL, NULL);
+}
+
+DEFUN (ipv6_prefix_list_seq_ge,
+       ipv6_prefix_list_seq_ge_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                 argv[3], argv[4], NULL);
+}
+
+DEFUN (ipv6_prefix_list_seq_ge_le,
+       ipv6_prefix_list_seq_ge_le_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                 argv[3], argv[4], argv[5]);
+}
+
+DEFUN (ipv6_prefix_list_seq_le,
+       ipv6_prefix_list_seq_le_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                 argv[3], NULL, argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_seq_le_ge,
+       ipv6_prefix_list_seq_le_ge_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                 argv[3], argv[5], argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list,
+       no_ipv6_prefix_list_cmd,
+       "no ipv6 prefix-list WORD",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, NULL,
+                                   NULL, NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_prefix,
+       no_ipv6_prefix_list_prefix_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                   argv[2], NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_ge,
+       no_ipv6_prefix_list_ge_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                   argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_ge_le,
+       no_ipv6_prefix_list_ge_le_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                   argv[2], argv[3], argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list_le,
+       no_ipv6_prefix_list_le_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                   argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ipv6_prefix_list_le_ge,
+       no_ipv6_prefix_list_le_ge_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+                                   argv[2], argv[4], argv[3]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq,
+       no_ipv6_prefix_list_seq_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                   argv[3], NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_ge,
+       no_ipv6_prefix_list_seq_ge_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                   argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_ge_le,
+       no_ipv6_prefix_list_seq_ge_le_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                   argv[3], argv[4], argv[5]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_le,
+       no_ipv6_prefix_list_seq_le_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                   argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_le_ge,
+       no_ipv6_prefix_list_seq_le_ge_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+                                   argv[3], argv[5], argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_sequence_number,
+       ipv6_prefix_list_sequence_number_cmd,
+       "ipv6 prefix-list sequence-number",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv6.seqnum = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_prefix_list_sequence_number,
+       no_ipv6_prefix_list_sequence_number_cmd,
+       "no ipv6 prefix-list sequence-number",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv6.seqnum = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_prefix_list_description,
+       ipv6_prefix_list_description_cmd,
+       "ipv6 prefix-list WORD description .LINE",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+{
+  struct prefix_list *plist;
+  struct buffer *b;
+  int i;
+
+  plist = prefix_list_get (AFI_IP6, argv[0]);
+  
+  if (plist->desc)
+    {
+      XFREE (MTYPE_TMP, plist->desc);
+      plist->desc = NULL;
+    }
+
+  /* Below is description get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  plist->desc = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_ipv6_prefix_list_description,
+       no_ipv6_prefix_list_description_cmd,
+       "no ipv6 prefix-list WORD description",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n")
+{
+  return vty_prefix_list_desc_unset (vty, AFI_IP6, argv[0]);
+}
+
+ALIAS (no_ipv6_prefix_list_description,
+       no_ipv6_prefix_list_description_arg_cmd,
+       "no ipv6 prefix-list WORD description .LINE",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFUN (show_ipv6_prefix_list,
+       show_ipv6_prefix_list_cmd,
+       "show ipv6 prefix-list",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR)
+{
+  return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_name,
+       show_ipv6_prefix_list_name_cmd,
+       "show ipv6 prefix-list WORD",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_name_seq,
+       show_ipv6_prefix_list_name_seq_cmd,
+       "show ipv6 prefix-list WORD seq <1-4294967295>",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], argv[1], sequential_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix,
+       show_ipv6_prefix_list_prefix_cmd,
+       "show ipv6 prefix-list WORD X:X::X:X/M",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix_longer,
+       show_ipv6_prefix_list_prefix_longer_cmd,
+       "show ipv6 prefix-list WORD X:X::X:X/M longer",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Lookup longer prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], longer_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix_first_match,
+       show_ipv6_prefix_list_prefix_first_match_cmd,
+       "show ipv6 prefix-list WORD X:X::X:X/M first-match",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "First matched prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], first_match_display);
+}
+
+DEFUN (show_ipv6_prefix_list_summary,
+       show_ipv6_prefix_list_summary_cmd,
+       "show ipv6 prefix-list summary",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, summary_display);
+}
+
+DEFUN (show_ipv6_prefix_list_summary_name,
+       show_ipv6_prefix_list_summary_name_cmd,
+       "show ipv6 prefix-list summary WORD",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, summary_display);
+}
+
+DEFUN (show_ipv6_prefix_list_detail,
+       show_ipv6_prefix_list_detail_cmd,
+       "show ipv6 prefix-list detail",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, detail_display);
+}
+
+DEFUN (show_ipv6_prefix_list_detail_name,
+       show_ipv6_prefix_list_detail_name_cmd,
+       "show ipv6 prefix-list detail WORD",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, detail_display);
+}
+
+DEFUN (clear_ipv6_prefix_list,
+       clear_ipv6_prefix_list_cmd,
+       "clear ipv6 prefix-list",
+       CLEAR_STR
+       IPV6_STR
+       PREFIX_LIST_STR)
+{
+  return vty_clear_prefix_list (vty, AFI_IP6, NULL, NULL);
+}
+
+DEFUN (clear_ipv6_prefix_list_name,
+       clear_ipv6_prefix_list_name_cmd,
+       "clear ipv6 prefix-list WORD",
+       CLEAR_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP6, argv[0], NULL);
+}
+
+DEFUN (clear_ipv6_prefix_list_name_prefix,
+       clear_ipv6_prefix_list_name_prefix_cmd,
+       "clear ipv6 prefix-list WORD X:X::X:X/M",
+       CLEAR_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]);
+}
+#endif /* HAVE_IPV6 */
+\f
+/* Configuration write function. */
+int
+config_write_prefix_afi (afi_t afi, struct vty *vty)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix_master *master;
+  int write = 0;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return 0;
+
+  if (! master->seqnum)
+    {
+      vty_out (vty, "no ip%s prefix-list sequence-number%s", 
+              afi == AFI_IP ? "" : "v6", VTY_NEWLINE);
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+
+  for (plist = master->num.head; plist; plist = plist->next)
+    {
+      if (plist->desc)
+       {
+         vty_out (vty, "ip%s prefix-list %s description %s%s",
+                  afi == AFI_IP ? "" : "v6",
+                  plist->name, plist->desc, VTY_NEWLINE);
+         write++;
+       }
+
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+       {
+         vty_out (vty, "ip%s prefix-list %s ",
+                  afi == AFI_IP ? "" : "v6",
+                  plist->name);
+
+         if (master->seqnum)
+           vty_out (vty, "seq %d ", pentry->seq);
+       
+         vty_out (vty, "%s ", prefix_list_type_str (pentry));
+
+         if (pentry->any)
+           vty_out (vty, "any");
+         else
+           {
+             struct prefix *p = &pentry->prefix;
+             char buf[BUFSIZ];
+
+             vty_out (vty, "%s/%d",
+                      inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                      p->prefixlen);
+
+             if (pentry->ge)
+               vty_out (vty, " ge %d", pentry->ge);
+             if (pentry->le)
+               vty_out (vty, " le %d", pentry->le);
+           }
+         vty_out (vty, "%s", VTY_NEWLINE);
+         write++;
+       }
+      /* vty_out (vty, "!%s", VTY_NEWLINE); */
+    }
+
+  for (plist = master->str.head; plist; plist = plist->next)
+    {
+      if (plist->desc)
+       {
+         vty_out (vty, "ip%s prefix-list %s description %s%s",
+                  afi == AFI_IP ? "" : "v6",
+                  plist->name, plist->desc, VTY_NEWLINE);
+         write++;
+       }
+
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+       {
+         vty_out (vty, "ip%s prefix-list %s ",
+                  afi == AFI_IP ? "" : "v6",
+                  plist->name);
+
+         if (master->seqnum)
+           vty_out (vty, "seq %d ", pentry->seq);
+
+         vty_out (vty, "%s", prefix_list_type_str (pentry));
+
+         if (pentry->any)
+           vty_out (vty, " any");
+         else
+           {
+             struct prefix *p = &pentry->prefix;
+             char buf[BUFSIZ];
+
+             vty_out (vty, " %s/%d",
+                      inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                      p->prefixlen);
+
+             if (pentry->ge)
+               vty_out (vty, " ge %d", pentry->ge);
+             if (pentry->le)
+               vty_out (vty, " le %d", pentry->le);
+           }
+         vty_out (vty, "%s", VTY_NEWLINE);
+         write++;
+       }
+    }
+  
+  return write;
+}
+
+int stream_putc (struct stream *, u_char);
+int stream_putl (struct stream *, u_int32_t);
+int stream_put_prefix (struct stream *, struct prefix *);
+
+struct stream *
+prefix_bgp_orf_entry (struct stream *s, struct prefix_list *plist,
+                     u_char init_flag, u_char permit_flag, u_char deny_flag)
+{
+  struct prefix_list_entry *pentry;
+
+  if (! plist)
+    return s;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      u_char flag = init_flag;
+      struct prefix *p = &pentry->prefix;
+
+      flag |= (pentry->type == PREFIX_PERMIT ?
+               permit_flag : deny_flag);
+      stream_putc (s, flag);
+      stream_putl (s, (u_int32_t)pentry->seq);
+      stream_putc (s, (u_char)pentry->ge);
+      stream_putc (s, (u_char)pentry->le);
+      stream_put_prefix (s, p);
+    }
+
+  return s;
+}
+
+int
+prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp,
+                   int permit, int set)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+
+  /* ge and le value check */ 
+  if (orfp->ge && orfp->ge <= orfp->p.prefixlen)
+    return CMD_WARNING;
+  if (orfp->le && orfp->le <= orfp->p.prefixlen)
+    return CMD_WARNING;
+  if (orfp->le && orfp->ge > orfp->le)
+    return CMD_WARNING;
+
+  if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128))
+    orfp->le = 0;
+
+  plist = prefix_list_get (AFI_ORF_PREFIX, name);
+  if (! plist)
+    return CMD_WARNING;
+
+  if (set)
+    {
+      pentry = prefix_list_entry_make (&orfp->p,
+                                      (permit ? PREFIX_PERMIT : PREFIX_DENY),
+                                      orfp->seq, orfp->le, orfp->ge, 0);
+
+      if (prefix_entry_dup_check (plist, pentry))
+       {
+         prefix_list_entry_free (pentry);
+         return CMD_WARNING;
+       }
+
+      prefix_list_entry_add (plist, pentry);
+    }
+  else
+    {
+      pentry = prefix_list_entry_lookup (plist, &orfp->p,
+                                        (permit ? PREFIX_PERMIT : PREFIX_DENY),
+                                        orfp->seq, orfp->le, orfp->ge);
+
+      if (! pentry)
+       return CMD_WARNING;
+
+      prefix_list_entry_delete (plist, pentry, 1);
+    }
+
+  return CMD_SUCCESS;
+}
+
+void
+prefix_bgp_orf_remove_all (char *name)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (AFI_ORF_PREFIX, name);
+  if (plist)
+    prefix_list_delete (plist);
+}
+
+/* return prefix count */
+int
+prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+
+  plist = prefix_list_lookup (AFI_ORF_PREFIX, name);
+  if (! plist)
+    return 0;
+
+  if (! vty)
+    return plist->count;
+
+  vty_out (vty, "ip%s prefix-list %s: %d entries%s",
+          afi == AFI_IP ? "" : "v6",
+          plist->name, plist->count, VTY_NEWLINE);
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      struct prefix *p = &pentry->prefix;
+      char buf[BUFSIZ];
+
+      vty_out (vty, "   seq %d %s %s/%d", pentry->seq,
+              prefix_list_type_str (pentry),
+              inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+              p->prefixlen);
+
+      if (pentry->ge)
+       vty_out (vty, " ge %d", pentry->ge);
+      if (pentry->le)
+       vty_out (vty, " le %d", pentry->le);
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  return plist->count;
+}
+
+void
+prefix_list_reset_orf ()
+{
+  struct prefix_list *plist;
+  struct prefix_list *next;
+  struct prefix_master *master;
+
+  master = prefix_master_get (AFI_ORF_PREFIX);
+  if (master == NULL)
+    return;
+
+  for (plist = master->num.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+  for (plist = master->str.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+
+  master->seqnum = 1;
+  master->recent = NULL;
+}
+
+
+/* Prefix-list node. */
+struct cmd_node prefix_node =
+{
+  PREFIX_NODE,
+  "",                          /* Prefix list has no interface. */
+  1
+};
+
+int
+config_write_prefix_ipv4 (struct vty *vty)
+{
+  return config_write_prefix_afi (AFI_IP, vty);
+}
+
+void
+prefix_list_reset_ipv4 ()
+{
+  struct prefix_list *plist;
+  struct prefix_list *next;
+  struct prefix_master *master;
+
+  master = prefix_master_get (AFI_IP);
+  if (master == NULL)
+    return;
+
+  for (plist = master->num.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+  for (plist = master->str.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+
+  master->seqnum = 1;
+  master->recent = NULL;
+}
+
+void
+prefix_list_init_ipv4 ()
+{
+  install_node (&prefix_node, config_write_prefix_ipv4);
+
+  install_element (CONFIG_NODE, &ip_prefix_list_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &no_ip_prefix_list_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &ip_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd);
+
+  install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd);
+
+  install_element (VIEW_NODE, &show_ip_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &show_ip_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd);
+}
+
+#ifdef HAVE_IPV6
+/* Prefix-list node. */
+struct cmd_node prefix_ipv6_node =
+{
+  PREFIX_IPV6_NODE,
+  "",                          /* Prefix list has no interface. */
+  1
+};
+
+int
+config_write_prefix_ipv6 (struct vty *vty)
+{
+  return config_write_prefix_afi (AFI_IP6, vty);
+}
+
+void
+prefix_list_reset_ipv6 ()
+{
+  struct prefix_list *plist;
+  struct prefix_list *next;
+  struct prefix_master *master;
+
+  master = prefix_master_get (AFI_IP6);
+  if (master == NULL)
+    return;
+
+  for (plist = master->num.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+  for (plist = master->str.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+
+  master->seqnum = 1;
+  master->recent = NULL;
+}
+
+void
+prefix_list_init_ipv6 ()
+{
+  install_node (&prefix_ipv6_node, config_write_prefix_ipv6);
+
+  install_element (CONFIG_NODE, &ipv6_prefix_list_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd);
+
+  install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd);
+
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd);
+}
+#endif /* HAVE_IPV6 */
+
+void
+prefix_list_init ()
+{
+  prefix_list_init_ipv4 ();
+#ifdef HAVE_IPV6
+  prefix_list_init_ipv6 ();
+#endif /* HAVE_IPV6 */
+}
+
+void
+prefix_list_reset ()
+{
+  prefix_list_reset_ipv4 ();
+#ifdef HAVE_IPV6
+  prefix_list_reset_ipv6 ();
+#endif /* HAVE_IPV6 */
+  prefix_list_reset_orf ();
+}
diff --git a/lib/plist.h b/lib/plist.h
new file mode 100644 (file)
index 0000000..9a9eb71
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Prefix list functions.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define AFI_ORF_PREFIX 65535
+
+enum prefix_list_type 
+{
+  PREFIX_DENY,
+  PREFIX_PERMIT,
+};
+
+enum prefix_name_type
+{
+  PREFIX_TYPE_STRING,
+  PREFIX_TYPE_NUMBER
+};
+
+struct prefix_list
+{
+  char *name;
+  char *desc;
+
+  struct prefix_master *master;
+
+  enum prefix_name_type type;
+
+  int count;
+  int rangecount;
+
+  struct prefix_list_entry *head;
+  struct prefix_list_entry *tail;
+
+  struct prefix_list *next;
+  struct prefix_list *prev;
+};
+
+struct orf_prefix
+{
+  u_int32_t seq;
+  u_char ge;
+  u_char le;
+  struct prefix p;
+};
+
+/* Prototypes. */
+void prefix_list_init (void);
+void prefix_list_reset (void);
+void prefix_list_add_hook (void (*func) (struct prefix_list *));
+void prefix_list_delete_hook (void (*func) (struct prefix_list *));
+
+struct prefix_list *prefix_list_lookup (afi_t, char *);
+enum prefix_list_type prefix_list_apply (struct prefix_list *, void *);
+
+struct stream *
+prefix_bgp_orf_entry (struct stream *, struct prefix_list *,
+                      u_char, u_char, u_char);
+int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int);
+void prefix_bgp_orf_remove_all (char *);
+int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *);
diff --git a/lib/prefix.c b/lib/prefix.c
new file mode 100644 (file)
index 0000000..61e0f19
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * Prefix related functions.
+ * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "log.h"
+\f
+/* Maskbit. */
+static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
+                                0xf8, 0xfc, 0xfe, 0xff};
+
+/* Number of bits in prefix type. */
+#ifndef PNBBY
+#define PNBBY 8
+#endif /* PNBBY */
+
+#define MASKBIT(offset)  ((0xff << (PNBBY - (offset))) & 0xff)
+
+/* Address Famiy Identifier to Address Family converter. */
+int
+afi2family (int afi)
+{
+  if (afi == AFI_IP)
+    return AF_INET;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return AF_INET6;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+int
+family2afi (int family)
+{
+  if (family == AF_INET)
+    return AFI_IP;
+#ifdef HAVE_IPV6
+  else if (family == AF_INET6)
+    return AFI_IP6;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* If n includes p prefix then return 1 else return 0. */
+int
+prefix_match (struct prefix *n, struct prefix *p)
+{
+  int offset;
+  int shift;
+
+  /* Set both prefix's head pointer. */
+  u_char *np = (u_char *)&n->u.prefix;
+  u_char *pp = (u_char *)&p->u.prefix;
+
+  /* If n's prefix is longer than p's one return 0. */
+  if (n->prefixlen > p->prefixlen)
+    return 0;
+
+  offset = n->prefixlen / PNBBY;
+  shift =  n->prefixlen % PNBBY;
+
+  if (shift)
+    if (maskbit[shift] & (np[offset] ^ pp[offset]))
+      return 0;
+  
+  while (offset--)
+    if (np[offset] != pp[offset])
+      return 0;
+  return 1;
+}
+
+/* Copy prefix from src to dest. */
+void
+prefix_copy (struct prefix *dest, struct prefix *src)
+{
+  dest->family = src->family;
+  dest->prefixlen = src->prefixlen;
+
+  if (src->family == AF_INET)
+    dest->u.prefix4 = src->u.prefix4;
+#ifdef HAVE_IPV6
+  else if (src->family == AF_INET6)
+    dest->u.prefix6 = src->u.prefix6;
+#endif /* HAVE_IPV6 */
+  else if (src->family == AF_UNSPEC)
+    {
+      dest->u.lp.id = src->u.lp.id;
+      dest->u.lp.adv_router = src->u.lp.adv_router;
+    }
+  else
+    {
+      zlog (NULL, LOG_INFO, "prefix_copy(): Unknown address family %d",
+             src->family);
+      assert (0);
+    }
+}
+
+/* If both prefix structure is same then return 1 else return 0. */
+int
+prefix_same (struct prefix *p1, struct prefix *p2)
+{
+  if (p1->family == p2->family && p1->prefixlen == p2->prefixlen)
+    {
+      if (p1->family == AF_INET)
+       if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
+         return 1;
+#ifdef HAVE_IPV6
+      if (p1->family == AF_INET6 )
+       if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
+         return 1;
+#endif /* HAVE_IPV6 */
+    }
+  return 0;
+}
+
+/* When both prefix structure is not same, but will be same after
+   applying mask, return 0. otherwise, return 1 */
+int
+prefix_cmp (struct prefix *p1, struct prefix *p2)
+{
+  int offset;
+  int shift;
+
+  /* Set both prefix's head pointer. */
+  u_char *pp1 = (u_char *)&p1->u.prefix;
+  u_char *pp2 = (u_char *)&p2->u.prefix;
+
+  if (p1->family != p2->family || p1->prefixlen != p2->prefixlen)
+    return 1;
+
+  offset = p1->prefixlen / 8;
+  shift = p1->prefixlen % 8;
+
+  if (shift)
+    if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
+      return 1;
+
+  while (offset--)
+    if (pp1[offset] != pp2[offset])
+      return 1;
+
+  return 0;
+}
+
+/* Return prefix family type string. */
+char *
+prefix_family_str (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    return "inet";
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    return "inet6";
+#endif /* HAVE_IPV6 */
+  return "unspec";
+}
+
+/* Allocate new prefix_ipv4 structure. */
+struct prefix_ipv4 *
+prefix_ipv4_new ()
+{
+  struct prefix_ipv4 *p;
+
+  p = XCALLOC (MTYPE_PREFIX_IPV4, sizeof *p);
+  p->family = AF_INET;
+  return p;
+}
+
+/* Free prefix_ipv4 structure. */
+void
+prefix_ipv4_free (struct prefix_ipv4 *p)
+{
+  XFREE (MTYPE_PREFIX_IPV4, p);
+}
+
+/* When string format is invalid return 0. */
+int
+str2prefix_ipv4 (char *str, struct prefix_ipv4 *p)
+{
+  int ret;
+  int plen;
+  char *pnt;
+  char *cp;
+
+  /* Find slash inside string. */
+  pnt = strchr (str, '/');
+
+  /* String doesn't contail slash. */
+  if (pnt == NULL) 
+    {
+      /* Convert string to prefix. */
+      ret = inet_aton (str, &p->prefix);
+      if (ret == 0)
+       return 0;
+
+      /* If address doesn't contain slash we assume it host address. */
+      p->family = AF_INET;
+      p->prefixlen = IPV4_MAX_BITLEN;
+
+      return ret;
+    }
+  else
+    {
+      cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
+      strncpy (cp, str, pnt - str);
+      *(cp + (pnt - str)) = '\0';
+      ret = inet_aton (cp, &p->prefix);
+      XFREE (MTYPE_TMP, cp);
+
+      /* Get prefix length. */
+      plen = (u_char) atoi (++pnt);
+      if (plen > 32)
+       return 0;
+
+      p->family = AF_INET;
+      p->prefixlen = plen;
+    }
+
+  return ret;
+}
+
+/* Convert masklen into IP address's netmask. */
+void
+masklen2ip (int masklen, struct in_addr *netmask)
+{
+  u_char *pnt;
+  int bit;
+  int offset;
+
+  memset (netmask, 0, sizeof (struct in_addr));
+  pnt = (unsigned char *) netmask;
+
+  offset = masklen / 8;
+  bit = masklen % 8;
+  
+  while (offset--)
+    *pnt++ = 0xff;
+
+  if (bit)
+    *pnt = maskbit[bit];
+}
+
+/* Convert IP address's netmask into integer. We assume netmask is
+   sequential one. Argument netmask should be network byte order. */
+u_char
+ip_masklen (struct in_addr netmask)
+{
+  u_char len;
+  u_char *pnt;
+  u_char *end;
+  u_char val;
+
+  len = 0;
+  pnt = (u_char *) &netmask;
+  end = pnt + 4;
+
+  while ((*pnt == 0xff) && pnt < end)
+    {
+      len+= 8;
+      pnt++;
+    } 
+
+  if (pnt < end)
+    {
+      val = *pnt;
+      while (val)
+       {
+         len++;
+         val <<= 1;
+       }
+    }
+  return len;
+}
+
+/* Apply mask to IPv4 prefix. */
+void
+apply_mask_ipv4 (struct prefix_ipv4 *p)
+{
+  u_char *pnt;
+  int index;
+  int offset;
+
+  index = p->prefixlen / 8;
+
+  if (index < 4)
+    {
+      pnt = (u_char *) &p->prefix;
+      offset = p->prefixlen % 8;
+
+      pnt[index] &= maskbit[offset];
+      index++;
+
+      while (index < 4)
+       pnt[index++] = 0;
+    }
+}
+
+/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
+int
+prefix_ipv4_any (struct prefix_ipv4 *p)
+{
+  return (p->prefix.s_addr == 0 && p->prefixlen == 0);
+}
+\f
+#ifdef HAVE_IPV6
+
+/* Allocate a new ip version 6 route */
+struct prefix_ipv6 *
+prefix_ipv6_new ()
+{
+  struct prefix_ipv6 *p;
+
+  p = XCALLOC (MTYPE_PREFIX_IPV6, sizeof (struct prefix_ipv6));
+  p->family = AF_INET6;
+  return p;
+}
+
+/* Free prefix for IPv6. */
+void
+prefix_ipv6_free (struct prefix_ipv6 *p)
+{
+  XFREE (MTYPE_PREFIX_IPV6, p);
+}
+
+/* If given string is valid return pin6 else return NULL */
+int
+str2prefix_ipv6 (char *str, struct prefix_ipv6 *p)
+{
+  char *pnt;
+  char *cp;
+  int ret;
+
+  pnt = strchr (str, '/');
+
+  /* If string doesn't contain `/' treat it as host route. */
+  if (pnt == NULL) 
+    {
+      ret = inet_pton (AF_INET6, str, &p->prefix);
+      if (ret != 1)
+       return 0;
+      p->prefixlen = IPV6_MAX_BITLEN;
+    }
+  else 
+    {
+      int plen;
+
+      cp = XMALLOC (0, (pnt - str) + 1);
+      strncpy (cp, str, pnt - str);
+      *(cp + (pnt - str)) = '\0';
+      ret = inet_pton (AF_INET6, cp, &p->prefix);
+      free (cp);
+      if (ret != 1)
+       return 0;
+      plen = (u_char) atoi (++pnt);
+      if (plen > 128)
+       return 0;
+      p->prefixlen = plen;
+    }
+  p->family = AF_INET6;
+
+  return ret;
+}
+
+/* Convert struct in6_addr netmask into integer. */
+int
+ip6_masklen (struct in6_addr netmask)
+{
+  int len = 0;
+  unsigned char val;
+  unsigned char *pnt;
+  
+  pnt = (unsigned char *) & netmask;
+
+  while ((*pnt == 0xff) && len < 128) 
+    {
+      len += 8;
+      pnt++;
+    } 
+  
+  if (len < 128) 
+    {
+      val = *pnt;
+      while (val) 
+       {
+         len++;
+         val <<= 1;
+       }
+    }
+  return len;
+}
+
+void
+masklen2ip6 (int masklen, struct in6_addr *netmask)
+{
+  unsigned char *pnt;
+  int bit;
+  int offset;
+
+  memset (netmask, 0, sizeof (struct in6_addr));
+  pnt = (unsigned char *) netmask;
+
+  offset = masklen / 8;
+  bit = masklen % 8;
+
+  while (offset--)
+    *pnt++ = 0xff;
+
+  if (bit)
+    *pnt = maskbit[bit];
+}
+
+void
+apply_mask_ipv6 (struct prefix_ipv6 *p)
+{
+  u_char *pnt;
+  int index;
+  int offset;
+
+  index = p->prefixlen / 8;
+
+  if (index < 16)
+    {
+      pnt = (u_char *) &p->prefix;
+      offset = p->prefixlen % 8;
+
+      pnt[index] &= maskbit[offset];
+      index++;
+
+      while (index < 16)
+       pnt[index++] = 0;
+    }
+}
+
+void
+str2in6_addr (char *str, struct in6_addr *addr)
+{
+  int i;
+  unsigned int x;
+
+  /* %x must point to unsinged int */
+  for (i = 0; i < 16; i++)
+    {
+      sscanf (str + (i * 2), "%02x", &x);
+      addr->s6_addr[i] = x & 0xff;
+    }
+}
+#endif /* HAVE_IPV6 */
+
+void
+apply_mask (struct prefix *p)
+{
+  switch (p->family)
+    {
+      case AF_INET:
+        apply_mask_ipv4 ((struct prefix_ipv4 *)p);
+        break;
+#ifdef HAVE_IPV6
+      case AF_INET6:
+        apply_mask_ipv6 ((struct prefix_ipv6 *)p);
+        break;
+#endif /* HAVE_IPV6 */
+      default:
+        break;
+    }
+  return;
+}
+
+/* Utility function of convert between struct prefix <=> union sockunion */
+struct prefix *
+sockunion2prefix (union sockunion *dest,
+                 union sockunion *mask)
+{
+  if (dest->sa.sa_family == AF_INET)
+    {
+      struct prefix_ipv4 *p;
+
+      p = prefix_ipv4_new ();
+      p->family = AF_INET;
+      p->prefix = dest->sin.sin_addr;
+      p->prefixlen = ip_masklen (mask->sin.sin_addr);
+      return (struct prefix *) p;
+    }
+#ifdef HAVE_IPV6
+  if (dest->sa.sa_family == AF_INET6)
+    {
+      struct prefix_ipv6 *p;
+
+      p = prefix_ipv6_new ();
+      p->family = AF_INET6;
+      p->prefixlen = ip6_masklen (mask->sin6.sin6_addr);
+      memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr));
+      return (struct prefix *) p;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* Utility function of convert between struct prefix <=> union sockunion */
+struct prefix *
+sockunion2hostprefix (union sockunion *su)
+{
+  if (su->sa.sa_family == AF_INET)
+    {
+      struct prefix_ipv4 *p;
+
+      p = prefix_ipv4_new ();
+      p->family = AF_INET;
+      p->prefix = su->sin.sin_addr;
+      p->prefixlen = IPV4_MAX_BITLEN;
+      return (struct prefix *) p;
+    }
+#ifdef HAVE_IPV6
+  if (su->sa.sa_family == AF_INET6)
+    {
+      struct prefix_ipv6 *p;
+
+      p = prefix_ipv6_new ();
+      p->family = AF_INET6;
+      p->prefixlen = IPV6_MAX_BITLEN;
+      memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr));
+      return (struct prefix *) p;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+int
+prefix_blen (struct prefix *p)
+{
+  switch (p->family) 
+    {
+    case AF_INET:
+      return IPV4_MAX_BYTELEN;
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      return IPV6_MAX_BYTELEN;
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return 0;
+}
+
+/* Generic function for conversion string to struct prefix. */
+int
+str2prefix (char *str, struct prefix *p)
+{
+  int ret;
+
+  /* First we try to convert string to struct prefix_ipv4. */
+  ret = str2prefix_ipv4 (str, (struct prefix_ipv4 *) p);
+  if (ret)
+    return ret;
+
+#ifdef HAVE_IPV6
+  /* Next we try to convert string to struct prefix_ipv6. */
+  ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p);
+  if (ret)
+    return ret;
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+int
+prefix2str (struct prefix *p, char *str, int size)
+{
+  char buf[BUFSIZ];
+
+  inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ);
+  snprintf (str, size, "%s/%d", buf, p->prefixlen);
+  return 0;
+}
+
+struct prefix *
+prefix_new ()
+{
+  struct prefix *p;
+
+  p = XCALLOC (MTYPE_PREFIX, sizeof *p);
+  return p;
+}
+
+/* Free prefix structure. */
+void
+prefix_free (struct prefix *p)
+{
+  XFREE (MTYPE_PREFIX, p);
+}
+
+/* Utility function.  Check the string only contains digit
+   character. */
+int
+all_digit (char *str)
+{
+  for (; *str != '\0'; str++)
+    if (!isdigit ((int) *str))
+      return 0;
+  return 1;
+}
+
+/* Utility function to convert ipv4 prefixes to Classful prefixes */
+void apply_classful_mask_ipv4 (struct prefix_ipv4 *p)
+{
+
+  u_int32_t destination;
+  
+  destination = ntohl (p->prefix.s_addr);
+  
+  if (p->prefixlen == 32);
+  /* do nothing for host routes */
+  else if (IN_CLASSC (destination)) 
+    {
+      p->prefixlen=24;
+      apply_mask_ipv4(p);
+    }
+  else if (IN_CLASSB(destination)) 
+    {
+      p->prefixlen=16;
+      apply_mask_ipv4(p);
+    }
+  else 
+    {
+      p->prefixlen=8;
+      apply_mask_ipv4(p);
+    }
+}
+
+/* Utility function to convert ipv4 netmask to prefixes 
+   ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
+   ex.) "1.0.0.0" NULL => "1.0.0.0/8"                   */
+int
+netmask_str2prefix_str (char *net_str, char *mask_str, char *prefix_str)
+{
+  struct in_addr network;
+  struct in_addr mask;
+  u_char prefixlen;
+  u_int32_t destination;
+  int ret;
+
+  ret = inet_aton (net_str, &network);
+  if (! ret)
+    return 0;
+
+  if (mask_str)
+    {
+      ret = inet_aton (mask_str, &mask);
+      if (! ret)
+        return 0;
+
+      prefixlen = ip_masklen (mask);
+    }
+  else 
+    {
+      destination = ntohl (network.s_addr);
+
+      if (network.s_addr == 0)
+       prefixlen = 0;
+      else if (IN_CLASSC (destination))
+       prefixlen = 24;
+      else if (IN_CLASSB (destination))
+       prefixlen = 16;
+      else if (IN_CLASSA (destination))
+       prefixlen = 8;
+      else
+       return 0;
+    }
+
+  sprintf (prefix_str, "%s/%d", net_str, prefixlen);
+
+  return 1;
+}
+
diff --git a/lib/prefix.h b/lib/prefix.h
new file mode 100644 (file)
index 0000000..7d7cde6
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Prefix structure.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_PREFIX_H
+#define _ZEBRA_PREFIX_H
+
+/* IPv4 and IPv6 unified prefix structure. */
+struct prefix
+{
+  u_char family;
+  u_char prefixlen;
+  union 
+  {
+    u_char prefix;
+    struct in_addr prefix4;
+#ifdef HAVE_IPV6
+    struct in6_addr prefix6;
+#endif /* HAVE_IPV6 */
+    struct 
+    {
+      struct in_addr id;
+      struct in_addr adv_router;
+    } lp;
+    u_char val[8];
+  } u __attribute__ ((aligned (8)));
+};
+
+/* IPv4 prefix structure. */
+struct prefix_ipv4
+{
+  u_char family;
+  u_char prefixlen;
+  struct in_addr prefix __attribute__ ((aligned (8)));
+};
+
+/* IPv6 prefix structure. */
+#ifdef HAVE_IPV6
+struct prefix_ipv6
+{
+  u_char family;
+  u_char prefixlen;
+  struct in6_addr prefix __attribute__ ((aligned (8)));
+};
+#endif /* HAVE_IPV6 */
+
+struct prefix_ls
+{
+  u_char family;
+  u_char prefixlen;
+  struct in_addr id __attribute__ ((aligned (8)));
+  struct in_addr adv_router;
+};
+
+/* Prefix for routing distinguisher. */
+struct prefix_rd
+{
+  u_char family;
+  u_char prefixlen;
+  u_char val[8] __attribute__ ((aligned (8)));
+};
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif /* INET_ADDRSTRLEN */
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif /* INET6_ADDRSTRLEN */
+
+#ifndef INET6_BUFSIZ
+#define INET6_BUFSIZ 51
+#endif /* INET6_BUFSIZ */
+
+/* Max bit/byte length of IPv4 address. */
+#define IPV4_MAX_BYTELEN    4
+#define IPV4_MAX_BITLEN    32
+#define IPV4_MAX_PREFIXLEN 32
+#define IPV4_ADDR_CMP(D,S)   memcmp ((D), (S), IPV4_MAX_BYTELEN)
+#define IPV4_ADDR_SAME(D,S)  (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0)
+#define IPV4_ADDR_COPY(D,S)  memcpy ((D), (S), IPV4_MAX_BYTELEN)
+
+#define IPV4_NET0(a)    ((((u_int32_t) (a)) & 0xff000000) == 0x00000000)
+#define IPV4_NET127(a)  ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000)
+
+/* Max bit/byte length of IPv6 address. */
+#define IPV6_MAX_BYTELEN    16
+#define IPV6_MAX_BITLEN    128
+#define IPV6_MAX_PREFIXLEN 128
+#define IPV6_ADDR_CMP(D,S)   memcmp ((D), (S), IPV6_MAX_BYTELEN)
+#define IPV6_ADDR_SAME(D,S)  (memcmp ((D), (S), IPV6_MAX_BYTELEN) == 0)
+#define IPV6_ADDR_COPY(D,S)  memcpy ((D), (S), IPV6_MAX_BYTELEN)
+
+/* Count prefix size from mask length */
+#define PSIZE(a) (((a) + 7) / (8))
+
+/* Prefix's family member. */
+#define PREFIX_FAMILY(p)  ((p)->family)
+
+/* Prototypes. */
+int afi2family (int);
+int family2afi (int);
+
+int prefix2str (struct prefix *, char *, int);
+int str2prefix (char *, struct prefix *);
+struct prefix *prefix_new ();
+void prefix_free (struct prefix *p);
+
+struct prefix_ipv4 *prefix_ipv4_new ();
+void prefix_ipv4_free ();
+int str2prefix_ipv4 (char *, struct prefix_ipv4 *);
+void apply_mask_ipv4 (struct prefix_ipv4 *);
+int prefix_blen (struct prefix *);
+u_char ip_masklen (struct in_addr);
+int prefix_ipv4_any (struct prefix_ipv4 *);
+void masklen2ip (int, struct in_addr *);
+void apply_classful_mask_ipv4 (struct prefix_ipv4 *);
+
+char *prefix_family_str (struct prefix *p);
+struct prefix *sockunion2prefix ();
+struct prefix *sockunion2hostprefix ();
+
+#ifdef HAVE_IPV6
+struct prefix_ipv6 *prefix_ipv6_new ();
+void prefix_ipv6_free ();
+struct prefix *str2routev6 (char *);
+int str2prefix_ipv6 (char *str, struct prefix_ipv6 *p);
+void apply_mask_ipv6 (struct prefix_ipv6 *p);
+void str2in6_addr (char *str, struct in6_addr *addr);
+void masklen2ip6 (int masklen, struct in6_addr *netmask);
+int ip6_masklen (struct in6_addr netmask);
+#endif /* HAVE_IPV6 */
+
+void apply_mask (struct prefix *);
+int prefix_match (struct prefix *n, struct prefix *p);
+int prefix_same (struct prefix *, struct prefix *);
+int prefix_cmp (struct prefix *, struct prefix *);
+void prefix_copy (struct prefix *, struct prefix *);
+
+int all_digit (char *);
+int netmask_str2prefix_str (char *, char *, char *);
+
+#endif /* _ZEBRA_PREFIX_H */
diff --git a/lib/print_version.c b/lib/print_version.c
new file mode 100644 (file)
index 0000000..6b4064d
--- /dev/null
@@ -0,0 +1,31 @@
+/* Print version function.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+
+void
+print_version (char *progname)
+{
+  printf ("%s version %s (%s)\n", progname, ZEBRA_VERSION, host_name);
+  printf ("Copyright 1996-2001, Kunihiro Ishiguro\n");
+}
diff --git a/lib/regex-gnu.h b/lib/regex-gnu.h
new file mode 100644 (file)
index 0000000..d88ab92
--- /dev/null
@@ -0,0 +1,542 @@
+/* Definitions for data structures and routines for the regular
+   expression library, version 0.12.
+   Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+/* Allow the use in C++ code.  */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+   <regex.h>.  */
+
+#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+   should be there.  */
+# include <stddef.h>
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+   wide enough to hold a value of a pointer.  For most ANSI compilers
+   ptrdiff_t and size_t should be likely OK.  Still size of these two
+   types is 2 for Microsoft C.  Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals.
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+        ^  is an anchor if it is at the beginning of a regular
+           expression or after an open-group or an alternation operator;
+        $  is an anchor if it is at the end of a regular expression, or
+           before a close-group or an alternation operator.
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically,
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES.
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+   without further backtracking.  */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+   If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+   If not set, and debugging was on, turn it off.
+   This only works if regex.c is compiled -DDEBUG.
+   We define this bit always, so that all that's needed to turn on
+   debugging is to recompile regex.c; the calling code can always have
+   this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+\f
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK                                                  \
+  (RE_BACKSLASH_ESCAPE_IN_LISTS   | RE_DOT_NOT_NULL                    \
+   | RE_NO_BK_PARENS              | RE_NO_BK_REFS                      \
+   | RE_NO_BK_VBAR                | RE_NO_EMPTY_RANGES                 \
+   | RE_DOT_NEWLINE              | RE_CONTEXT_INDEP_ANCHORS            \
+   | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK                                              \
+  ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG)        \
+   & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS))
+
+#define RE_SYNTAX_POSIX_AWK                                            \
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS             \
+   | RE_INTERVALS          | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP                                                 \
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES                                \
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS                           \
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP                                                        \
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS                   \
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE                   \
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS                            \
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP                                          \
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON                                                \
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL             \
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC                                          \
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC                                  \
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED                                       \
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS                  \
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES                           \
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR                             \
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED                               \
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS                 \
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES                          \
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS                            \
+   | RE_NO_BK_VBAR         | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+\f
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+# undef RE_DUP_MAX
+#endif
+/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows.  */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+#ifdef _XOPEN_SOURCE
+  REG_ENOSYS = -1,     /* This will never happen for this implementation.  */
+#endif
+
+  REG_NOERROR = 0,     /* Success.  */
+  REG_NOMATCH,         /* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,          /* Invalid pattern.  */
+  REG_ECOLLATE,                /* Not implemented.  */
+  REG_ECTYPE,          /* Invalid character class name.  */
+  REG_EESCAPE,         /* Trailing backslash.  */
+  REG_ESUBREG,         /* Invalid back reference.  */
+  REG_EBRACK,          /* Unmatched left bracket.  */
+  REG_EPAREN,          /* Parenthesis imbalance.  */
+  REG_EBRACE,          /* Unmatched \{.  */
+  REG_BADBR,           /* Invalid contents of \{\}.  */
+  REG_ERANGE,          /* Invalid range end.  */
+  REG_ESPACE,          /* Ran out of memory.  */
+  REG_BADRPT,          /* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,            /* Premature end.  */
+  REG_ESIZE,           /* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN          /* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+\f
+/* This data structure represents a compiled pattern.  Before calling
+   the pattern compiler, the fields `buffer', `allocated', `fastmap',
+   `translate', and `no_sub' can be set.  After the pattern has been
+   compiled, the `re_nsub' field is available.  All other fields are
+   private to the regex routines.  */
+
+#ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE char *
+#endif
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+       /* Space that holds the compiled pattern.  It is declared as
+          `unsigned char *' because its elements are
+           sometimes used as array indexes.  */
+  unsigned char *buffer;
+
+       /* Number of bytes to which `buffer' points.  */
+  unsigned long int allocated;
+
+       /* Number of bytes actually used in `buffer'.  */
+  unsigned long int used;
+
+        /* Syntax setting with which the pattern was compiled.  */
+  reg_syntax_t syntax;
+
+        /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+           the fastmap, if there is one, to skip over impossible
+           starting points for matches.  */
+  char *fastmap;
+
+        /* Either a translate table to apply to all characters before
+           comparing them, or zero for no translation.  The translation
+           is applied to a pattern when it is compiled and to a string
+           when it is matched.  */
+  RE_TRANSLATE_TYPE translate;
+
+       /* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+        /* Zero if this pattern cannot match the empty string, one else.
+           Well, in truth it's used only in `re_search_2', to see
+           whether or not we should use the fastmap, so we don't set
+           this absolutely perfectly; see `re_compile_fastmap' (the
+           `duplicate' case).  */
+  unsigned can_be_null : 1;
+
+        /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+             for `max (RE_NREGS, re_nsub + 1)' groups.
+           If REGS_REALLOCATE, reallocate space if necessary.
+           If REGS_FIXED, use what's there.  */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned regs_allocated : 2;
+
+        /* Set to zero when `regex_compile' compiles a pattern; set to one
+           by `re_compile_fastmap' if it updates the fastmap.  */
+  unsigned fastmap_accurate : 1;
+
+        /* If set, `re_match_2' does not return information about
+           subexpressions.  */
+  unsigned no_sub : 1;
+
+        /* If set, a beginning-of-line anchor doesn't match at the
+           beginning of the string.  */
+  unsigned not_bol : 1;
+
+        /* Similarly for an end-of-line anchor.  */
+  unsigned not_eol : 1;
+
+        /* If true, an anchor at a newline matches.  */
+  unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+\f
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+   `re_match_2' returns information about at least this many registers
+   the first time a `regs' structure is passed.  */
+#ifndef RE_NREGS
+# define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+\f
+/* Declarations for routines.  */
+
+/* To avoid duplicating every routine declaration -- once with a
+   prototype (if we are ANSI), and once without (if we aren't) -- we
+   use the following macro to declare argument types.  This
+   unfortunately clutters up the declarations a bit, but I think it's
+   worth it.  */
+
+#if __STDC__
+
+# define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+# define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+   You can also simply assign to the `re_syntax_options' variable.  */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+   and syntax given by the global `re_syntax_options', into the buffer
+   BUFFER.  Return NULL if successful, and an error string if not.  */
+extern const char *re_compile_pattern
+  _RE_ARGS ((const char *pattern, size_t length,
+             struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+   accelerate searches.  Return 0 if successful and -2 if was an
+   internal error.  */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+   compiled into BUFFER.  Start searching at position START, for RANGE
+   characters.  Return the starting position of the match, -1 for no
+   match, or -2 for an internal error.  Also return register
+   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
+extern int re_search
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+            int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+   STRING2.  Also, stop searching at index START + STOP.  */
+extern int re_search_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+   in BUFFER matched, starting at position START.  */
+extern int re_match
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+             int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
+extern int re_match_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
+   for recording register information.  STARTS and ENDS must be
+   allocated with malloc, and must each be at least `NUM_REGS * sizeof
+   (regoff_t)' bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+extern void re_set_registers
+  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+             unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility.  */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+# endif
+#endif
+
+/* POSIX compatibility.  */
+extern int regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
+                             int __cflags));
+
+extern int regexec _RE_ARGS ((const regex_t *__preg,
+                             const char *__string, size_t __nmatch,
+                             regmatch_t __pmatch[], int __eflags));
+
+extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+                                 char *__errbuf, size_t __errbuf_size));
+
+extern void regfree _RE_ARGS ((regex_t *__preg));
+
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* regex.h */
+\f
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/lib/regex.c b/lib/regex.c
new file mode 100644 (file)
index 0000000..8c7acd5
--- /dev/null
@@ -0,0 +1,5891 @@
+/* Extended regular expression matching and search library,
+   version 0.12.
+   (Implements POSIX draft P1003.2/D11.2, except for some of the
+   internationalization features.)
+   Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined _AIX && !defined REGEX_MALLOC
+  #pragma alloca
+#endif
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef PARAMS
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif  /* GCC.  */
+#endif  /* Not PARAMS.  */
+
+#if defined STDC_HEADERS && !defined emacs
+# include <stddef.h>
+#else
+/* We need this for `regex.h', and perhaps for the Emacs include files.  */
+# include <sys/types.h>
+#endif
+
+#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
+
+/* For platform which support the ISO C amendement 1 functionality we
+   support user defined character classes.  */
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean.  */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+       __regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+       __re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+       __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+       __re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+       __re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+       __re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+       __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+#define btowc __btowc
+#endif
+
+/* This is for other GNU distributions with internationalized messages.  */
+#if HAVE_LIBINTL_H || defined _LIBC
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+   strings.  */
+# define gettext_noop(String) String
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+   that make sense only in Emacs. */
+#ifdef emacs
+
+# include "lisp.h"
+# include "buffer.h"
+# include "syntax.h"
+
+#else  /* not emacs */
+
+/* If we are not linking with Emacs proper,
+   we can't use the relocating allocator
+   even if config.h says that we can.  */
+# undef REL_ALLOC
+
+# if defined STDC_HEADERS || defined _LIBC
+#  include <stdlib.h>
+# else
+char *malloc ();
+char *realloc ();
+# endif
+
+/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
+   If nothing else has been done, use the method below.  */
+# ifdef INHIBIT_STRING_HEADER
+#  if !(defined HAVE_BZERO && defined HAVE_BCOPY)
+#   if !defined bzero && !defined bcopy
+#    undef INHIBIT_STRING_HEADER
+#   endif
+#  endif
+# endif
+
+/* This is the normal way of making sure we have a bcopy and a bzero.
+   This is used in most programs--a few other programs avoid this
+   by defining INHIBIT_STRING_HEADER.  */
+# ifndef INHIBIT_STRING_HEADER
+#  if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
+#   include <string.h>
+#   ifndef bzero
+#    ifndef _LIBC
+#     define bzero(s, n)       (memset (s, '\0', n), (s))
+#    else
+#     define bzero(s, n)       __bzero (s, n)
+#    endif
+#   endif
+#  else
+#   include <strings.h>
+#   ifndef memcmp
+#    define memcmp(s1, s2, n)  bcmp (s1, s2, n)
+#   endif
+#   ifndef memcpy
+#    define memcpy(d, s, n)    (bcopy (s, d, n), (d))
+#   endif
+#  endif
+# endif
+
+/* Define the syntax stuff for \<, \>, etc.  */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+   commands in re_match_2.  */
+# ifndef Sword
+#  define Sword 1
+# endif
+
+# ifdef SWITCH_ENUM_BUG
+#  define SWITCH_ENUM_CAST(x) ((int)(x))
+# else
+#  define SWITCH_ENUM_CAST(x) (x)
+# endif
+
+/* How many characters in the character set.  */
+# define CHAR_SET_SIZE 256
+
+# ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+# else /* not SYNTAX_TABLE */
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+   register int c;
+   static int done;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+
+# endif /* not SYNTAX_TABLE */
+
+# define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+\f
+/* Get the interface, including the syntax bits.  */
+#include <regex-gnu.h>
+
+/* isalpha etc. are used for the character classes.  */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+   "... Some ctype macros are valid only for character codes that
+   isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+   using /bin/cc or gcc but without giving an ansi option).  So, all
+   ctype uses should be through macros like ISPRINT...  If
+   STDC_HEADERS is defined, then autoconf has verified that the ctype
+   macros don't need to be guarded with references to isascii. ...
+   Defining isascii to 1 should let any compiler worth its salt
+   eliminate the && through constant folding."
+   Solaris defines some of these symbols so we must undefine them first.  */
+
+#undef ISASCII
+#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define ISASCII(c) 1
+#else
+# define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#undef ISPRINT
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifdef _tolower
+# define TOLOWER(c) _tolower(c)
+#else
+# define TOLOWER(c) tolower(c)
+#endif
+
+#ifndef NULL
+# define NULL (void *)0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+   since ours (we hope) works properly with all combinations of
+   machines, compilers, `char' and `unsigned char' argument types.
+   (Per Bothner suggested the basic approach.)  */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+# define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else  /* not __STDC__ */
+/* As in Harbison and Steele.  */
+# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+\f
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+   use `alloca' instead of `malloc'.  This is because using malloc in
+   re_search* or re_match* could cause memory leaks when C-g is used in
+   Emacs; also, malloc is slower and causes storage fragmentation.  On
+   the other hand, malloc is more portable, and easier to debug.
+
+   Because we sometimes use alloca, some routines have to be macros,
+   not functions -- `alloca'-allocated space disappears at the end of the
+   function it is called in.  */
+
+#ifdef REGEX_MALLOC
+
+# define REGEX_ALLOCATE malloc
+# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+# define REGEX_FREE free
+
+#else /* not REGEX_MALLOC  */
+
+/* Emacs already defines alloca, sometimes.  */
+# ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#  ifdef __GNUC__
+#   define alloca __builtin_alloca
+#  else /* not __GNUC__ */
+#   if HAVE_ALLOCA_H
+#    include <alloca.h>
+#   endif /* HAVE_ALLOCA_H */
+#  endif /* not __GNUC__ */
+
+# endif /* not alloca */
+
+# define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable.  */
+# define REGEX_REALLOCATE(source, osize, nsize)                                \
+  (destination = (char *) alloca (nsize),                              \
+   memcpy (destination, source, osize))
+
+/* No need to do anything to free, after alloca.  */
+# define REGEX_FREE(arg) ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack.  */
+
+#if defined REL_ALLOC && defined REGEX_MALLOC
+
+# define REGEX_ALLOCATE_STACK(size)                            \
+  r_alloc (&failure_stack_ptr, (size))
+# define REGEX_REALLOCATE_STACK(source, osize, nsize)          \
+  r_re_alloc (&failure_stack_ptr, (nsize))
+# define REGEX_FREE_STACK(ptr)                                 \
+  r_alloc_free (&failure_stack_ptr)
+
+#else /* not using relocating allocator */
+
+# ifdef REGEX_MALLOC
+
+#  define REGEX_ALLOCATE_STACK malloc
+#  define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#  define REGEX_FREE_STACK free
+
+# else /* not REGEX_MALLOC */
+
+#  define REGEX_ALLOCATE_STACK alloca
+
+#  define REGEX_REALLOCATE_STACK(source, osize, nsize)                 \
+   REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything.  */
+#  define REGEX_FREE_STACK(arg)
+
+# endif /* not REGEX_MALLOC */
+#endif /* not using relocating allocator */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+   `string1' or just past its end.  This works if PTR is NULL, which is
+   a good thing.  */
+#define FIRST_STRING_P(ptr)                                    \
+  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail.  */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+  if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits.  */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp,
+                                       const char *string1, int size1,
+                                       const char *string2, int size2,
+                                       int pos,
+                                       struct re_registers *regs,
+                                       int stop));
+\f
+/* These are the command codes that appear in compiled regular
+   expressions.  Some opcodes are followed by argument bytes.  A
+   command code can specify any interpretation whatsoever for its
+   arguments.  Zero bytes may appear in the compiled regular expression.  */
+
+typedef enum
+{
+  no_op = 0,
+
+  /* Succeed right away--no more backtracking.  */
+  succeed,
+
+        /* Followed by one byte giving n, then by n literal bytes.  */
+  exactn,
+
+        /* Matches any (more or less) character.  */
+  anychar,
+
+        /* Matches any one char belonging to specified set.  First
+           following byte is number of bitmap bytes.  Then come bytes
+           for a bitmap saying which chars are in.  Bits in each byte
+           are ordered low-bit-first.  A character is in the set if its
+           bit is 1.  A character too large to have a bit in the map is
+           automatically not in the set.  */
+  charset,
+
+        /* Same parameters as charset, but match any character that is
+           not one of those specified.  */
+  charset_not,
+
+        /* Start remembering the text that is matched, for storing in a
+           register.  Followed by one byte with the register number, in
+           the range 0 to one less than the pattern buffer's re_nsub
+           field.  Then followed by one byte with the number of groups
+           inner to this one.  (This last has to be part of the
+           start_memory only because we need it in the on_failure_jump
+           of re_match_2.)  */
+  start_memory,
+
+        /* Stop remembering the text that is matched and store it in a
+           memory register.  Followed by one byte with the register
+           number, in the range 0 to one less than `re_nsub' in the
+           pattern buffer, and one byte with the number of inner groups,
+           just like `start_memory'.  (We need the number of inner
+           groups here because we don't have any easy way of finding the
+           corresponding start_memory when we're at a stop_memory.)  */
+  stop_memory,
+
+        /* Match a duplicate of something remembered. Followed by one
+           byte containing the register number.  */
+  duplicate,
+
+        /* Fail unless at beginning of line.  */
+  begline,
+
+        /* Fail unless at end of line.  */
+  endline,
+
+        /* Succeeds if at beginning of buffer (if emacs) or at beginning
+           of string to be matched (if not).  */
+  begbuf,
+
+        /* Analogously, for end of buffer/string.  */
+  endbuf,
+
+        /* Followed by two byte relative address to which to jump.  */
+  jump,
+
+       /* Same as jump, but marks the end of an alternative.  */
+  jump_past_alt,
+
+        /* Followed by two-byte relative address of place to resume at
+           in case of failure.  */
+  on_failure_jump,
+
+        /* Like on_failure_jump, but pushes a placeholder instead of the
+           current string position when executed.  */
+  on_failure_keep_string_jump,
+
+        /* Throw away latest failure point and then jump to following
+           two-byte relative address.  */
+  pop_failure_jump,
+
+        /* Change to pop_failure_jump if know won't have to backtrack to
+           match; otherwise change to jump.  This is used to jump
+           back to the beginning of a repeat.  If what follows this jump
+           clearly won't match what the repeat does, such that we can be
+           sure that there is no use backtracking out of repetitions
+           already matched, then we change it to a pop_failure_jump.
+           Followed by two-byte address.  */
+  maybe_pop_jump,
+
+        /* Jump to following two-byte address, and push a dummy failure
+           point. This failure point will be thrown away if an attempt
+           is made to use it for a failure.  A `+' construct makes this
+           before the first repeat.  Also used as an intermediary kind
+           of jump when compiling an alternative.  */
+  dummy_failure_jump,
+
+       /* Push a dummy failure point and continue.  Used at the end of
+          alternatives.  */
+  push_dummy_failure,
+
+        /* Followed by two-byte relative address and two-byte number n.
+           After matching N times, jump to the address upon failure.  */
+  succeed_n,
+
+        /* Followed by two-byte relative address, and two-byte number n.
+           Jump to the address N times, then fail.  */
+  jump_n,
+
+        /* Set the following two-byte relative address to the
+           subsequent two-byte number.  The address *includes* the two
+           bytes of number.  */
+  set_number_at,
+
+  wordchar,    /* Matches any word-constituent character.  */
+  notwordchar, /* Matches any char that is not a word-constituent.  */
+
+  wordbeg,     /* Succeeds if at word beginning.  */
+  wordend,     /* Succeeds if at word end.  */
+
+  wordbound,   /* Succeeds if at a word boundary.  */
+  notwordbound /* Succeeds if not at a word boundary.  */
+
+#ifdef emacs
+  ,before_dot, /* Succeeds if before point.  */
+  at_dot,      /* Succeeds if at point.  */
+  after_dot,   /* Succeeds if after point.  */
+
+       /* Matches any character whose syntax is specified.  Followed by
+           a byte which contains a syntax code, e.g., Sword.  */
+  syntaxspec,
+
+       /* Matches any character whose syntax is not that specified.  */
+  notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+\f
+/* Common operations on the compiled pattern.  */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
+
+#define STORE_NUMBER(destination, number)                              \
+  do {                                                                 \
+    (destination)[0] = (number) & 0377;                                        \
+    (destination)[1] = (number) >> 8;                                  \
+  } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+   the byte after where the number is stored.  Therefore, DESTINATION
+   must be an lvalue.  */
+
+#define STORE_NUMBER_AND_INCR(destination, number)                     \
+  do {                                                                 \
+    STORE_NUMBER (destination, number);                                        \
+    (destination) += 2;                                                        \
+  } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+   at SOURCE.  */
+
+#define EXTRACT_NUMBER(destination, source)                            \
+  do {                                                                 \
+    (destination) = *(source) & 0377;                                  \
+    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;          \
+  } while (0)
+
+#ifdef DEBUG
+static void extract_number _RE_ARGS ((int *dest, unsigned char *source));
+static void
+extract_number (dest, source)
+    int *dest;
+    unsigned char *source;
+{
+  int temp = SIGN_EXTEND_CHAR (*(source + 1));
+  *dest = *source & 0377;
+  *dest += temp << 8;
+}
+
+# ifndef EXTRACT_MACROS /* To debug the macros.  */
+#  undef EXTRACT_NUMBER
+#  define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+# endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+   SOURCE must be an lvalue.  */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source)                   \
+  do {                                                                 \
+    EXTRACT_NUMBER (destination, source);                              \
+    (source) += 2;                                                     \
+  } while (0)
+
+#ifdef DEBUG
+static void extract_number_and_incr _RE_ARGS ((int *destination,
+                                              unsigned char **source));
+static void
+extract_number_and_incr (destination, source)
+    int *destination;
+    unsigned char **source;
+{
+  extract_number (destination, *source);
+  *source += 2;
+}
+
+# ifndef EXTRACT_MACROS
+#  undef EXTRACT_NUMBER_AND_INCR
+#  define EXTRACT_NUMBER_AND_INCR(dest, src) \
+  extract_number_and_incr (&dest, &src)
+# endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+\f
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+   it is doing (if the variable `debug' is nonzero).  If linked with the
+   main program in `iregex.c', you can enter patterns and strings
+   interactively.  And if linked with the main program in `main.c' and
+   the other test files, you can run the already-written tests.  */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging.  */
+# include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging.  */
+# include <assert.h>
+
+static int debug;
+
+# define DEBUG_STATEMENT(e) e
+# define DEBUG_PRINT1(x) if (debug) printf (x)
+# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)                                 \
+  if (debug) print_partial_compiled_pattern (s, e)
+# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)                        \
+  if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form.  */
+
+void
+print_fastmap (fastmap)
+    char *fastmap;
+{
+  unsigned was_a_range = 0;
+  unsigned i = 0;
+
+  while (i < (1 << BYTEWIDTH))
+    {
+      if (fastmap[i++])
+       {
+         was_a_range = 0;
+          putchar (i - 1);
+          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
+            {
+              was_a_range = 1;
+              i++;
+            }
+         if (was_a_range)
+            {
+              printf ("-");
+              putchar (i - 1);
+            }
+        }
+    }
+  putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+   the START pointer into it and ending just before the pointer END.  */
+
+void
+print_partial_compiled_pattern (start, end)
+    unsigned char *start;
+    unsigned char *end;
+{
+  int mcnt, mcnt2;
+  unsigned char *p1;
+  unsigned char *p = start;
+  unsigned char *pend = end;
+
+  if (start == NULL)
+    {
+      printf ("(null)\n");
+      return;
+    }
+
+  /* Loop over pattern commands.  */
+  while (p < pend)
+    {
+      printf ("%d:\t", p - start);
+
+      switch ((re_opcode_t) *p++)
+       {
+        case no_op:
+          printf ("/no_op");
+          break;
+
+       case exactn:
+         mcnt = *p++;
+          printf ("/exactn/%d", mcnt);
+          do
+           {
+              putchar ('/');
+             putchar (*p++);
+            }
+          while (--mcnt);
+          break;
+
+       case start_memory:
+          mcnt = *p++;
+          printf ("/start_memory/%d/%d", mcnt, *p++);
+          break;
+
+       case stop_memory:
+          mcnt = *p++;
+         printf ("/stop_memory/%d/%d", mcnt, *p++);
+          break;
+
+       case duplicate:
+         printf ("/duplicate/%d", *p++);
+         break;
+
+       case anychar:
+         printf ("/anychar");
+         break;
+
+       case charset:
+        case charset_not:
+          {
+            register int c, last = -100;
+           register int in_range = 0;
+
+           printf ("/charset [%s",
+                   (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+            assert (p + *p < pend);
+
+            for (c = 0; c < 256; c++)
+             if (c / 8 < *p
+                 && (p[1 + (c/8)] & (1 << (c % 8))))
+               {
+                 /* Are we starting a range?  */
+                 if (last + 1 == c && ! in_range)
+                   {
+                     putchar ('-');
+                     in_range = 1;
+                   }
+                 /* Have we broken a range?  */
+                 else if (last + 1 != c && in_range)
+              {
+                     putchar (last);
+                     in_range = 0;
+                   }
+
+                 if (! in_range)
+                   putchar (c);
+
+                 last = c;
+              }
+
+           if (in_range)
+             putchar (last);
+
+           putchar (']');
+
+           p += 1 + *p;
+         }
+         break;
+
+       case begline:
+         printf ("/begline");
+          break;
+
+       case endline:
+          printf ("/endline");
+          break;
+
+       case on_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+         printf ("/on_failure_jump to %d", p + mcnt - start);
+          break;
+
+       case on_failure_keep_string_jump:
+          extract_number_and_incr (&mcnt, &p);
+         printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+          break;
+
+       case dummy_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+         printf ("/dummy_failure_jump to %d", p + mcnt - start);
+          break;
+
+       case push_dummy_failure:
+          printf ("/push_dummy_failure");
+          break;
+
+        case maybe_pop_jump:
+          extract_number_and_incr (&mcnt, &p);
+         printf ("/maybe_pop_jump to %d", p + mcnt - start);
+         break;
+
+        case pop_failure_jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/pop_failure_jump to %d", p + mcnt - start);
+         break;
+
+        case jump_past_alt:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/jump_past_alt to %d", p + mcnt - start);
+         break;
+
+        case jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/jump to %d", p + mcnt - start);
+         break;
+
+        case succeed_n:
+          extract_number_and_incr (&mcnt, &p);
+         p1 = p + mcnt;
+          extract_number_and_incr (&mcnt2, &p);
+         printf ("/succeed_n to %d, %d times", p1 - start, mcnt2);
+          break;
+
+        case jump_n:
+          extract_number_and_incr (&mcnt, &p);
+         p1 = p + mcnt;
+          extract_number_and_incr (&mcnt2, &p);
+         printf ("/jump_n to %d, %d times", p1 - start, mcnt2);
+          break;
+
+        case set_number_at:
+          extract_number_and_incr (&mcnt, &p);
+         p1 = p + mcnt;
+          extract_number_and_incr (&mcnt2, &p);
+         printf ("/set_number_at location %d to %d", p1 - start, mcnt2);
+          break;
+
+        case wordbound:
+         printf ("/wordbound");
+         break;
+
+       case notwordbound:
+         printf ("/notwordbound");
+          break;
+
+       case wordbeg:
+         printf ("/wordbeg");
+         break;
+
+       case wordend:
+         printf ("/wordend");
+
+# ifdef emacs
+       case before_dot:
+         printf ("/before_dot");
+          break;
+
+       case at_dot:
+         printf ("/at_dot");
+          break;
+
+       case after_dot:
+         printf ("/after_dot");
+          break;
+
+       case syntaxspec:
+          printf ("/syntaxspec");
+         mcnt = *p++;
+         printf ("/%d", mcnt);
+          break;
+
+       case notsyntaxspec:
+          printf ("/notsyntaxspec");
+         mcnt = *p++;
+         printf ("/%d", mcnt);
+         break;
+# endif /* emacs */
+
+       case wordchar:
+         printf ("/wordchar");
+          break;
+
+       case notwordchar:
+         printf ("/notwordchar");
+          break;
+
+       case begbuf:
+         printf ("/begbuf");
+          break;
+
+       case endbuf:
+         printf ("/endbuf");
+          break;
+
+        default:
+          printf ("?%d", *(p-1));
+       }
+
+      putchar ('\n');
+    }
+
+  printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+    struct re_pattern_buffer *bufp;
+{
+  unsigned char *buffer = bufp->buffer;
+
+  print_partial_compiled_pattern (buffer, buffer + bufp->used);
+  printf ("%ld bytes used/%ld bytes allocated.\n",
+         bufp->used, bufp->allocated);
+
+  if (bufp->fastmap_accurate && bufp->fastmap)
+    {
+      printf ("fastmap: ");
+      print_fastmap (bufp->fastmap);
+    }
+
+  printf ("re_nsub: %d\t", bufp->re_nsub);
+  printf ("regs_alloc: %d\t", bufp->regs_allocated);
+  printf ("can_be_null: %d\t", bufp->can_be_null);
+  printf ("newline_anchor: %d\n", bufp->newline_anchor);
+  printf ("no_sub: %d\t", bufp->no_sub);
+  printf ("not_bol: %d\t", bufp->not_bol);
+  printf ("not_eol: %d\t", bufp->not_eol);
+  printf ("syntax: %lx\n", bufp->syntax);
+  /* Perhaps we should print the translate table?  */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+    const char *where;
+    const char *string1;
+    const char *string2;
+    int size1;
+    int size2;
+{
+  int this_char;
+
+  if (where == NULL)
+    printf ("(null)");
+  else
+    {
+      if (FIRST_STRING_P (where))
+        {
+          for (this_char = where - string1; this_char < size1; this_char++)
+            putchar (string1[this_char]);
+
+          where = string2;
+        }
+
+      for (this_char = where - string2; this_char < size2; this_char++)
+        putchar (string2[this_char]);
+    }
+}
+
+void
+printchar (c)
+     int c;
+{
+  putc (c, stderr);
+}
+
+#else /* not DEBUG */
+
+# undef assert
+# define assert(e)
+
+# define DEBUG_STATEMENT(e)
+# define DEBUG_PRINT1(x)
+# define DEBUG_PRINT2(x1, x2)
+# define DEBUG_PRINT3(x1, x2, x3)
+# define DEBUG_PRINT4(x1, x2, x3, x4)
+# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+\f
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+/* This has no initializer because initialized variables in Emacs
+   become read-only after dumping.  */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+{
+  reg_syntax_t ret = re_syntax_options;
+
+  re_syntax_options = syntax;
+#ifdef DEBUG
+  if (syntax & RE_DEBUG)
+    debug = 1;
+  else if (debug) /* was on but now is not */
+    debug = 0;
+#endif /* DEBUG */
+  return ret;
+}
+#ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+#endif
+\f
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.
+   POSIX doesn't require that we do anything for REG_NOERROR,
+   but why not be nice?  */
+
+static const char re_error_msgid[] =
+  {
+#define REG_NOERROR_IDX        0
+    gettext_noop ("Success")   /* REG_NOERROR */
+    "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+    gettext_noop ("No match")  /* REG_NOMATCH */
+    "\0"
+#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+    gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+    "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+    gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */
+    "\0"
+#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+    gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+    "\0"
+#define REG_EESCAPE_IDX        (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+    gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+    "\0"
+#define REG_ESUBREG_IDX        (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+    gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+    "\0"
+#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+    gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+    "\0"
+#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+    gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+    "\0"
+#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+    gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+    "\0"
+#define REG_BADBR_IDX  (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+    gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+    "\0"
+#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+    gettext_noop ("Invalid range end") /* REG_ERANGE */
+    "\0"
+#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+    gettext_noop ("Memory exhausted") /* REG_ESPACE */
+    "\0"
+#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+    gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+    "\0"
+#define REG_EEND_IDX   (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+    gettext_noop ("Premature end of regular expression") /* REG_EEND */
+    "\0"
+#define REG_ESIZE_IDX  (REG_EEND_IDX + sizeof "Premature end of regular expression")
+    gettext_noop ("Regular expression too big") /* REG_ESIZE */
+    "\0"
+#define REG_ERPAREN_IDX        (REG_ESIZE_IDX + sizeof "Regular expression too big")
+    gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */
+  };
+
+static const size_t re_error_msgid_idx[] =
+  {
+    REG_NOERROR_IDX,
+    REG_NOMATCH_IDX,
+    REG_BADPAT_IDX,
+    REG_ECOLLATE_IDX,
+    REG_ECTYPE_IDX,
+    REG_EESCAPE_IDX,
+    REG_ESUBREG_IDX,
+    REG_EBRACK_IDX,
+    REG_EPAREN_IDX,
+    REG_EBRACE_IDX,
+    REG_BADBR_IDX,
+    REG_ERANGE_IDX,
+    REG_ESPACE_IDX,
+    REG_BADRPT_IDX,
+    REG_EEND_IDX,
+    REG_ESIZE_IDX,
+    REG_ERPAREN_IDX
+  };
+\f
+/* Avoiding alloca during matching, to placate r_alloc.  */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+   searching and matching functions should not call alloca.  On some
+   systems, alloca is implemented in terms of malloc, and if we're
+   using the relocating allocator routines, then malloc could cause a
+   relocation, which might (if the strings being searched are in the
+   ralloc heap) shift the data out from underneath the regexp
+   routines.
+
+   Here's another reason to avoid allocation: Emacs
+   processes input from X in a signal handler; processing X input may
+   call malloc; if input arrives while a matching routine is calling
+   malloc, then we're scrod.  But Emacs can't just block input while
+   calling matching routines; then we don't notice interrupts when
+   they come in.  So, Emacs blocks input around all regexp calls
+   except the matching calls, which it leaves unprotected, in the
+   faith that they will not malloc.  */
+
+/* Normally, this is fine.  */
+#define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+   what config.h may say.  So don't take precautions for it.  */
+#ifdef __GNUC__
+# undef C_ALLOCA
+#endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+   and (2) it's not safe for them to use malloc.
+   Note that if REL_ALLOC is defined, matching would not use malloc for the
+   failure stack, but we would still use it for the register vectors;
+   so REL_ALLOC should not affect this.  */
+#if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs
+# undef MATCH_MAY_ALLOCATE
+#endif
+
+\f
+/* Failure stack declarations and macros; both re_compile_fastmap and
+   re_match_2 use a failure stack.  These have to be macros because of
+   REGEX_ALLOCATE_STACK.  */
+
+
+/* Number of failure points for which to initially allocate space
+   when matching.  If this number is exceeded, we allocate more
+   space, so it is not a hard limit.  */
+#ifndef INIT_FAILURE_ALLOC
+# define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack.  Would be
+   exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
+   This is a variable only so users of regex can assign to it; we never
+   change it ourselves.  */
+
+#ifdef INT_IS_16BIT
+
+# if defined MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+   whose default stack limit is 2mb.  */
+long int re_max_failures = 4000;
+# else
+long int re_max_failures = 2000;
+# endif
+
+union fail_stack_elt
+{
+  unsigned char *pointer;
+  long int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned long int size;
+  unsigned long int avail;             /* Offset of next open position.  */
+} fail_stack_type;
+
+#else /* not INT_IS_16BIT */
+
+# if defined MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+   whose default stack limit is 2mb.  */
+int re_max_failures = 20000;
+# else
+int re_max_failures = 2000;
+# endif
+
+union fail_stack_elt
+{
+  unsigned char *pointer;
+  int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;                      /* Offset of next open position.  */
+} fail_stack_type;
+
+#endif /* INT_IS_16BIT */
+
+#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
+
+
+/* Define macros to initialize and free the failure stack.
+   Do `return -2' if the alloc fails.  */
+
+#ifdef MATCH_MAY_ALLOCATE
+# define INIT_FAIL_STACK()                                             \
+  do {                                                                 \
+    fail_stack.stack = (fail_stack_elt_t *)                            \
+      REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+                                                                       \
+    if (fail_stack.stack == NULL)                                      \
+      return -2;                                                       \
+                                                                       \
+    fail_stack.size = INIT_FAILURE_ALLOC;                              \
+    fail_stack.avail = 0;                                              \
+  } while (0)
+
+# define RESET_FAIL_STACK()  REGEX_FREE_STACK (fail_stack.stack)
+#else
+# define INIT_FAIL_STACK()                                             \
+  do {                                                                 \
+    fail_stack.avail = 0;                                              \
+  } while (0)
+
+# define RESET_FAIL_STACK()
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+   Return 1 if succeeds, and 0 if either ran out of memory
+   allocating space for it or it was already too large.
+
+   REGEX_REALLOCATE_STACK requires `destination' be declared.   */
+
+#define DOUBLE_FAIL_STACK(fail_stack)                                  \
+  ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS)        \
+   ? 0                                                                 \
+   : ((fail_stack).stack = (fail_stack_elt_t *)                                \
+        REGEX_REALLOCATE_STACK ((fail_stack).stack,                    \
+          (fail_stack).size * sizeof (fail_stack_elt_t),               \
+          ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),       \
+                                                                       \
+      (fail_stack).stack == NULL                                       \
+      ? 0                                                              \
+      : ((fail_stack).size <<= 1,                                      \
+         1)))
+
+
+/* Push pointer POINTER on FAIL_STACK.
+   Return 1 if was able to do so and 0 if ran out of memory allocating
+   space to do so.  */
+#define PUSH_PATTERN_OP(POINTER, FAIL_STACK)                           \
+  ((FAIL_STACK_FULL ()                                                 \
+    && !DOUBLE_FAIL_STACK (FAIL_STACK))                                        \
+   ? 0                                                                 \
+   : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER,      \
+      1))
+
+/* Push a pointer value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_POINTER(item)                                     \
+  fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_INT(item)                                 \
+  fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_ELT(item)                                 \
+  fail_stack.stack[fail_stack.avail++] =  (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+   All assume that `fail_stack' is nonempty.  */
+#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging.  */
+#ifdef DEBUG
+# define DEBUG_PUSH PUSH_FAILURE_INT
+# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+#else
+# define DEBUG_PUSH(item)
+# define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+   if we ever fail back to it.
+
+   Requires variables fail_stack, regstart, regend, reg_info, and
+   num_regs_pushed be declared.  DOUBLE_FAIL_STACK requires `destination'
+   be declared.
+
+   Does `return FAILURE_CODE' if runs out of memory.  */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)  \
+  do {                                                                 \
+    char *destination;                                                 \
+    /* Must be int, so when we don't save any registers, the arithmetic        \
+       of 0 + -1 isn't done as unsigned.  */                           \
+    /* Can't be int, since there is not a shred of a guarantee that int        \
+       is wide enough to hold a value of something to which pointer can        \
+       be assigned */                                                  \
+    active_reg_t this_reg;                                             \
+                                                                       \
+    DEBUG_STATEMENT (failure_id++);                                    \
+    DEBUG_STATEMENT (nfailure_points_pushed++);                                \
+    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);          \
+    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
+    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
+                                                                       \
+    DEBUG_PRINT2 ("  slots needed: %ld\n", NUM_FAILURE_ITEMS);         \
+    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);      \
+                                                                       \
+    /* Ensure we have enough space allocated for what we will push.  */        \
+    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)                  \
+      {                                                                        \
+        if (!DOUBLE_FAIL_STACK (fail_stack))                           \
+          return failure_code;                                         \
+                                                                       \
+        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",             \
+                      (fail_stack).size);                              \
+        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+      }                                                                        \
+                                                                       \
+    /* Push the info, starting with the registers.  */                 \
+    DEBUG_PRINT1 ("\n");                                               \
+                                                                       \
+    if (1)                                                             \
+      for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+          this_reg++)                                                  \
+       {                                                               \
+         DEBUG_PRINT2 ("  Pushing reg: %lu\n", this_reg);              \
+         DEBUG_STATEMENT (num_regs_pushed++);                          \
+                                                                       \
+         DEBUG_PRINT2 ("    start: %p\n", regstart[this_reg]);         \
+         PUSH_FAILURE_POINTER (regstart[this_reg]);                    \
+                                                                       \
+         DEBUG_PRINT2 ("    end: %p\n", regend[this_reg]);             \
+         PUSH_FAILURE_POINTER (regend[this_reg]);                      \
+                                                                       \
+         DEBUG_PRINT2 ("    info: %p\n      ",                         \
+                       reg_info[this_reg].word.pointer);               \
+         DEBUG_PRINT2 (" match_null=%d",                               \
+                       REG_MATCH_NULL_STRING_P (reg_info[this_reg]));  \
+         DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));  \
+         DEBUG_PRINT2 (" matched_something=%d",                        \
+                       MATCHED_SOMETHING (reg_info[this_reg]));        \
+         DEBUG_PRINT2 (" ever_matched=%d",                             \
+                       EVER_MATCHED_SOMETHING (reg_info[this_reg]));   \
+         DEBUG_PRINT1 ("\n");                                          \
+         PUSH_FAILURE_ELT (reg_info[this_reg].word);                   \
+       }                                                               \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing  low active reg: %ld\n", lowest_active_reg);\
+    PUSH_FAILURE_INT (lowest_active_reg);                              \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing high active reg: %ld\n", highest_active_reg);\
+    PUSH_FAILURE_INT (highest_active_reg);                             \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing pattern %p:\n", pattern_place);           \
+    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);          \
+    PUSH_FAILURE_POINTER (pattern_place);                              \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing string %p: `", string_place);             \
+    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
+                                size2);                                \
+    DEBUG_PRINT1 ("'\n");                                              \
+    PUSH_FAILURE_POINTER (string_place);                               \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);           \
+    DEBUG_PUSH (failure_id);                                           \
+  } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+   for each register.  */
+#define NUM_REG_ITEMS  3
+
+/* Individual items aside from the registers.  */
+#ifdef DEBUG
+# define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
+#else
+# define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack.  */
+/* We used to use (num_regs - 1), which is the number of registers
+   this regexp will save; but that was changed to 5
+   to avoid stack overflow for a regexp with lots of parens.  */
+#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items.  */
+#define NUM_FAILURE_ITEMS                              \
+  (((0                                                 \
+     ? 0 : highest_active_reg - lowest_active_reg + 1) \
+    * NUM_REG_ITEMS)                                   \
+   + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it.  */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+   We restore into the parameters, all of which should be lvalues:
+     STR -- the saved data position.
+     PAT -- the saved pattern position.
+     LOW_REG, HIGH_REG -- the highest and lowest active registers.
+     REGSTART, REGEND -- arrays of string positions.
+     REG_INFO -- array of information about each subexpression.
+
+   Also assumes the variables `fail_stack' and (if debugging), `bufp',
+   `pend', `string1', `size1', `string2', and `size2'.  */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{                                                                      \
+  DEBUG_STATEMENT (unsigned failure_id;)                               \
+  active_reg_t this_reg;                                               \
+  const unsigned char *string_temp;                                    \
+                                                                       \
+  assert (!FAIL_STACK_EMPTY ());                                       \
+                                                                       \
+  /* Remove failure points and point to how many regs pushed.  */      \
+  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");                               \
+  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);   \
+  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);    \
+                                                                       \
+  assert (fail_stack.avail >= NUM_NONREG_ITEMS);                       \
+                                                                       \
+  DEBUG_POP (&failure_id);                                             \
+  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);             \
+                                                                       \
+  /* If the saved string location is NULL, it came from an             \
+     on_failure_keep_string_jump opcode, and we want to throw away the \
+     saved NULL, thus retaining our current position in the string.  */        \
+  string_temp = POP_FAILURE_POINTER ();                                        \
+  if (string_temp != NULL)                                             \
+    str = (const char *) string_temp;                                  \
+                                                                       \
+  DEBUG_PRINT2 ("  Popping string %p: `", str);                                \
+  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);     \
+  DEBUG_PRINT1 ("'\n");                                                        \
+                                                                       \
+  pat = (unsigned char *) POP_FAILURE_POINTER ();                      \
+  DEBUG_PRINT2 ("  Popping pattern %p:\n", pat);                       \
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);                      \
+                                                                       \
+  /* Restore register info.  */                                                \
+  high_reg = (active_reg_t) POP_FAILURE_INT ();                                \
+  DEBUG_PRINT2 ("  Popping high active reg: %ld\n", high_reg);         \
+                                                                       \
+  low_reg = (active_reg_t) POP_FAILURE_INT ();                         \
+  DEBUG_PRINT2 ("  Popping  low active reg: %ld\n", low_reg);          \
+                                                                       \
+  if (1)                                                               \
+    for (this_reg = high_reg; this_reg >= low_reg; this_reg--)         \
+      {                                                                        \
+       DEBUG_PRINT2 ("    Popping reg: %ld\n", this_reg);              \
+                                                                       \
+       reg_info[this_reg].word = POP_FAILURE_ELT ();                   \
+       DEBUG_PRINT2 ("      info: %p\n",                               \
+                     reg_info[this_reg].word.pointer);                 \
+                                                                       \
+       regend[this_reg] = (const char *) POP_FAILURE_POINTER ();       \
+       DEBUG_PRINT2 ("      end: %p\n", regend[this_reg]);             \
+                                                                       \
+       regstart[this_reg] = (const char *) POP_FAILURE_POINTER ();     \
+       DEBUG_PRINT2 ("      start: %p\n", regstart[this_reg]);         \
+      }                                                                        \
+  else                                                                 \
+    {                                                                  \
+      for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
+       {                                                               \
+         reg_info[this_reg].word.integer = 0;                          \
+         regend[this_reg] = 0;                                         \
+         regstart[this_reg] = 0;                                       \
+       }                                                               \
+      highest_active_reg = high_reg;                                   \
+    }                                                                  \
+                                                                       \
+  set_regs_matched_done = 0;                                           \
+  DEBUG_STATEMENT (nfailure_points_popped++);                          \
+} /* POP_FAILURE_POINT */
+
+
+\f
+/* Structure for per-register (a.k.a. per-group) information.
+   Other register information, such as the
+   starting and ending positions (which are addresses), and the list of
+   inner groups (which is a bits list) are maintained in separate
+   variables.
+
+   We are making a (strictly speaking) nonportable assumption here: that
+   the compiler will pack our bit fields into something that fits into
+   the type of `word', i.e., is something that fits into one item on the
+   failure stack.  */
+
+
+/* Declarations and macros for re_match_2.  */
+
+typedef union
+{
+  fail_stack_elt_t word;
+  struct
+  {
+      /* This field is one if this group can match the empty string,
+         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
+#define MATCH_NULL_UNSET_VALUE 3
+    unsigned match_null_string_p : 2;
+    unsigned is_active : 1;
+    unsigned matched_something : 1;
+    unsigned ever_matched_something : 1;
+  } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R)  ((R).bits.is_active)
+#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+   for the subexpressions which we are currently inside.  Also records
+   that those subexprs have matched.  */
+#define SET_REGS_MATCHED()                                             \
+  do                                                                   \
+    {                                                                  \
+      if (!set_regs_matched_done)                                      \
+       {                                                               \
+         active_reg_t r;                                               \
+         set_regs_matched_done = 1;                                    \
+         for (r = lowest_active_reg; r <= highest_active_reg; r++)     \
+           {                                                           \
+             MATCHED_SOMETHING (reg_info[r])                           \
+               = EVER_MATCHED_SOMETHING (reg_info[r])                  \
+               = 1;                                                    \
+           }                                                           \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+/* Registers are set to a sentinel when they haven't yet matched.  */
+static char reg_unset_dummy;
+#define REG_UNSET_VALUE (&reg_unset_dummy)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+\f
+/* Subroutine declarations and macros for regex_compile.  */
+
+static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size,
+                                             reg_syntax_t syntax,
+                                             struct re_pattern_buffer *bufp));
+static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg));
+static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc,
+                                int arg1, int arg2));
+static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc,
+                                 int arg, unsigned char *end));
+static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc,
+                                 int arg1, int arg2, unsigned char *end));
+static boolean at_begline_loc_p _RE_ARGS ((const char *pattern, const char *p,
+                                          reg_syntax_t syntax));
+static boolean at_endline_loc_p _RE_ARGS ((const char *p, const char *pend,
+                                          reg_syntax_t syntax));
+static reg_errcode_t compile_range _RE_ARGS ((const char **p_ptr,
+                                             const char *pend,
+                                             char *translate,
+                                             reg_syntax_t syntax,
+                                             unsigned char *b));
+
+/* Fetch the next character in the uncompiled pattern---translating it
+   if necessary.  Also cast from a signed character in the constant
+   string passed to us by the user to an unsigned char that we can use
+   as an array index (in, e.g., `translate').  */
+#ifndef PATFETCH
+# define PATFETCH(c)                                                   \
+  do {if (p == pend) return REG_EEND;                                  \
+    c = (unsigned char) *p++;                                          \
+    if (translate) c = (unsigned char) translate[c];                   \
+  } while (0)
+#endif
+
+/* Fetch the next character in the uncompiled pattern, with no
+   translation.  */
+#define PATFETCH_RAW(c)                                                        \
+  do {if (p == pend) return REG_EEND;                                  \
+    c = (unsigned char) *p++;                                          \
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D.  We
+   cast the subscript to translate because some data is declared as
+   `char *', to avoid warnings when a string constant is passed.  But
+   when we use a character as a subscript we must make it unsigned.  */
+#ifndef TRANSLATE
+# define TRANSLATE(d) \
+  (translate ? (char) translate[(unsigned char) (d)] : (d))
+#endif
+
+
+/* Macros for outputting the compiled pattern into `buffer'.  */
+
+/* If the buffer isn't allocated when it comes in, use this.  */
+#define INIT_BUF_SIZE  32
+
+/* Make sure we have at least N more bytes of space in buffer.  */
+#define GET_BUFFER_SPACE(n)                                            \
+    while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \
+      EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it.  */
+#define BUF_PUSH(c)                                                    \
+  do {                                                                 \
+    GET_BUFFER_SPACE (1);                                              \
+    *b++ = (unsigned char) (c);                                                \
+  } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
+#define BUF_PUSH_2(c1, c2)                                             \
+  do {                                                                 \
+    GET_BUFFER_SPACE (2);                                              \
+    *b++ = (unsigned char) (c1);                                       \
+    *b++ = (unsigned char) (c2);                                       \
+  } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes.  */
+#define BUF_PUSH_3(c1, c2, c3)                                         \
+  do {                                                                 \
+    GET_BUFFER_SPACE (3);                                              \
+    *b++ = (unsigned char) (c1);                                       \
+    *b++ = (unsigned char) (c2);                                       \
+    *b++ = (unsigned char) (c3);                                       \
+  } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO.  We store a
+   relative address offset by the three bytes the jump itself occupies.  */
+#define STORE_JUMP(op, loc, to) \
+  store_op1 (op, loc, (int) ((to) - (loc) - 3))
+
+/* Likewise, for a two-argument jump.  */
+#define STORE_JUMP2(op, loc, to, arg) \
+  store_op2 (op, loc, (int) ((to) - (loc) - 3), arg)
+
+/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP(op, loc, to) \
+  insert_op1 (op, loc, (int) ((to) - (loc) - 3), b)
+
+/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP2(op, loc, to, arg) \
+  insert_op2 (op, loc, (int) ((to) - (loc) - 3), arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+   into the pattern are two bytes long.  So if 2^16 bytes turns out to
+   be too small, many things would have to change.  */
+/* Any other compiler which, like MSC, has allocation limit below 2^16
+   bytes will have to use approach similar to what was done below for
+   MSC and drop MAX_BUF_SIZE a bit.  Otherwise you may end up
+   reallocating to 0 bytes.  Such thing is not going to work too well.
+   You have been warned!!  */
+#if defined _MSC_VER  && !defined WIN32
+/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
+   The REALLOC define eliminates a flurry of conversion warnings,
+   but is not required. */
+# define MAX_BUF_SIZE  65500L
+# define REALLOC(p,s) realloc ((p), (size_t) (s))
+#else
+# define MAX_BUF_SIZE (1L << 16)
+# define REALLOC(p,s) realloc ((p), (s))
+#endif
+
+/* Extend the buffer by twice its current size via realloc and
+   reset the pointers that pointed into the old block to point to the
+   correct places in the new one.  If extending the buffer results in it
+   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
+#define EXTEND_BUFFER()                                                        \
+  do {                                                                         \
+    unsigned char *old_buffer = bufp->buffer;                          \
+    if (bufp->allocated == MAX_BUF_SIZE)                               \
+      return REG_ESIZE;                                                        \
+    bufp->allocated <<= 1;                                             \
+    if (bufp->allocated > MAX_BUF_SIZE)                                        \
+      bufp->allocated = MAX_BUF_SIZE;                                  \
+    bufp->buffer = (unsigned char *) REALLOC (bufp->buffer, bufp->allocated);\
+    if (bufp->buffer == NULL)                                          \
+      return REG_ESPACE;                                               \
+    /* If the buffer moved, move all the pointers into it.  */         \
+    if (old_buffer != bufp->buffer)                                    \
+      {                                                                        \
+        b = (b - old_buffer) + bufp->buffer;                           \
+        begalt = (begalt - old_buffer) + bufp->buffer;                 \
+        if (fixup_alt_jump)                                            \
+          fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+        if (laststart)                                                 \
+          laststart = (laststart - old_buffer) + bufp->buffer;         \
+        if (pending_exact)                                             \
+          pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
+      }                                                                        \
+  } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+   {start,stop}_memory, the maximum number of groups we can report
+   things about is what fits in that byte.  */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers.  We just
+   ignore the excess.  */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack.  */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
+/* int may be not enough when sizeof(int) == 2.  */
+typedef long pattern_offset_t;
+
+typedef struct
+{
+  pattern_offset_t begalt_offset;
+  pattern_offset_t fixup_alt_jump;
+  pattern_offset_t inner_group_offset;
+  pattern_offset_t laststart_offset;
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;                      /* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / BYTEWIDTH]               \
+   |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num)                                       \
+  { if (p != pend)                                                     \
+     {                                                                 \
+       PATFETCH (c);                                                   \
+       while (ISDIGIT (c))                                             \
+         {                                                             \
+           if (num < 0)                                                        \
+              num = 0;                                                 \
+           num = num * 10 + c - '0';                                   \
+           if (p == pend)                                              \
+              break;                                                   \
+           PATFETCH (c);                                               \
+         }                                                             \
+       }                                                               \
+    }
+
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+/* The GNU C library provides support for user-defined character classes
+   and the functions from ISO C amendement 1.  */
+# ifdef CHARCLASS_NAME_MAX
+#  define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+# else
+/* This shouldn't happen but some implementation might still have this
+   problem.  Use a reasonable default value.  */
+#  define CHAR_CLASS_MAX_LENGTH 256
+# endif
+
+# ifdef _LIBC
+#  define IS_CHAR_CLASS(string) __wctype (string)
+# else
+#  define IS_CHAR_CLASS(string) wctype (string)
+# endif
+#else
+# define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+# define IS_CHAR_CLASS(string)                                         \
+   (STREQ (string, "alpha") || STREQ (string, "upper")                 \
+    || STREQ (string, "lower") || STREQ (string, "digit")              \
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")             \
+    || STREQ (string, "space") || STREQ (string, "print")              \
+    || STREQ (string, "punct") || STREQ (string, "graph")              \
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+#endif
+\f
+#ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+   we make the fail stack and register vectors global.
+   The fail stack, we grow to the maximum size when a regexp
+   is compiled.
+   The register vectors, we adjust in size each time we
+   compile a regexp, according to the number of registers it needs.  */
+
+static fail_stack_type fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+   That is so we can make them bigger as needed,
+   but never make them smaller.  */
+static int regs_allocated_size;
+
+static const char **     regstart, **     regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info;
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+
+/* Make the register vectors big enough for NUM_REGS registers,
+   but don't make them smaller.  */
+
+static
+regex_grow_registers (num_regs)
+     int num_regs;
+{
+  if (num_regs > regs_allocated_size)
+    {
+      RETALLOC_IF (regstart,    num_regs, const char *);
+      RETALLOC_IF (regend,      num_regs, const char *);
+      RETALLOC_IF (old_regstart, num_regs, const char *);
+      RETALLOC_IF (old_regend,  num_regs, const char *);
+      RETALLOC_IF (best_regstart, num_regs, const char *);
+      RETALLOC_IF (best_regend,         num_regs, const char *);
+      RETALLOC_IF (reg_info,    num_regs, register_info_type);
+      RETALLOC_IF (reg_dummy,   num_regs, const char *);
+      RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+
+      regs_allocated_size = num_regs;
+    }
+}
+
+#endif /* not MATCH_MAY_ALLOCATE */
+\f
+static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type
+                                                compile_stack,
+                                                regnum_t regnum));
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is zero;
+     `re_nsub' is the number of subexpressions in PATTERN;
+     `not_bol' and `not_eol' are zero;
+
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+/* Return, freeing storage we allocated.  */
+#define FREE_STACK_RETURN(value)               \
+  return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+     const char *pattern;
+     size_t size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer *bufp;
+{
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+
+  /* A random temporary spot in PATTERN.  */
+  const char *p1;
+
+  /* Points to the end of the buffer, where we should append.  */
+  register unsigned char *b;
+
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  const char *p = pattern;
+  const char *pend = pattern + size;
+
+  /* How to translate the characters in the pattern.  */
+  RE_TRANSLATE_TYPE translate = bufp->translate;
+
+  /* Address of the count-byte of the most recently inserted `exactn'
+     command.  This makes it possible to tell if a new exact-match
+     character can be added to that command or if the character requires
+     a new `exactn' command.  */
+  unsigned char *pending_exact = 0;
+
+  /* Address of start of the most recently finished expression.
+     This tells, e.g., postfix * where to find the start of its
+     operand.  Reset at the beginning of groups and alternatives.  */
+  unsigned char *laststart = 0;
+
+  /* Address of beginning of regexp, or inside of last group.  */
+  unsigned char *begalt;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+     which to go back if the interval is invalid.  */
+  const char *beg_interval;
+
+  /* Address of the place where a forward jump should go to the end of
+     the containing expression.  Each alternative of an `or' -- except the
+     last -- ends with a forward jump of this sort.  */
+  unsigned char *fixup_alt_jump = 0;
+
+  /* Counts open-groups as they are encountered.  Remembered for the
+     matching close-group on the compile stack, so the same register
+     number is put in the stop_memory as the start_memory.  */
+  regnum_t regnum = 0;
+
+#ifdef DEBUG
+  DEBUG_PRINT1 ("\nCompiling pattern: ");
+  if (debug)
+    {
+      unsigned debug_count;
+
+      for (debug_count = 0; debug_count < size; debug_count++)
+        putchar (pattern[debug_count]);
+      putchar ('\n');
+    }
+#endif /* DEBUG */
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+  if (compile_stack.stack == NULL)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  bufp->syntax = syntax;
+  bufp->fastmap_accurate = 0;
+  bufp->not_bol = bufp->not_eol = 0;
+
+  /* Set `used' to zero, so that if we return an error, the pattern
+     printer (for debugging) will think there's no pattern.  We reset it
+     at the end.  */
+  bufp->used = 0;
+
+  /* Always count groups, whether or not bufp->no_sub is set.  */
+  bufp->re_nsub = 0;
+
+#if !defined emacs && !defined SYNTAX_TABLE
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  if (bufp->allocated == 0)
+    {
+      if (bufp->buffer)
+       { /* If zero allocated, but buffer is non-null, try to realloc
+             enough space.  This loses if buffer's address is bogus, but
+             that is the user's responsibility.  */
+          RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+        }
+      else
+        { /* Caller did not allocate a buffer.  Do it for them.  */
+          bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+        }
+      if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+      bufp->allocated = INIT_BUF_SIZE;
+    }
+
+  begalt = b = bufp->buffer;
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || at_begline_loc_p (pattern, p, syntax))
+              BUF_PUSH (begline);
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || at_endline_loc_p (p, pend, syntax))
+               BUF_PUSH (endline);
+             else
+               goto normal_char;
+           }
+           break;
+
+
+       case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (!laststart)
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                FREE_STACK_RETURN (REG_BADRPT);
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* Are we optimizing this jump?  */
+            boolean keep_string_p = false;
+
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!laststart)
+              break;
+
+            /* Now we know whether or not zero matches is allowed
+               and also whether or not two or more matches is allowed.  */
+            if (many_times_ok)
+              { /* More than one repetition is allowed, so put in at the
+                   end a backward relative jump from `b' to before the next
+                   jump we're going to put in below (which jumps from
+                   laststart to after this jump).
+
+                   But if we are at the `*' in the exact sequence `.*\n',
+                   insert an unconditional jump backwards to the .,
+                   instead of the beginning of the loop.  This way we only
+                   push a failure point once, instead of every time
+                   through the loop.  */
+                assert (p - 1 > pattern);
+
+                /* Allocate the space for the jump.  */
+                GET_BUFFER_SPACE (3);
+
+                /* We know we are not at the first character of the pattern,
+                   because laststart was nonzero.  And we've already
+                   incremented `p', by the way, to be the character after
+                   the `*'.  Do we have to do something analogous here
+                   for null bytes, because of RE_DOT_NOT_NULL?  */
+                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+                   && zero_times_ok
+                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+                    && !(syntax & RE_DOT_NEWLINE))
+                  { /* We have .*\n.  */
+                    STORE_JUMP (jump, b, laststart);
+                    keep_string_p = true;
+                  }
+                else
+                  /* Anything else.  */
+                  STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+                /* We've added more stuff to the buffer.  */
+                b += 3;
+              }
+
+            /* On failure, jump from laststart to b + 3, which will be the
+               end of the buffer after this jump is inserted.  */
+            GET_BUFFER_SPACE (3);
+            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+                                       : on_failure_jump,
+                         laststart, b + 3);
+            pending_exact = 0;
+            b += 3;
+
+            if (!zero_times_ok)
+              {
+                /* At least one repetition is required, so insert a
+                   `dummy_failure_jump' before the initial
+                   `on_failure_jump' instruction of the loop. This
+                   effects a skip over that instruction the first time
+                   we hit that loop.  */
+                GET_BUFFER_SPACE (3);
+                INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+                b += 3;
+              }
+            }
+         break;
+
+
+       case '.':
+          laststart = b;
+          BUF_PUSH (anychar);
+          break;
+
+
+        case '[':
+          {
+            boolean had_char_class = false;
+
+            if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+            /* Ensure that we have enough space to push a charset: the
+               opcode, the length count, and the bitset; 34 bytes in all.  */
+           GET_BUFFER_SPACE (34);
+
+            laststart = b;
+
+            /* We test `*p == '^' twice, instead of using an if
+               statement, so we only need one BUF_PUSH.  */
+            BUF_PUSH (*p == '^' ? charset_not : charset);
+            if (*p == '^')
+              p++;
+
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+
+            /* Push the number of bytes in the bitmap.  */
+            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* Clear the whole map.  */
+            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* charset_not matches newline according to a syntax bit.  */
+            if ((re_opcode_t) b[-2] == charset_not
+                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+              SET_LIST_BIT ('\n');
+
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                PATFETCH (c);
+
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    SET_LIST_BIT (c1);
+                    continue;
+                  }
+
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  break;
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  FREE_STACK_RETURN (REG_ERANGE);
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-'
+                    && !(p - 2 >= pattern && p[-2] == '[')
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+
+                   /* Move past the `-'.  */
+                    PATFETCH (c1);
+
+                    ret = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                /* See if we're at the beginning of a possible character
+                   class.  */
+
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                  { /* Leave room for the null.  */
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                    PATFETCH (c);
+                    c1 = 0;
+
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if ((c == ':' && *p == ']') || p == pend)
+                          break;
+                       if (c1 < CHAR_CLASS_MAX_LENGTH)
+                         str[c1++] = c;
+                       else
+                         /* This is in any case an invalid class name.  */
+                         str[0] = '\0';
+                      }
+                    str[c1] = '\0';
+
+                    /* If isn't a word bracketed by `[:' and `:]':
+                       undo the ending character, the letters, and leave
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_upper = STREQ (str, "upper");
+                       wctype_t wt;
+                        int ch;
+
+                       wt = IS_CHAR_CLASS (str);
+                       if (wt == 0)
+                         FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ++ch)
+                         {
+# ifdef _LIBC
+                           if (__iswctype (__btowc (ch), wt))
+                             SET_LIST_BIT (ch);
+# else
+                           if (iswctype (btowc (ch), wt))
+                             SET_LIST_BIT (ch);
+# endif
+
+                           if (translate && (is_upper || is_lower)
+                               && (ISUPPER (ch) || ISLOWER (ch)))
+                             SET_LIST_BIT (ch);
+                         }
+
+                        had_char_class = true;
+#else
+                        int ch;
+                        boolean is_alnum = STREQ (str, "alnum");
+                        boolean is_alpha = STREQ (str, "alpha");
+                        boolean is_blank = STREQ (str, "blank");
+                        boolean is_cntrl = STREQ (str, "cntrl");
+                        boolean is_digit = STREQ (str, "digit");
+                        boolean is_graph = STREQ (str, "graph");
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_print = STREQ (str, "print");
+                        boolean is_punct = STREQ (str, "punct");
+                        boolean is_space = STREQ (str, "space");
+                        boolean is_upper = STREQ (str, "upper");
+                        boolean is_xdigit = STREQ (str, "xdigit");
+
+                        if (!IS_CHAR_CLASS (str))
+                         FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+                          {
+                           /* This was split into 3 if's to
+                              avoid an arbitrary limit in some compiler.  */
+                            if (   (is_alnum  && ISALNUM (ch))
+                                || (is_alpha  && ISALPHA (ch))
+                                || (is_blank  && ISBLANK (ch))
+                                || (is_cntrl  && ISCNTRL (ch)))
+                             SET_LIST_BIT (ch);
+                           if (   (is_digit  && ISDIGIT (ch))
+                                || (is_graph  && ISGRAPH (ch))
+                                || (is_lower  && ISLOWER (ch))
+                                || (is_print  && ISPRINT (ch)))
+                             SET_LIST_BIT (ch);
+                           if (   (is_punct  && ISPUNCT (ch))
+                                || (is_space  && ISSPACE (ch))
+                                || (is_upper  && ISUPPER (ch))
+                                || (is_xdigit && ISXDIGIT (ch)))
+                             SET_LIST_BIT (ch);
+                           if (   translate && (is_upper || is_lower)
+                               && (ISUPPER (ch) || ISLOWER (ch)))
+                             SET_LIST_BIT (ch);
+                          }
+                        had_char_class = true;
+#endif /* libc || wctype.h */
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT (':');
+                        had_char_class = false;
+                      }
+                  }
+                else
+                  {
+                    had_char_class = false;
+                    SET_LIST_BIT (c);
+                  }
+              }
+
+            /* Discard any (non)matching list bytes that are all 0 at the
+               end of the map.  Decrease the map-length byte too.  */
+            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+              b[-1]--;
+            b += b[-1];
+          }
+          break;
+
+
+       case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+       case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+             goto handle_interval;
+           else
+             goto normal_char;
+
+
+        case '\\':
+          if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              bufp->re_nsub++;
+              regnum++;
+
+              if (COMPILE_STACK_FULL)
+                {
+                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                            compile_stack_elt_t);
+                  if (compile_stack.stack == NULL) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+              /* These are the values to restore when we hit end of this
+                 group.  They are all relative offsets, so that if the
+                 whole pattern moves because of realloc, they will still
+                 be valid.  */
+              COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+              COMPILE_STACK_TOP.fixup_alt_jump
+                = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+              COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+              COMPILE_STACK_TOP.regnum = regnum;
+
+              /* We will eventually replace the 0 with the number of
+                 groups inner to this one.  But do not push a
+                 start_memory for groups beyond the last one we can
+                 represent in the compiled pattern.  */
+              if (regnum <= MAX_REGNUM)
+                {
+                  COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+                  BUF_PUSH_3 (start_memory, regnum, 0);
+                }
+
+              compile_stack.avail++;
+
+              fixup_alt_jump = 0;
+              laststart = 0;
+              begalt = b;
+             /* If we've reached MAX_REGNUM groups, then this open
+                won't actually generate any code, so we'll have to
+                clear pending_exact explicitly.  */
+             pending_exact = 0;
+              break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+              if (COMPILE_STACK_EMPTY)
+               {
+                 if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                   goto normal_backslash;
+                 else
+                   FREE_STACK_RETURN (REG_ERPAREN);
+               }
+
+            handle_close:
+              if (fixup_alt_jump)
+                { /* Push a dummy failure point at the end of the
+                     alternative for a possible future
+                     `pop_failure_jump' to pop.  See comments at
+                     `push_dummy_failure' in `re_match_2'.  */
+                  BUF_PUSH (push_dummy_failure);
+
+                  /* We allocated space for this jump when we assigned
+                     to `fixup_alt_jump', in the `handle_alt' case below.  */
+                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+                }
+
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+               {
+                 if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                   goto normal_char;
+                 else
+                   FREE_STACK_RETURN (REG_ERPAREN);
+               }
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+              assert (compile_stack.avail != 0);
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+
+                compile_stack.avail--;
+                begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+                fixup_alt_jump
+                  = COMPILE_STACK_TOP.fixup_alt_jump
+                    ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+                    : 0;
+                laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+               /* If we've reached MAX_REGNUM groups, then this open
+                  won't actually generate any code, so we'll have to
+                  clear pending_exact explicitly.  */
+               pending_exact = 0;
+
+                /* We're at the end of the group, so now we know how many
+                   groups were inside this one.  */
+                if (this_group_regnum <= MAX_REGNUM)
+                  {
+                    unsigned char *inner_group_loc
+                      = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+
+                    *inner_group_loc = regnum - this_group_regnum;
+                    BUF_PUSH_3 (stop_memory, this_group_regnum,
+                                regnum - this_group_regnum);
+                  }
+              }
+              break;
+
+
+            case '|':                                  /* `\|'.  */
+              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+              /* Insert before the previous alternative a jump which
+                 jumps to this alternative if the former fails.  */
+              GET_BUFFER_SPACE (3);
+              INSERT_JUMP (on_failure_jump, begalt, b + 6);
+              pending_exact = 0;
+              b += 3;
+
+              /* The alternative before this one has a jump after it
+                 which gets executed if it gets matched.  Adjust that
+                 jump so it will jump to this alternative's analogous
+                 jump (put in below, which in turn will jump to the next
+                 (if any) alternative's such jump, etc.).  The last such
+                 jump jumps to the correct final destination.  A picture:
+                          _____ _____
+                          |   | |   |
+                          |   v |   v
+                         a | b   | c
+
+                 If we are at `b', then fixup_alt_jump right now points to a
+                 three-byte space after `a'.  We'll put in the jump, set
+                 fixup_alt_jump to right after `b', and leave behind three
+                 bytes which we'll fill in when we get to after `c'.  */
+
+              if (fixup_alt_jump)
+                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+              /* Mark and leave space for a jump after this alternative,
+                 to be filled in later either by next alternative or
+                 when know we're at the end of a series of alternatives.  */
+              fixup_alt_jump = b;
+              GET_BUFFER_SPACE (3);
+              b += 3;
+
+              laststart = 0;
+              begalt = b;
+              break;
+
+
+            case '{':
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval
+                        operator.  */
+                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                  || (p - 2 == pattern  &&  p == pend))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+                beg_interval = p - 1;
+
+                if (p == pend)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_EBRACE);
+                  }
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                    || lower_bound > upper_bound)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                if (!(syntax & RE_NO_BK_BRACES))
+                  {
+                    if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                /* If it's invalid to have no preceding re.  */
+                if (!laststart)
+                  {
+                    if (syntax & RE_CONTEXT_INVALID_OPS)
+                      FREE_STACK_RETURN (REG_BADRPT);
+                    else if (syntax & RE_CONTEXT_INDEP_OPS)
+                      laststart = b;
+                    else
+                      goto unfetch_interval;
+                  }
+
+                /* If the upper bound is zero, don't want to succeed at
+                   all; jump from `laststart' to `b + 3', which will be
+                   the end of the buffer after we insert the jump.  */
+                 if (upper_bound == 0)
+                   {
+                     GET_BUFFER_SPACE (3);
+                     INSERT_JUMP (jump, laststart, b + 3);
+                     b += 3;
+                   }
+
+                 /* Otherwise, we have a nontrivial interval.  When
+                    we're all done, the pattern will look like:
+                      set_number_at <jump count> <upper bound>
+                      set_number_at <succeed_n count> <lower bound>
+                      succeed_n <after jump addr> <succeed_n count>
+                      <body of loop>
+                      jump_n <succeed_n addr> <jump count>
+                    (The upper bound and `jump_n' are omitted if
+                    `upper_bound' is 1, though.)  */
+                 else
+                   { /* If the upper bound is > 1, we need to insert
+                        more at the end of the loop.  */
+                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+                     GET_BUFFER_SPACE (nbytes);
+
+                     /* Initialize lower bound of the `succeed_n', even
+                        though it will be set during matching by its
+                        attendant `set_number_at' (inserted next),
+                        because `re_compile_fastmap' needs to know.
+                        Jump to the `jump_n' we might insert below.  */
+                     INSERT_JUMP2 (succeed_n, laststart,
+                                   b + 5 + (upper_bound > 1) * 5,
+                                   lower_bound);
+                     b += 5;
+
+                     /* Code to initialize the lower bound.  Insert
+                        before the `succeed_n'.  The `5' is the last two
+                        bytes of this `set_number_at', plus 3 bytes of
+                        the following `succeed_n'.  */
+                     insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+                     b += 5;
+
+                     if (upper_bound > 1)
+                       { /* More than one repetition is allowed, so
+                            append a backward jump to the `succeed_n'
+                            that starts this interval.
+
+                            When we've reached this during matching,
+                            we'll have matched the interval once, so
+                            jump back only `upper_bound - 1' times.  */
+                         STORE_JUMP2 (jump_n, b, laststart + 5,
+                                      upper_bound - 1);
+                         b += 5;
+
+                         /* The location we want to set is the second
+                            parameter of the `jump_n'; that is `b-2' as
+                            an absolute address.  `laststart' will be
+                            the `set_number_at' we're about to insert;
+                            `laststart+3' the number to set, the source
+                            for the relative address.  But we are
+                            inserting into the middle of the pattern --
+                            so everything is getting moved up by 5.
+                            Conclusion: (b - 2) - (laststart + 3) + 5,
+                            i.e., b - laststart.
+
+                            We insert this at the beginning of the loop
+                            so that if we fail during matching, we'll
+                            reinitialize the bounds.  */
+                         insert_op2 (set_number_at, laststart, b - laststart,
+                                     upper_bound - 1, b);
+                         b += 5;
+                       }
+                   }
+                pending_exact = 0;
+                beg_interval = NULL;
+              }
+              break;
+
+            unfetch_interval:
+              /* If an invalid interval, match the characters as literals.  */
+               assert (beg_interval);
+               p = beg_interval;
+               beg_interval = NULL;
+
+               /* normal_char and normal_backslash need `c'.  */
+               PATFETCH (c);
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (p > pattern  &&  p[-1] == '\\')
+                     goto normal_backslash;
+                 }
+               goto normal_char;
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+              BUF_PUSH (at_dot);
+              break;
+
+            case 's':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+              break;
+
+            case 'S':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              laststart = b;
+              BUF_PUSH (wordchar);
+              break;
+
+
+            case 'W':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              laststart = b;
+              BUF_PUSH (notwordchar);
+              break;
+
+
+            case '<':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              BUF_PUSH (wordbeg);
+              break;
+
+            case '>':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              BUF_PUSH (wordend);
+              break;
+
+            case 'b':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              BUF_PUSH (wordbound);
+              break;
+
+            case 'B':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              BUF_PUSH (notwordbound);
+              break;
+
+            case '`':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              BUF_PUSH (begbuf);
+              break;
+
+            case '\'':
+             if (syntax & RE_NO_GNU_OPS)
+               goto normal_char;
+              BUF_PUSH (endbuf);
+              break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                FREE_STACK_RETURN (REG_ESUBREG);
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, (regnum_t) c1))
+                goto normal_char;
+
+              laststart = b;
+              BUF_PUSH_2 (duplicate, c1);
+              break;
+
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+       default:
+        /* Expects the character in `c'.  */
+       normal_char:
+             /* If no exactn currently being built.  */
+          if (!pending_exact
+
+              /* If last exactn not at current position.  */
+              || pending_exact + *pending_exact + 1 != b
+
+              /* We have only one byte following the exactn for the count.  */
+             || *pending_exact == (1 << BYTEWIDTH) - 1
+
+              /* If followed by a repetition operator.  */
+              || *p == '*' || *p == '^'
+             || ((syntax & RE_BK_PLUS_QM)
+                 ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+                 : (*p == '+' || *p == '?'))
+             || ((syntax & RE_INTERVALS)
+                  && ((syntax & RE_NO_BK_BRACES)
+                     ? *p == '{'
+                      : (p[0] == '\\' && p[1] == '{'))))
+           {
+             /* Start building a new exactn.  */
+
+              laststart = b;
+
+             BUF_PUSH_2 (exactn, 0);
+             pending_exact = b - 1;
+            }
+
+         BUF_PUSH (c);
+          (*pending_exact)++;
+         break;
+        } /* switch (c) */
+    } /* while p != pend */
+
+
+  /* Through the pattern now.  */
+
+  if (fixup_alt_jump)
+    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+  if (!COMPILE_STACK_EMPTY)
+    FREE_STACK_RETURN (REG_EPAREN);
+
+  /* If we don't want backtracking, force success
+     the first time we reach the end of the compiled pattern.  */
+  if (syntax & RE_NO_POSIX_BACKTRACKING)
+    BUF_PUSH (succeed);
+
+  free (compile_stack.stack);
+
+  /* We have succeeded; set the length of the buffer.  */
+  bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+  if (debug)
+    {
+      DEBUG_PRINT1 ("\nCompiled pattern: \n");
+      print_compiled_pattern (bufp);
+    }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+  /* Initialize the failure stack to the largest possible stack.  This
+     isn't necessary unless we're trying to avoid calling alloca in
+     the search and match routines.  */
+  {
+    int num_regs = bufp->re_nsub + 1;
+
+    /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+       is strictly greater than re_max_failures, the largest possible stack
+       is 2 * re_max_failures failure points.  */
+    if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+      {
+       fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+# ifdef emacs
+       if (! fail_stack.stack)
+         fail_stack.stack
+           = (fail_stack_elt_t *) xmalloc (fail_stack.size
+                                           * sizeof (fail_stack_elt_t));
+       else
+         fail_stack.stack
+           = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+                                            (fail_stack.size
+                                             * sizeof (fail_stack_elt_t)));
+# else /* not emacs */
+       if (! fail_stack.stack)
+         fail_stack.stack
+           = (fail_stack_elt_t *) malloc (fail_stack.size
+                                          * sizeof (fail_stack_elt_t));
+       else
+         fail_stack.stack
+           = (fail_stack_elt_t *) realloc (fail_stack.stack,
+                                           (fail_stack.size
+                                            * sizeof (fail_stack_elt_t)));
+# endif /* not emacs */
+      }
+
+    regex_grow_registers (num_regs);
+  }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+  return REG_NOERROR;
+} /* regex_compile */
+\f
+/* Subroutines for `regex_compile'.  */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG.  */
+
+static void
+store_op1 (op, loc, arg)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg1);
+  STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+   for OP followed by two-byte integer parameter ARG.  */
+
+static void
+insert_op1 (op, loc, arg, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+    unsigned char *end;
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 3;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+    unsigned char *end;
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 5;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+   after an alternative or a begin-subexpression.  We assume there is at
+   least one character before the ^.  */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+    const char *pattern, *p;
+    reg_syntax_t syntax;
+{
+  const char *prev = p - 2;
+  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+  return
+       /* After a subexpression?  */
+       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+       /* After an alternative?  */
+    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+   at least one character after the $, i.e., `P < PEND'.  */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+    const char *p, *pend;
+    reg_syntax_t syntax;
+{
+  const char *next = p;
+  boolean next_backslash = *next == '\\';
+  const char *next_next = p + 1 < pend ? p + 1 : 0;
+
+  return
+       /* Before a subexpression?  */
+       (syntax & RE_NO_BK_PARENS ? *next == ')'
+        : next_backslash && next_next && *next_next == ')')
+       /* Before an alternative?  */
+    || (syntax & RE_NO_BK_VBAR ? *next == '|'
+        : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+   false if it's not.  */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;
+       this_element >= 0;
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+   Then we set the translation of all bits between the starting and
+   ending characters (inclusive) in the compiled pattern B.
+
+   Return an error code.
+
+   We use these short variable names so we can use the same macros as
+   `regex_compile' itself.  */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+    const char **p_ptr, *pend;
+    RE_TRANSLATE_TYPE translate;
+    reg_syntax_t syntax;
+    unsigned char *b;
+{
+  unsigned this_char;
+
+  const char *p = *p_ptr;
+  unsigned int range_start, range_end;
+
+  if (p == pend)
+    return REG_ERANGE;
+
+  /* Even though the pattern is a signed `char *', we need to fetch
+     with unsigned char *'s; if the high bit of the pattern character
+     is set, the range endpoints will be negative if we fetch using a
+     signed char *.
+
+     We also want to fetch the endpoints without translating them; the
+     appropriate translation is done in the bit-setting loop below.  */
+  /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *.  */
+  range_start = ((const unsigned char *) p)[-2];
+  range_end   = ((const unsigned char *) p)[0];
+
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  /* If the start is after the end, the range is empty.  */
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  /* Here we see why `this_char' has to be larger than an `unsigned
+     char' -- the range is inclusive, so if `range_end' == 0xff
+     (assuming 8-bit characters), we would otherwise go into an infinite
+     loop, since all characters <= 0xff.  */
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      SET_LIST_BIT (TRANSLATE (this_char));
+    }
+
+  return REG_NOERROR;
+}
+\f
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
+   characters can start a string that matches the pattern.  This fastmap
+   is used by re_search to skip quickly over impossible starting points.
+
+   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+   area as BUFP->fastmap.
+
+   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+   the pattern buffer.
+
+   Returns 0 if we succeed, -2 if an internal error.   */
+
+int
+re_compile_fastmap (bufp)
+     struct re_pattern_buffer *bufp;
+{
+  int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+  fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+  char *destination;
+#endif
+
+  register char *fastmap = bufp->fastmap;
+  unsigned char *pattern = bufp->buffer;
+  unsigned char *p = pattern;
+  register unsigned char *pend = pattern + bufp->used;
+
+#ifdef REL_ALLOC
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+  /* Assume that each path through the pattern can be null until
+     proven otherwise.  We set this false at the bottom of switch
+     statement, to which we get only if a particular path doesn't
+     match the empty string.  */
+  boolean path_can_be_null = true;
+
+  /* We aren't doing a `succeed_n' to begin with.  */
+  boolean succeed_n_p = false;
+
+  assert (fastmap != NULL && p != NULL);
+
+  INIT_FAIL_STACK ();
+  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  bufp->fastmap_accurate = 1;      /* It will be when we're done.  */
+  bufp->can_be_null = 0;
+
+  while (1)
+    {
+      if (p == pend || *p == succeed)
+       {
+         /* We have reached the (effective) end of pattern.  */
+         if (!FAIL_STACK_EMPTY ())
+           {
+             bufp->can_be_null |= path_can_be_null;
+
+             /* Reset for next path.  */
+             path_can_be_null = true;
+
+             p = fail_stack.stack[--fail_stack.avail].pointer;
+
+             continue;
+           }
+         else
+           break;
+       }
+
+      /* We should never be about to go beyond the end of the pattern.  */
+      assert (p < pend);
+
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+       {
+
+        /* I guess the idea here is to simply not bother with a fastmap
+           if a backreference is used, since it's too hard to figure out
+           the fastmap for the corresponding group.  Setting
+           `can_be_null' stops `re_search_2' from using the fastmap, so
+           that is all we do.  */
+       case duplicate:
+         bufp->can_be_null = 1;
+          goto done;
+
+
+      /* Following are the cases which match a character.  These end
+         with `break'.  */
+
+       case exactn:
+          fastmap[p[1]] = 1;
+         break;
+
+
+        case charset:
+          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+           if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+              fastmap[j] = 1;
+         break;
+
+
+       case charset_not:
+         /* Chars beyond end of map must be allowed.  */
+         for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+            fastmap[j] = 1;
+
+         for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+           if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+              fastmap[j] = 1;
+          break;
+
+
+       case wordchar:
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) == Sword)
+             fastmap[j] = 1;
+         break;
+
+
+       case notwordchar:
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) != Sword)
+             fastmap[j] = 1;
+         break;
+
+
+        case anychar:
+         {
+           int fastmap_newline = fastmap['\n'];
+
+           /* `.' matches anything ...  */
+           for (j = 0; j < (1 << BYTEWIDTH); j++)
+             fastmap[j] = 1;
+
+           /* ... except perhaps newline.  */
+           if (!(bufp->syntax & RE_DOT_NEWLINE))
+             fastmap['\n'] = fastmap_newline;
+
+           /* Return if we have already set `can_be_null'; if we have,
+              then the fastmap is irrelevant.  Something's wrong here.  */
+           else if (bufp->can_be_null)
+             goto done;
+
+           /* Otherwise, have to check alternative paths.  */
+           break;
+         }
+
+#ifdef emacs
+        case syntaxspec:
+         k = *p++;
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) == (enum syntaxcode) k)
+             fastmap[j] = 1;
+         break;
+
+
+       case notsyntaxspec:
+         k = *p++;
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) != (enum syntaxcode) k)
+             fastmap[j] = 1;
+         break;
+
+
+      /* All cases after this match the empty string.  These end with
+         `continue'.  */
+
+
+       case before_dot:
+       case at_dot:
+       case after_dot:
+          continue;
+#endif /* emacs */
+
+
+        case no_op:
+        case begline:
+        case endline:
+       case begbuf:
+       case endbuf:
+       case wordbound:
+       case notwordbound:
+       case wordbeg:
+       case wordend:
+        case push_dummy_failure:
+          continue;
+
+
+       case jump_n:
+        case pop_failure_jump:
+       case maybe_pop_jump:
+       case jump:
+        case jump_past_alt:
+       case dummy_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+         p += j;
+         if (j > 0)
+           continue;
+
+          /* Jump backward implies we just went through the body of a
+             loop and matched nothing.  Opcode jumped to should be
+             `on_failure_jump' or `succeed_n'.  Just treat it like an
+             ordinary jump.  For a * loop, it has pushed its failure
+             point already; if so, discard that as redundant.  */
+          if ((re_opcode_t) *p != on_failure_jump
+             && (re_opcode_t) *p != succeed_n)
+           continue;
+
+          p++;
+          EXTRACT_NUMBER_AND_INCR (j, p);
+          p += j;
+
+          /* If what's on the stack is where we are now, pop it.  */
+          if (!FAIL_STACK_EMPTY ()
+             && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+            fail_stack.avail--;
+
+          continue;
+
+
+        case on_failure_jump:
+        case on_failure_keep_string_jump:
+       handle_on_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+
+          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+             end of the pattern.  We don't want to push such a point,
+             since when we restore it above, entering the switch will
+             increment `p' past the end of the pattern.  We don't need
+             to push such a point since we obviously won't find any more
+             fastmap entries beyond `pend'.  Such a pattern can match
+             the null string, though.  */
+          if (p + j < pend)
+            {
+              if (!PUSH_PATTERN_OP (p + j, fail_stack))
+               {
+                 RESET_FAIL_STACK ();
+                 return -2;
+               }
+            }
+          else
+            bufp->can_be_null = 1;
+
+          if (succeed_n_p)
+            {
+              EXTRACT_NUMBER_AND_INCR (k, p);  /* Skip the n.  */
+              succeed_n_p = false;
+           }
+
+          continue;
+
+
+       case succeed_n:
+          /* Get to the number of times to succeed.  */
+          p += 2;
+
+          /* Increment p past the n for when k != 0.  */
+          EXTRACT_NUMBER_AND_INCR (k, p);
+          if (k == 0)
+           {
+              p -= 4;
+             succeed_n_p = true;  /* Spaghetti code alert.  */
+              goto handle_on_failure_jump;
+            }
+          continue;
+
+
+       case set_number_at:
+          p += 4;
+          continue;
+
+
+       case start_memory:
+        case stop_memory:
+         p += 2;
+         continue;
+
+
+       default:
+          abort (); /* We have listed all the cases.  */
+        } /* switch *p++ */
+
+      /* Getting here means we have found the possible starting
+         characters for one path of the pattern -- and that the empty
+         string does not match.  We need not follow this path further.
+         Instead, look at the next alternative (remembered on the
+         stack), or quit if no more.  The test at the top of the loop
+         does these things.  */
+      path_can_be_null = false;
+      p = pend;
+    } /* while p */
+
+  /* Set `can_be_null' for the last path (also the first path, if the
+     pattern is empty).  */
+  bufp->can_be_null |= path_can_be_null;
+
+ done:
+  RESET_FAIL_STACK ();
+  return 0;
+} /* re_compile_fastmap */
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+\f
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+    struct re_pattern_buffer *bufp;
+    struct re_registers *regs;
+    unsigned num_regs;
+    regoff_t *starts, *ends;
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t *) 0;
+    }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+\f
+/* Searching routines.  */
+
+/* Like re_search_2, below, but only one string is specified, and
+   doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, startpos, range;
+     struct re_registers *regs;
+{
+  return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+                     regs, size);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+   virtual concatenation of STRING1 and STRING2, starting first at index
+   STARTPOS, then at STARTPOS + 1, and so on.
+
+   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+   RANGE is how far to scan while trying to match.  RANGE = 0 means try
+   only at STARTPOS; in general, the last start tried is STARTPOS +
+   RANGE.
+
+   In REGS, return the indices of the virtual concatenation of STRING1
+   and STRING2 that matched the entire BUFP->buffer and its contained
+   subexpressions.
+
+   Do not consider matching one past the index STOP in the virtual
+   concatenation of STRING1 and STRING2.
+
+   We return either the position in the strings at which the match was
+   found, -1 if no match, or -2 if error (such as failure
+   stack overflow).  */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+{
+  int val;
+  register char *fastmap = bufp->fastmap;
+  register RE_TRANSLATE_TYPE translate = bufp->translate;
+  int total_size = size1 + size2;
+  int endpos = startpos + range;
+
+  /* Check for out-of-range STARTPOS.  */
+  if (startpos < 0 || startpos > total_size)
+    return -1;
+
+  /* Fix up RANGE if it might eventually take us outside
+     the virtual concatenation of STRING1 and STRING2.
+     Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE.  */
+  if (endpos < 0)
+    range = 0 - startpos;
+  else if (endpos > total_size)
+    range = total_size - startpos;
+
+  /* If the search isn't to be a backwards one, don't waste time in a
+     search for a pattern that must be anchored.  */
+  if (bufp->used > 0 && range > 0
+      && ((re_opcode_t) bufp->buffer[0] == begbuf
+         /* `begline' is like `begbuf' if it cannot match at newlines.  */
+         || ((re_opcode_t) bufp->buffer[0] == begline
+             && !bufp->newline_anchor)))
+    {
+      if (startpos > 0)
+       return -1;
+      else
+       range = 1;
+    }
+
+#ifdef emacs
+  /* In a forward search for something that starts with \=.
+     don't keep searching past point.  */
+  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
+    {
+      range = PT - startpos;
+      if (range <= 0)
+       return -1;
+    }
+#endif /* emacs */
+
+  /* Update the fastmap now if not correct already.  */
+  if (fastmap && !bufp->fastmap_accurate)
+    if (re_compile_fastmap (bufp) == -2)
+      return -2;
+
+  /* Loop through the string, looking for a place to start matching.  */
+  for (;;)
+    {
+      /* If a fastmap is supplied, skip quickly over characters that
+         cannot be the start of a match.  If the pattern can match the
+         null string, however, we don't need to skip characters; we want
+         the first null string.  */
+      if (fastmap && startpos < total_size && !bufp->can_be_null)
+       {
+         if (range > 0)        /* Searching forwards.  */
+           {
+             register const char *d;
+             register int lim = 0;
+             int irange = range;
+
+              if (startpos < size1 && startpos + range >= size1)
+                lim = range - (size1 - startpos);
+
+             d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+              /* Written out as an if-else to avoid testing `translate'
+                 inside the loop.  */
+             if (translate)
+                while (range > lim
+                       && !fastmap[(unsigned char)
+                                  translate[(unsigned char) *d++]])
+                  range--;
+             else
+                while (range > lim && !fastmap[(unsigned char) *d++])
+                  range--;
+
+             startpos += irange - range;
+           }
+         else                          /* Searching backwards.  */
+           {
+             register char c = (size1 == 0 || startpos >= size1
+                                 ? string2[startpos - size1]
+                                 : string1[startpos]);
+
+             if (!fastmap[(unsigned char) TRANSLATE (c)])
+               goto advance;
+           }
+       }
+
+      /* If can't match the null string, and that's all we have left, fail.  */
+      if (range >= 0 && startpos == total_size && fastmap
+          && !bufp->can_be_null)
+       return -1;
+
+      val = re_match_2_internal (bufp, string1, size1, string2, size2,
+                                startpos, regs, stop);
+#ifndef REGEX_MALLOC
+# ifdef C_ALLOCA
+      alloca (0);
+# endif
+#endif
+
+      if (val >= 0)
+       return startpos;
+
+      if (val == -2)
+       return -2;
+
+    advance:
+      if (!range)
+        break;
+      else if (range > 0)
+        {
+          range--;
+          startpos++;
+        }
+      else
+        {
+          range++;
+          startpos--;
+        }
+    }
+  return -1;
+} /* re_search_2 */
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+\f
+/* This converts PTR, a pointer into one of the search strings `string1'
+   and `string2' into an offset from the beginning of that string.  */
+#define POINTER_TO_OFFSET(ptr)                 \
+  (FIRST_STRING_P (ptr)                                \
+   ? ((regoff_t) ((ptr) - string1))            \
+   : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2.  */
+
+#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
+
+/* Call before fetching a character with *d.  This switches over to
+   string2 if necessary.  */
+#define PREFETCH()                                                     \
+  while (d == dend)                                                    \
+    {                                                                  \
+      /* End of string2 => fail.  */                                   \
+      if (dend == end_match_2)                                                 \
+        goto fail;                                                     \
+      /* End of string1 => advance to string2.  */                     \
+      d = string2;                                                     \
+      dend = end_match_2;                                              \
+    }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+   of `string1' and `string2'.  If only one string, it's `string2'.  */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent.  We have
+   two special cases to check for: if past the end of string1, look at
+   the first character in string2; and if before the beginning of
+   string2, look at the last character in string1.  */
+#define WORDCHAR_P(d)                                                  \
+  (SYNTAX ((d) == end1 ? *string2                                      \
+           : (d) == string2 - 1 ? *(end1 - 1) : *(d))                  \
+   == Sword)
+
+/* Disabled due to a compiler bug -- see comment at case wordbound */
+#if 0
+/* Test if the character before D and the one at D differ with respect
+   to being word-constituent.  */
+#define AT_WORD_BOUNDARY(d)                                            \
+  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)                            \
+   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+#endif
+
+/* Free everything we malloc.  */
+#ifdef MATCH_MAY_ALLOCATE
+# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
+# define FREE_VARIABLES()                                              \
+  do {                                                                 \
+    REGEX_FREE_STACK (fail_stack.stack);                               \
+    FREE_VAR (regstart);                                               \
+    FREE_VAR (regend);                                                 \
+    FREE_VAR (old_regstart);                                           \
+    FREE_VAR (old_regend);                                             \
+    FREE_VAR (best_regstart);                                          \
+    FREE_VAR (best_regend);                                            \
+    FREE_VAR (reg_info);                                               \
+    FREE_VAR (reg_dummy);                                              \
+    FREE_VAR (reg_info_dummy);                                         \
+  } while (0)
+#else
+# define FREE_VARIABLES() ((void)0) /* Do nothing!  But inhibit gcc warning. */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints.  They must not be valid
+   register values; since we have a limit of 255 registers (because
+   we use only one byte in the pattern for the register number), we can
+   use numbers larger than 255.  They must differ by 1, because of
+   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
+   be larger than the value for the highest register, so we do not try
+   to actually save any registers when none are active.  */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+\f
+/* Matching routines.  */
+
+#ifndef emacs   /* Emacs never uses this.  */
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+int
+re_match (bufp, string, size, pos, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, pos;
+     struct re_registers *regs;
+{
+  int result = re_match_2_internal (bufp, NULL, 0, string, size,
+                                   pos, regs, size);
+# ifndef REGEX_MALLOC
+#  ifdef C_ALLOCA
+  alloca (0);
+#  endif
+# endif
+  return result;
+}
+# ifdef _LIBC
+weak_alias (__re_match, re_match)
+# endif
+#endif /* not emacs */
+
+static boolean group_match_null_string_p _RE_ARGS ((unsigned char **p,
+                                                   unsigned char *end,
+                                               register_info_type *reg_info));
+static boolean alt_match_null_string_p _RE_ARGS ((unsigned char *p,
+                                                 unsigned char *end,
+                                               register_info_type *reg_info));
+static boolean common_op_match_null_string_p _RE_ARGS ((unsigned char **p,
+                                                       unsigned char *end,
+                                               register_info_type *reg_info));
+static int bcmp_translate _RE_ARGS ((const char *s1, const char *s2,
+                                    int len, char *translate));
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   and SIZE2, respectively).  We start matching at POS, and stop
+   matching at STOP.
+
+   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+   store offsets for the substring each group matched in REGS.  See the
+   documentation for exactly how many groups we fill.
+
+   We return -1 if no match, -2 if an internal error (such as the
+   failure stack overflowing).  Otherwise, we return the length of the
+   matched substring.  */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+                                   pos, regs, stop);
+#ifndef REGEX_MALLOC
+# ifdef C_ALLOCA
+  alloca (0);
+# endif
+#endif
+  return result;
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+/* This is a separate function so that we can force an alloca cleanup
+   afterwards.  */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  /* General temporaries.  */
+  int mcnt;
+  unsigned char *p1;
+
+  /* Just past the end of the corresponding string.  */
+  const char *end1, *end2;
+
+  /* Pointers into string1 and string2, just past the last characters in
+     each to consider matching.  */
+  const char *end_match_1, *end_match_2;
+
+  /* Where we are in the data, and the end of the current string.  */
+  const char *d, *dend;
+
+  /* Where we are in the pattern, and the end of the pattern.  */
+  unsigned char *p = bufp->buffer;
+  register unsigned char *pend = p + bufp->used;
+
+  /* Mark the opcode just after a start_memory, so we can test for an
+     empty subpattern when we get to the stop_memory.  */
+  unsigned char *just_past_start_mem = 0;
+
+  /* We use this to map every character in the string.  */
+  RE_TRANSLATE_TYPE translate = bufp->translate;
+
+  /* Failure point stack.  Each place that can handle a failure further
+     down the line pushes a failure point on this stack.  It consists of
+     restart, regend, and reg_info for all registers corresponding to
+     the subexpressions we're currently inside, plus the number of such
+     registers, and, finally, two char *'s.  The first char * is where
+     to resume scanning the pattern; the second one is where to resume
+     scanning the strings.  If the latter is zero, the failure point is
+     a ``dummy''; if a failure happens and the failure point is a dummy,
+     it gets discarded and the next next one is tried.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+  static unsigned failure_id;
+  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+#ifdef REL_ALLOC
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+  /* We fill all the registers internally, independent of what we
+     return, for use in backreferences.  The number here includes
+     an element for register zero.  */
+  size_t num_regs = bufp->re_nsub + 1;
+
+  /* The currently active registers.  */
+  active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+  /* Information on the contents of registers. These are pointers into
+     the input strings; they record just what was matched (on this
+     attempt) by a subexpression part of the pattern, that is, the
+     regnum-th regstart pointer points to where in the pattern we began
+     matching and the regnum-th regend points to right after where we
+     stopped matching the regnum-th subexpression.  (The zeroth register
+     keeps track of what the whole pattern matches.)  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **regstart, **regend;
+#endif
+
+  /* If a group that's operated upon by a repetition operator fails to
+     match anything, then the register for its start will need to be
+     restored because it will have been set to wherever in the string we
+     are when we last see its open-group operator.  Similarly for a
+     register's end.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **old_regstart, **old_regend;
+#endif
+
+  /* The is_active field of reg_info helps us keep track of which (possibly
+     nested) subexpressions we are currently in. The matched_something
+     field of reg_info[reg_num] helps us tell whether or not we have
+     matched any of the pattern so far this time through the reg_num-th
+     subexpression.  These two fields get reset each time through any
+     loop their register is in.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  register_info_type *reg_info;
+#endif
+
+  /* The following record the register info as found in the above
+     variables when we find a match better than any we've seen before.
+     This happens as we backtrack through the failure points, which in
+     turn happens only if we have not yet matched the entire string. */
+  unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **best_regstart, **best_regend;
+#endif
+
+  /* Logically, this is `best_regend[0]'.  But we don't want to have to
+     allocate space for that if we're not allocating space for anything
+     else (see below).  Also, we never need info about register 0 for
+     any of the other register vectors, and it seems rather a kludge to
+     treat `best_regend' differently than the rest.  So we keep track of
+     the end of the best match so far in a separate variable.  We
+     initialize this to NULL so that when we backtrack the first time
+     and need to test it, it's not garbage.  */
+  const char *match_end = NULL;
+
+  /* This helps SET_REGS_MATCHED avoid doing redundant work.  */
+  int set_regs_matched_done = 0;
+
+  /* Used when we pop values we don't care about.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **reg_dummy;
+  register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+  /* Counts the total number of registers pushed.  */
+  unsigned num_regs_pushed = 0;
+#endif
+
+  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+  INIT_FAIL_STACK ();
+
+#ifdef MATCH_MAY_ALLOCATE
+  /* Do not bother to initialize all the register variables if there are
+     no groups in the pattern, as it takes a fair amount of time.  If
+     there are groups, we include space for register 0 (the whole
+     pattern), even though we never use it, since it simplifies the
+     array indexing.  We should fix this.  */
+  if (bufp->re_nsub)
+    {
+      regstart = REGEX_TALLOC (num_regs, const char *);
+      regend = REGEX_TALLOC (num_regs, const char *);
+      old_regstart = REGEX_TALLOC (num_regs, const char *);
+      old_regend = REGEX_TALLOC (num_regs, const char *);
+      best_regstart = REGEX_TALLOC (num_regs, const char *);
+      best_regend = REGEX_TALLOC (num_regs, const char *);
+      reg_info = REGEX_TALLOC (num_regs, register_info_type);
+      reg_dummy = REGEX_TALLOC (num_regs, const char *);
+      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+      if (!(regstart && regend && old_regstart && old_regend && reg_info
+            && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+        {
+          FREE_VARIABLES ();
+          return -2;
+        }
+    }
+  else
+    {
+      /* We must initialize all our variables to NULL, so that
+         `FREE_VARIABLES' doesn't try to free them.  */
+      regstart = regend = old_regstart = old_regend = best_regstart
+        = best_regend = reg_dummy = NULL;
+      reg_info = reg_info_dummy = (register_info_type *) NULL;
+    }
+#endif /* MATCH_MAY_ALLOCATE */
+
+  /* The starting position is bogus.  */
+  if (pos < 0 || pos > size1 + size2)
+    {
+      FREE_VARIABLES ();
+      return -1;
+    }
+
+  /* Initialize subexpression text positions to -1 to mark ones that no
+     start_memory/stop_memory has been seen for. Also initialize the
+     register information struct.  */
+  for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+    {
+      regstart[mcnt] = regend[mcnt]
+        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+      IS_ACTIVE (reg_info[mcnt]) = 0;
+      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+    }
+
+  /* We move `string1' into `string2' if the latter's empty -- but not if
+     `string1' is null.  */
+  if (size2 == 0 && string1 != NULL)
+    {
+      string2 = string1;
+      size2 = size1;
+      string1 = 0;
+      size1 = 0;
+    }
+  end1 = string1 + size1;
+  end2 = string2 + size2;
+
+  /* Compute where to stop matching, within the two strings.  */
+  if (stop <= size1)
+    {
+      end_match_1 = string1 + stop;
+      end_match_2 = string2;
+    }
+  else
+    {
+      end_match_1 = end1;
+      end_match_2 = string2 + stop - size1;
+    }
+
+  /* `p' scans through the pattern as `d' scans through the data.
+     `dend' is the end of the input string that `d' points within.  `d'
+     is advanced into the following input string whenever necessary, but
+     this happens before fetching; therefore, at the beginning of the
+     loop, `d' can be pointing at the end of a string, but it cannot
+     equal `string2'.  */
+  if (size1 > 0 && pos <= size1)
+    {
+      d = string1 + pos;
+      dend = end_match_1;
+    }
+  else
+    {
+      d = string2 + pos - size1;
+      dend = end_match_2;
+    }
+
+  DEBUG_PRINT1 ("The compiled pattern is:\n");
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+  DEBUG_PRINT1 ("The string to match is: `");
+  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+  DEBUG_PRINT1 ("'\n");
+
+  /* This loops over pattern commands.  It exits by returning from the
+     function if the match is complete, or it drops through if the match
+     fails at this starting point in the input data.  */
+  for (;;)
+    {
+#ifdef _LIBC
+      DEBUG_PRINT2 ("\n%p: ", p);
+#else
+      DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+
+      if (p == pend)
+       { /* End of pattern means we might have succeeded.  */
+          DEBUG_PRINT1 ("end of pattern ... ");
+
+         /* If we haven't matched the entire string, and we want the
+             longest match, try backtracking.  */
+          if (d != end_match_2)
+           {
+             /* 1 if this match ends in the same string (string1 or string2)
+                as the best previous match.  */
+             boolean same_str_p = (FIRST_STRING_P (match_end)
+                                   == MATCHING_IN_FIRST_STRING);
+             /* 1 if this match is the best seen so far.  */
+             boolean best_match_p;
+
+             /* AIX compiler got confused when this was combined
+                with the previous declaration.  */
+             if (same_str_p)
+               best_match_p = d > match_end;
+             else
+               best_match_p = !MATCHING_IN_FIRST_STRING;
+
+              DEBUG_PRINT1 ("backtracking.\n");
+
+              if (!FAIL_STACK_EMPTY ())
+                { /* More failure points to try.  */
+
+                  /* If exceeds best match so far, save it.  */
+                  if (!best_regs_set || best_match_p)
+                    {
+                      best_regs_set = true;
+                      match_end = d;
+
+                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+                      for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+                        {
+                          best_regstart[mcnt] = regstart[mcnt];
+                          best_regend[mcnt] = regend[mcnt];
+                        }
+                    }
+                  goto fail;
+                }
+
+              /* If no failure points, don't restore garbage.  And if
+                 last match is real best match, don't restore second
+                 best one. */
+              else if (best_regs_set && !best_match_p)
+                {
+               restore_best_regs:
+                  /* Restore best match.  It may happen that `dend ==
+                     end_match_1' while the restored d is in string2.
+                     For example, the pattern `x.*y.*z' against the
+                     strings `x-' and `y-z-', if the two strings are
+                     not consecutive in memory.  */
+                  DEBUG_PRINT1 ("Restoring best registers.\n");
+
+                  d = match_end;
+                  dend = ((d >= string1 && d <= end1)
+                          ? end_match_1 : end_match_2);
+
+                 for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+                   {
+                     regstart[mcnt] = best_regstart[mcnt];
+                     regend[mcnt] = best_regend[mcnt];
+                   }
+                }
+            } /* d != end_match_2 */
+
+       succeed_label:
+          DEBUG_PRINT1 ("Accepting match.\n");
+
+          /* If caller wants register contents data back, do it.  */
+          if (regs && !bufp->no_sub)
+           {
+              /* Have the register data arrays been allocated?  */
+              if (bufp->regs_allocated == REGS_UNALLOCATED)
+                { /* No.  So allocate them with malloc.  We need one
+                     extra element beyond `num_regs' for the `-1' marker
+                     GNU code uses.  */
+                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+                  regs->start = TALLOC (regs->num_regs, regoff_t);
+                  regs->end = TALLOC (regs->num_regs, regoff_t);
+                  if (regs->start == NULL || regs->end == NULL)
+                   {
+                     FREE_VARIABLES ();
+                     return -2;
+                   }
+                  bufp->regs_allocated = REGS_REALLOCATE;
+                }
+              else if (bufp->regs_allocated == REGS_REALLOCATE)
+                { /* Yes.  If we need more elements than were already
+                     allocated, reallocate them.  If we need fewer, just
+                     leave it alone.  */
+                  if (regs->num_regs < num_regs + 1)
+                    {
+                      regs->num_regs = num_regs + 1;
+                      RETALLOC (regs->start, regs->num_regs, regoff_t);
+                      RETALLOC (regs->end, regs->num_regs, regoff_t);
+                      if (regs->start == NULL || regs->end == NULL)
+                       {
+                         FREE_VARIABLES ();
+                         return -2;
+                       }
+                    }
+                }
+              else
+               {
+                 /* These braces fend off a "empty body in an else-statement"
+                    warning under GCC when assert expands to nothing.  */
+                 assert (bufp->regs_allocated == REGS_FIXED);
+               }
+
+              /* Convert the pointer data in `regstart' and `regend' to
+                 indices.  Register zero has to be set differently,
+                 since we haven't kept track of any info for it.  */
+              if (regs->num_regs > 0)
+                {
+                  regs->start[0] = pos;
+                  regs->end[0] = (MATCHING_IN_FIRST_STRING
+                                 ? ((regoff_t) (d - string1))
+                                 : ((regoff_t) (d - string2 + size1)));
+                }
+
+              /* Go through the first `min (num_regs, regs->num_regs)'
+                 registers, since that is all we initialized.  */
+             for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs);
+                  mcnt++)
+               {
+                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+                    regs->start[mcnt] = regs->end[mcnt] = -1;
+                  else
+                    {
+                     regs->start[mcnt]
+                       = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+                      regs->end[mcnt]
+                       = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+                    }
+               }
+
+              /* If the regs structure we return has more elements than
+                 were in the pattern, set the extra elements to -1.  If
+                 we (re)allocated the registers, this is the case,
+                 because we always allocate enough to have at least one
+                 -1 at the end.  */
+              for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++)
+                regs->start[mcnt] = regs->end[mcnt] = -1;
+           } /* regs && !bufp->no_sub */
+
+          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                        nfailure_points_pushed, nfailure_points_popped,
+                        nfailure_points_pushed - nfailure_points_popped);
+          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+          mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+                           ? string1
+                           : string2 - size1);
+
+          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+          FREE_VARIABLES ();
+          return mcnt;
+        }
+
+      /* Otherwise match next pattern command.  */
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+       {
+        /* Ignore these.  Used to ignore the n of succeed_n's which
+           currently have n == 0.  */
+        case no_op:
+          DEBUG_PRINT1 ("EXECUTING no_op.\n");
+          break;
+
+       case succeed:
+          DEBUG_PRINT1 ("EXECUTING succeed.\n");
+         goto succeed_label;
+
+        /* Match the next n pattern characters exactly.  The following
+           byte in the pattern defines n, and the n bytes after that
+           are the characters to match.  */
+       case exactn:
+         mcnt = *p++;
+          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+          /* This is written out as an if-else so we don't waste time
+             testing `translate' inside the loop.  */
+          if (translate)
+           {
+             do
+               {
+                 PREFETCH ();
+                 if ((unsigned char) translate[(unsigned char) *d++]
+                     != (unsigned char) *p++)
+                    goto fail;
+               }
+             while (--mcnt);
+           }
+         else
+           {
+             do
+               {
+                 PREFETCH ();
+                 if (*d++ != (char) *p++) goto fail;
+               }
+             while (--mcnt);
+           }
+         SET_REGS_MATCHED ();
+          break;
+
+
+        /* Match any character except possibly a newline or a null.  */
+       case anychar:
+          DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+          PREFETCH ();
+
+          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+           goto fail;
+
+          SET_REGS_MATCHED ();
+          DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
+          d++;
+         break;
+
+
+       case charset:
+       case charset_not:
+         {
+           register unsigned char c;
+           boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+           PREFETCH ();
+           c = TRANSLATE (*d); /* The character to match.  */
+
+            /* Cast to `unsigned' instead of `unsigned char' in case the
+               bit list is a full 32 bytes long.  */
+           if (c < (unsigned) (*p * BYTEWIDTH)
+               && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+             not = !not;
+
+           p += 1 + *p;
+
+           if (!not) goto fail;
+
+           SET_REGS_MATCHED ();
+            d++;
+           break;
+         }
+
+
+        /* The beginning of a group is represented by start_memory.
+           The arguments are the register number in the next byte, and the
+           number of groups inner to this one in the next.  The text
+           matched within the group is recorded (in the internal
+           registers data structure) under the register number.  */
+        case start_memory:
+         DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+          /* Find out if this group can match the empty string.  */
+         p1 = p;               /* To send to group_match_null_string_p.  */
+
+          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+            REG_MATCH_NULL_STRING_P (reg_info[*p])
+              = group_match_null_string_p (&p1, pend, reg_info);
+
+          /* Save the position in the string where we were the last time
+             we were at this open-group operator in case the group is
+             operated upon by a repetition operator, e.g., with `(a*)*b'
+             against `ab'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+                             : regstart[*p];
+         DEBUG_PRINT2 ("  old_regstart: %d\n",
+                        POINTER_TO_OFFSET (old_regstart[*p]));
+
+          regstart[*p] = d;
+         DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+          IS_ACTIVE (reg_info[*p]) = 1;
+          MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+         /* Clear this whenever we change the register activity status.  */
+         set_regs_matched_done = 0;
+
+          /* This is the new highest active register.  */
+          highest_active_reg = *p;
+
+          /* If nothing was active before, this is the new lowest active
+             register.  */
+          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+            lowest_active_reg = *p;
+
+          /* Move past the register number and inner group count.  */
+          p += 2;
+         just_past_start_mem = p;
+
+          break;
+
+
+        /* The stop_memory opcode represents the end of a group.  Its
+           arguments are the same as start_memory's: the register
+           number, and the number of inner groups.  */
+       case stop_memory:
+         DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+          /* We need to save the string position the last time we were at
+             this close-group operator in case the group is operated
+             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+             against `aba'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
+                          : regend[*p];
+         DEBUG_PRINT2 ("      old_regend: %d\n",
+                        POINTER_TO_OFFSET (old_regend[*p]));
+
+          regend[*p] = d;
+         DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+          /* This register isn't active anymore.  */
+          IS_ACTIVE (reg_info[*p]) = 0;
+
+         /* Clear this whenever we change the register activity status.  */
+         set_regs_matched_done = 0;
+
+          /* If this was the only register active, nothing is active
+             anymore.  */
+          if (lowest_active_reg == highest_active_reg)
+            {
+              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+            }
+          else
+            { /* We must scan for the new highest active register, since
+                 it isn't necessarily one less than now: consider
+                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
+                 new highest active register is 1.  */
+              unsigned char r = *p - 1;
+              while (r > 0 && !IS_ACTIVE (reg_info[r]))
+                r--;
+
+              /* If we end up at register zero, that means that we saved
+                 the registers as the result of an `on_failure_jump', not
+                 a `start_memory', and we jumped to past the innermost
+                 `stop_memory'.  For example, in ((.)*) we save
+                 registers 1 and 2 as a result of the *, but when we pop
+                 back to the second ), we are at the stop_memory 1.
+                 Thus, nothing is active.  */
+             if (r == 0)
+                {
+                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+                }
+              else
+                highest_active_reg = r;
+            }
+
+          /* If just failed to match something this time around with a
+             group that's operated on by a repetition operator, try to
+             force exit from the ``loop'', and restore the register
+             information for this group that we had before trying this
+             last match.  */
+          if ((!MATCHED_SOMETHING (reg_info[*p])
+               || just_past_start_mem == p - 1)
+             && (p + 2) < pend)
+            {
+              boolean is_a_jump_n = false;
+
+              p1 = p + 2;
+              mcnt = 0;
+              switch ((re_opcode_t) *p1++)
+                {
+                  case jump_n:
+                   is_a_jump_n = true;
+                  case pop_failure_jump:
+                 case maybe_pop_jump:
+                 case jump:
+                 case dummy_failure_jump:
+                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                   if (is_a_jump_n)
+                     p1 += 2;
+                    break;
+
+                  default:
+                    /* do nothing */ ;
+                }
+             p1 += mcnt;
+
+              /* If the next operation is a jump backwards in the pattern
+                to an on_failure_jump right before the start_memory
+                 corresponding to this stop_memory, exit from the loop
+                 by forcing a failure after pushing on the stack the
+                 on_failure_jump's jump in the pattern, and d.  */
+              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+                  && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+               {
+                  /* If this group ever matched anything, then restore
+                     what its registers were before trying this last
+                     failed match, e.g., with `(a*)*b' against `ab' for
+                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
+                     against `aba' for regend[3].
+
+                     Also restore the registers for inner groups for,
+                     e.g., `((a*)(b*))*' against `aba' (register 3 would
+                     otherwise get trashed).  */
+
+                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+                   {
+                     unsigned r;
+
+                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+                     /* Restore this and inner groups' (if any) registers.  */
+                      for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1);
+                          r++)
+                        {
+                          regstart[r] = old_regstart[r];
+
+                          /* xx why this test?  */
+                          if (old_regend[r] >= regstart[r])
+                            regend[r] = old_regend[r];
+                        }
+                    }
+                 p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+                  goto fail;
+                }
+            }
+
+          /* Move past the register number and the inner group count.  */
+          p += 2;
+          break;
+
+
+       /* \<digit> has been turned into a `duplicate' command which is
+           followed by the numeric value of <digit> as the register number.  */
+        case duplicate:
+         {
+           register const char *d2, *dend2;
+           int regno = *p++;   /* Get which register to match against.  */
+           DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+           /* Can't back reference a group which we've never matched.  */
+            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+              goto fail;
+
+            /* Where in input to try to start matching.  */
+            d2 = regstart[regno];
+
+            /* Where to stop matching; if both the place to start and
+               the place to stop matching are in the same string, then
+               set to the place to stop, otherwise, for now have to use
+               the end of the first string.  */
+
+            dend2 = ((FIRST_STRING_P (regstart[regno])
+                     == FIRST_STRING_P (regend[regno]))
+                    ? regend[regno] : end_match_1);
+           for (;;)
+             {
+               /* If necessary, advance to next segment in register
+                   contents.  */
+               while (d2 == dend2)
+                 {
+                   if (dend2 == end_match_2) break;
+                   if (dend2 == regend[regno]) break;
+
+                    /* End of string1 => advance to string2. */
+                    d2 = string2;
+                    dend2 = regend[regno];
+                 }
+               /* At end of register contents => success */
+               if (d2 == dend2) break;
+
+               /* If necessary, advance to next segment in data.  */
+               PREFETCH ();
+
+               /* How many characters left in this segment to match.  */
+               mcnt = dend - d;
+
+               /* Want how many consecutive characters we can match in
+                   one shot, so, if necessary, adjust the count.  */
+                if (mcnt > dend2 - d2)
+                 mcnt = dend2 - d2;
+
+               /* Compare that many; failure if mismatch, else move
+                   past them.  */
+               if (translate
+                    ? bcmp_translate (d, d2, mcnt, translate)
+                    : memcmp (d, d2, mcnt))
+                 goto fail;
+               d += mcnt, d2 += mcnt;
+
+               /* Do this because we've match some characters.  */
+               SET_REGS_MATCHED ();
+             }
+         }
+         break;
+
+
+        /* begline matches the empty string at the beginning of the string
+           (unless `not_bol' is set in `bufp'), and, if
+           `newline_anchor' is set, after newlines.  */
+       case begline:
+          DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+          if (AT_STRINGS_BEG (d))
+            {
+              if (!bufp->not_bol) break;
+            }
+          else if (d[-1] == '\n' && bufp->newline_anchor)
+            {
+              break;
+            }
+          /* In all other cases, we fail.  */
+          goto fail;
+
+
+        /* endline is the dual of begline.  */
+       case endline:
+          DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+          if (AT_STRINGS_END (d))
+            {
+              if (!bufp->not_eol) break;
+            }
+
+          /* We have to ``prefetch'' the next character.  */
+          else if ((d == end1 ? *string2 : *d) == '\n'
+                   && bufp->newline_anchor)
+            {
+              break;
+            }
+          goto fail;
+
+
+       /* Match at the very beginning of the data.  */
+        case begbuf:
+          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+          if (AT_STRINGS_BEG (d))
+            break;
+          goto fail;
+
+
+       /* Match at the very end of the data.  */
+        case endbuf:
+          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+         if (AT_STRINGS_END (d))
+           break;
+          goto fail;
+
+
+        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
+           pushes NULL as the value for the string on the stack.  Then
+           `pop_failure_point' will keep the current value for the
+           string, instead of restoring it.  To see why, consider
+           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
+           then the . fails against the \n.  But the next thing we want
+           to do is match the \n against the \n; if we restored the
+           string value, we would be back at the foo.
+
+           Because this is used only in specific cases, we don't need to
+           check all the things that `on_failure_jump' does, to make
+           sure the right things get saved on the stack.  Hence we don't
+           share its code.  The only reason to push anything on the
+           stack at all is that otherwise we would have to change
+           `anychar's code to do something besides goto fail in this
+           case; that seems worse than this.  */
+        case on_failure_keep_string_jump:
+          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+          DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt);
+#else
+          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+#endif
+
+          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+          break;
+
+
+       /* Uses of on_failure_jump:
+
+           Each alternative starts with an on_failure_jump that points
+           to the beginning of the next alternative.  Each alternative
+           except the last ends with a jump that in effect jumps past
+           the rest of the alternatives.  (They really jump to the
+           ending jump of the following alternative, because tensioning
+           these jumps is a hassle.)
+
+           Repeats start with an on_failure_jump that points past both
+           the repetition text and either the following jump or
+           pop_failure_jump back to this on_failure_jump.  */
+       case on_failure_jump:
+        on_failure:
+          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+          DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt);
+#else
+          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+#endif
+
+          /* If this on_failure_jump comes right before a group (i.e.,
+             the original * applied to a group), save the information
+             for that group and all inner ones, so that if we fail back
+             to this point, the group's information will be correct.
+             For example, in \(a*\)*\1, we need the preceding group,
+             and in \(zz\(a*\)b*\)\2, we need the inner group.  */
+
+          /* We can't use `p' to check ahead because we push
+             a failure point to `p + mcnt' after we do this.  */
+          p1 = p;
+
+          /* We need to skip no_op's before we look for the
+             start_memory in case this on_failure_jump is happening as
+             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+             against aba.  */
+          while (p1 < pend && (re_opcode_t) *p1 == no_op)
+            p1++;
+
+          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+            {
+              /* We have a new highest active register now.  This will
+                 get reset at the start_memory we are about to get to,
+                 but we will have saved all the registers relevant to
+                 this repetition op, as described above.  */
+              highest_active_reg = *(p1 + 1) + *(p1 + 2);
+              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+                lowest_active_reg = *(p1 + 1);
+            }
+
+          DEBUG_PRINT1 (":\n");
+          PUSH_FAILURE_POINT (p + mcnt, d, -2);
+          break;
+
+
+        /* A smart repeat ends with `maybe_pop_jump'.
+          We change it to either `pop_failure_jump' or `jump'.  */
+        case maybe_pop_jump:
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+          {
+           register unsigned char *p2 = p;
+
+            /* Compare the beginning of the repeat with what in the
+               pattern follows its end. If we can establish that there
+               is nothing that they would both match, i.e., that we
+               would have to backtrack because of (as in, e.g., `a*a')
+               then we can change to pop_failure_jump, because we'll
+               never have to backtrack.
+
+               This is not true in the case of alternatives: in
+               `(a|ab)*' we do need to backtrack to the `ab' alternative
+               (e.g., if the string was `ab').  But instead of trying to
+               detect that here, the alternative has put on a dummy
+               failure point which is what we will end up popping.  */
+
+           /* Skip over open/close-group commands.
+              If what follows this loop is a ...+ construct,
+              look at what begins its body, since we will have to
+              match at least one of that.  */
+           while (1)
+             {
+               if (p2 + 2 < pend
+                   && ((re_opcode_t) *p2 == stop_memory
+                       || (re_opcode_t) *p2 == start_memory))
+                 p2 += 3;
+               else if (p2 + 6 < pend
+                        && (re_opcode_t) *p2 == dummy_failure_jump)
+                 p2 += 6;
+               else
+                 break;
+             }
+
+           p1 = p + mcnt;
+           /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+              to the `maybe_finalize_jump' of this case.  Examine what
+              follows.  */
+
+            /* If we're at the end of the pattern, we can change.  */
+            if (p2 == pend)
+             {
+               /* Consider what happens when matching ":\(.*\)"
+                  against ":/".  I don't really understand this code
+                  yet.  */
+               p[-3] = (unsigned char) pop_failure_jump;
+                DEBUG_PRINT1
+                  ("  End of pattern: change to `pop_failure_jump'.\n");
+              }
+
+            else if ((re_opcode_t) *p2 == exactn
+                    || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+             {
+               register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+                if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+                  {
+                   p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+
+               else if ((re_opcode_t) p1[3] == charset
+                        || (re_opcode_t) p1[3] == charset_not)
+                 {
+                   int not = (re_opcode_t) p1[3] == charset_not;
+
+                   if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+                       && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+                     not = !not;
+
+                    /* `not' is equal to 1 if c would match, which means
+                        that we can't change to pop_failure_jump.  */
+                   if (!not)
+                      {
+                       p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+                 }
+             }
+            else if ((re_opcode_t) *p2 == charset)
+             {
+#ifdef DEBUG
+               register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+#if 0
+                if ((re_opcode_t) p1[3] == exactn
+                   && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
+                         && (p2[2 + p1[5] / BYTEWIDTH]
+                             & (1 << (p1[5] % BYTEWIDTH)))))
+#else
+                if ((re_opcode_t) p1[3] == exactn
+                   && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+                         && (p2[2 + p1[4] / BYTEWIDTH]
+                             & (1 << (p1[4] % BYTEWIDTH)))))
+#endif
+                  {
+                   p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+
+               else if ((re_opcode_t) p1[3] == charset_not)
+                 {
+                   int idx;
+                   /* We win if the charset_not inside the loop
+                      lists every character listed in the charset after.  */
+                   for (idx = 0; idx < (int) p2[1]; idx++)
+                     if (! (p2[2 + idx] == 0
+                            || (idx < (int) p1[4]
+                                && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+                       break;
+
+                   if (idx == p2[1])
+                      {
+                       p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+                 }
+               else if ((re_opcode_t) p1[3] == charset)
+                 {
+                   int idx;
+                   /* We win if the charset inside the loop
+                      has no overlap with the one after the loop.  */
+                   for (idx = 0;
+                        idx < (int) p2[1] && idx < (int) p1[4];
+                        idx++)
+                     if ((p2[2 + idx] & p1[5 + idx]) != 0)
+                       break;
+
+                   if (idx == p2[1] || idx == p1[4])
+                      {
+                       p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+                 }
+             }
+         }
+         p -= 2;               /* Point at relative address again.  */
+         if ((re_opcode_t) p[-1] != pop_failure_jump)
+           {
+             p[-1] = (unsigned char) jump;
+              DEBUG_PRINT1 ("  Match => jump.\n");
+             goto unconditional_jump;
+           }
+        /* Note fall through.  */
+
+
+       /* The end of a simple repeat has a pop_failure_jump back to
+           its matching on_failure_jump, where the latter will push a
+           failure point.  The pop_failure_jump takes off failure
+           points put on by this pop_failure_jump's matching
+           on_failure_jump; we got through the pattern to here from the
+           matching on_failure_jump, so didn't fail.  */
+        case pop_failure_jump:
+          {
+            /* We need to pass separate storage for the lowest and
+               highest registers, even though we don't care about the
+               actual values.  Otherwise, we will restore only one
+               register from the stack, since lowest will == highest in
+               `pop_failure_point'.  */
+            active_reg_t dummy_low_reg, dummy_high_reg;
+            unsigned char *pdummy;
+            const char *sdummy;
+
+            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+            POP_FAILURE_POINT (sdummy, pdummy,
+                               dummy_low_reg, dummy_high_reg,
+                               reg_dummy, reg_dummy, reg_info_dummy);
+          }
+         /* Note fall through.  */
+
+       unconditional_jump:
+#ifdef _LIBC
+         DEBUG_PRINT2 ("\n%p: ", p);
+#else
+         DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+          /* Note fall through.  */
+
+        /* Unconditionally jump (without popping any failure points).  */
+        case jump:
+         EXTRACT_NUMBER_AND_INCR (mcnt, p);    /* Get the amount to jump.  */
+          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+         p += mcnt;                            /* Do the jump.  */
+#ifdef _LIBC
+          DEBUG_PRINT2 ("(to %p).\n", p);
+#else
+          DEBUG_PRINT2 ("(to 0x%x).\n", p);
+#endif
+         break;
+
+
+        /* We need this opcode so we can detect where alternatives end
+           in `group_match_null_string_p' et al.  */
+        case jump_past_alt:
+          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+          goto unconditional_jump;
+
+
+        /* Normally, the on_failure_jump pushes a failure point, which
+           then gets popped at pop_failure_jump.  We will end up at
+           pop_failure_jump, also, and with a pattern of, say, `a+', we
+           are skipping over the on_failure_jump, so we have to push
+           something meaningless for pop_failure_jump to pop.  */
+        case dummy_failure_jump:
+          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+          /* It doesn't matter what we push for the string here.  What
+             the code at `fail' tests is the value for the pattern.  */
+          PUSH_FAILURE_POINT (NULL, NULL, -2);
+          goto unconditional_jump;
+
+
+        /* At the end of an alternative, we need to push a dummy failure
+           point in case we are followed by a `pop_failure_jump', because
+           we don't want the failure point for the alternative to be
+           popped.  For example, matching `(a|ab)*' against `aab'
+           requires that we match the `ab' alternative.  */
+        case push_dummy_failure:
+          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+          /* See comments just above at `dummy_failure_jump' about the
+             two zeroes.  */
+          PUSH_FAILURE_POINT (NULL, NULL, -2);
+          break;
+
+        /* Have to succeed matching what follows at least n times.
+           After that, handle like `on_failure_jump'.  */
+        case succeed_n:
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+          assert (mcnt >= 0);
+          /* Originally, this is how many times we HAVE to succeed.  */
+          if (mcnt > 0)
+            {
+               mcnt--;
+              p += 2;
+               STORE_NUMBER_AND_INCR (p, mcnt);
+#ifdef _LIBC
+               DEBUG_PRINT3 ("  Setting %p to %d.\n", p - 2, mcnt);
+#else
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p - 2, mcnt);
+#endif
+            }
+         else if (mcnt == 0)
+            {
+#ifdef _LIBC
+              DEBUG_PRINT2 ("  Setting two bytes from %p to no_op.\n", p+2);
+#else
+              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
+#endif
+             p[2] = (unsigned char) no_op;
+              p[3] = (unsigned char) no_op;
+              goto on_failure;
+            }
+          break;
+
+        case jump_n:
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+          /* Originally, this is how many times we CAN jump.  */
+          if (mcnt)
+            {
+               mcnt--;
+               STORE_NUMBER (p + 2, mcnt);
+#ifdef _LIBC
+               DEBUG_PRINT3 ("  Setting %p to %d.\n", p + 2, mcnt);
+#else
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p + 2, mcnt);
+#endif
+              goto unconditional_jump;
+            }
+          /* If don't have to jump any more, skip over the rest of command.  */
+         else
+           p += 4;
+          break;
+
+       case set_number_at:
+         {
+            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            p1 = p + mcnt;
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+            DEBUG_PRINT3 ("  Setting %p to %d.\n", p1, mcnt);
+#else
+            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
+#endif
+           STORE_NUMBER (p1, mcnt);
+            break;
+          }
+
+#if 0
+       /* The DEC Alpha C compiler 3.x generates incorrect code for the
+          test  WORDCHAR_P (d - 1) != WORDCHAR_P (d)  in the expansion of
+          AT_WORD_BOUNDARY, so this code is disabled.  Expanding the
+          macro and introducing temporary variables works around the bug.  */
+
+       case wordbound:
+         DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+         if (AT_WORD_BOUNDARY (d))
+           break;
+         goto fail;
+
+       case notwordbound:
+         DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+         if (AT_WORD_BOUNDARY (d))
+           goto fail;
+         break;
+#else
+       case wordbound:
+       {
+         boolean prevchar, thischar;
+
+         DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+         if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+           break;
+
+         prevchar = WORDCHAR_P (d - 1);
+         thischar = WORDCHAR_P (d);
+         if (prevchar != thischar)
+           break;
+         goto fail;
+       }
+
+      case notwordbound:
+       {
+         boolean prevchar, thischar;
+
+         DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+         if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+           goto fail;
+
+         prevchar = WORDCHAR_P (d - 1);
+         thischar = WORDCHAR_P (d);
+         if (prevchar != thischar)
+           goto fail;
+         break;
+       }
+#endif
+
+       case wordbeg:
+          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+         if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+           break;
+          goto fail;
+
+       case wordend:
+          DEBUG_PRINT1 ("EXECUTING wordend.\n");
+         if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+              && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+           break;
+          goto fail;
+
+#ifdef emacs
+       case before_dot:
+          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+         if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+           goto fail;
+         break;
+
+       case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+         if (PTR_CHAR_POS ((unsigned char *) d) != point)
+           goto fail;
+         break;
+
+       case after_dot:
+          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+           goto fail;
+         break;
+
+       case syntaxspec:
+          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+         mcnt = *p++;
+         goto matchsyntax;
+
+        case wordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+         mcnt = (int) Sword;
+        matchsyntax:
+         PREFETCH ();
+         /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+         d++;
+         if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+           goto fail;
+          SET_REGS_MATCHED ();
+         break;
+
+       case notsyntaxspec:
+          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+         mcnt = *p++;
+         goto matchnotsyntax;
+
+        case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+         mcnt = (int) Sword;
+        matchnotsyntax:
+         PREFETCH ();
+         /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+         d++;
+         if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+           goto fail;
+         SET_REGS_MATCHED ();
+          break;
+
+#else /* not emacs */
+       case wordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+         PREFETCH ();
+          if (!WORDCHAR_P (d))
+            goto fail;
+         SET_REGS_MATCHED ();
+          d++;
+         break;
+
+       case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+         PREFETCH ();
+         if (WORDCHAR_P (d))
+            goto fail;
+          SET_REGS_MATCHED ();
+          d++;
+         break;
+#endif /* not emacs */
+
+        default:
+          abort ();
+       }
+      continue;  /* Successfully executed one pattern command; keep going.  */
+
+
+    /* We goto here if a matching operation fails. */
+    fail:
+      if (!FAIL_STACK_EMPTY ())
+       { /* A restart point is known.  Restore to that state.  */
+          DEBUG_PRINT1 ("\nFAIL:\n");
+          POP_FAILURE_POINT (d, p,
+                             lowest_active_reg, highest_active_reg,
+                             regstart, regend, reg_info);
+
+          /* If this failure point is a dummy, try the next one.  */
+          if (!p)
+           goto fail;
+
+          /* If we failed to the end of the pattern, don't examine *p.  */
+         assert (p <= pend);
+          if (p < pend)
+            {
+              boolean is_a_jump_n = false;
+
+              /* If failed to a backwards jump that's part of a repetition
+                 loop, need to pop this failure point and use the next one.  */
+              switch ((re_opcode_t) *p)
+                {
+                case jump_n:
+                  is_a_jump_n = true;
+                case maybe_pop_jump:
+                case pop_failure_jump:
+                case jump:
+                  p1 = p + 1;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  p1 += mcnt;
+
+                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+                      || (!is_a_jump_n
+                          && (re_opcode_t) *p1 == on_failure_jump))
+                    goto fail;
+                  break;
+                default:
+                  /* do nothing */ ;
+                }
+            }
+
+          if (d >= string1 && d <= end1)
+           dend = end_match_1;
+        }
+      else
+        break;   /* Matching at this starting point really fails.  */
+    } /* for (;;) */
+
+  if (best_regs_set)
+    goto restore_best_regs;
+
+  FREE_VARIABLES ();
+
+  return -1;                           /* Failure to match.  */
+} /* re_match_2 */
+\f
+/* Subroutine definitions for re_match_2.  */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+   Return true if the pattern up to the corresponding stop_memory can
+   match the empty string, and false otherwise.
+
+   If we find the matching stop_memory, sets P to point to one past its number.
+   Otherwise, sets P to an undefined byte less than or equal to END.
+
+   We don't handle duplicates properly (yet).  */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  /* Point to after the args to the start_memory.  */
+  unsigned char *p1 = *p + 2;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and return true or
+        false, as appropriate, when we get to one that can't, or to the
+         matching stop_memory.  */
+
+      switch ((re_opcode_t) *p1)
+        {
+        /* Could be either a loop or a series of alternatives.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+          /* If the next operation is not a jump backwards in the
+            pattern.  */
+
+         if (mcnt >= 0)
+           {
+              /* Go through the on_failure_jumps of the alternatives,
+                 seeing if any of the alternatives cannot match nothing.
+                 The last alternative starts with only a jump,
+                 whereas the rest start with on_failure_jump and end
+                 with a jump, e.g., here is the pattern for `a|b|c':
+
+                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+                 /exactn/1/c
+
+                 So, we have to first go through the first (n-1)
+                 alternatives and then deal with the last one separately.  */
+
+
+              /* Deal with the first (n-1) alternatives, which start
+                 with an on_failure_jump (see above) that jumps to right
+                 past a jump_past_alt.  */
+
+              while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+                {
+                  /* `mcnt' holds how many bytes long the alternative
+                     is, including the ending `jump_past_alt' and
+                     its number.  */
+
+                  if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+                                                     reg_info))
+                    return false;
+
+                  /* Move to right after this alternative, including the
+                    jump_past_alt.  */
+                  p1 += mcnt;
+
+                  /* Break if it's the beginning of an n-th alternative
+                     that doesn't begin with an on_failure_jump.  */
+                  if ((re_opcode_t) *p1 != on_failure_jump)
+                    break;
+
+                 /* Still have to check that it's not an n-th
+                    alternative that starts with an on_failure_jump.  */
+                 p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+                    {
+                     /* Get to the beginning of the n-th alternative.  */
+                      p1 -= 3;
+                      break;
+                    }
+                }
+
+              /* Deal with the last alternative: go back and get number
+                 of the `jump_past_alt' just before it.  `mcnt' contains
+                 the length of the alternative.  */
+              EXTRACT_NUMBER (mcnt, p1 - 2);
+
+              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+                return false;
+
+              p1 += mcnt;      /* Get past the n-th alternative.  */
+            } /* if mcnt > 0 */
+          break;
+
+
+        case stop_memory:
+         assert (p1[1] == **p);
+          *p = p1 + 2;
+          return true;
+
+
+        default:
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    } /* while p1 < end */
+
+  return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+   It expects P to be the first byte of a single alternative and END one
+   byte past the last. The alternative can contain groups.  */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+    unsigned char *p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  unsigned char *p1 = p;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and break when we get
+         to one that can't.  */
+
+      switch ((re_opcode_t) *p1)
+        {
+       /* It's a loop.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+          break;
+
+       default:
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    }  /* while p1 < end */
+
+  return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+   alt_match_null_string_p.
+
+   Sets P to one after the op and its arguments, if any.  */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  boolean ret;
+  int reg_no;
+  unsigned char *p1 = *p;
+
+  switch ((re_opcode_t) *p1++)
+    {
+    case no_op:
+    case begline:
+    case endline:
+    case begbuf:
+    case endbuf:
+    case wordbeg:
+    case wordend:
+    case wordbound:
+    case notwordbound:
+#ifdef emacs
+    case before_dot:
+    case at_dot:
+    case after_dot:
+#endif
+      break;
+
+    case start_memory:
+      reg_no = *p1;
+      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+      ret = group_match_null_string_p (&p1, end, reg_info);
+
+      /* Have to set this here in case we're checking a group which
+         contains a group and a back reference to it.  */
+
+      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+      if (!ret)
+        return false;
+      break;
+
+    /* If this is an optimized succeed_n for zero times, make the jump.  */
+    case jump:
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+      if (mcnt >= 0)
+        p1 += mcnt;
+      else
+        return false;
+      break;
+
+    case succeed_n:
+      /* Get to the number of times to succeed.  */
+      p1 += 2;
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+      if (mcnt == 0)
+        {
+          p1 -= 4;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+        }
+      else
+        return false;
+      break;
+
+    case duplicate:
+      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+        return false;
+      break;
+
+    case set_number_at:
+      p1 += 4;
+
+    default:
+      /* All other opcodes mean we cannot match the empty string.  */
+      return false;
+  }
+
+  *p = p1;
+  return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+   bytes; nonzero otherwise.  */
+
+static int
+bcmp_translate (s1, s2, len, translate)
+     const char *s1, *s2;
+     register int len;
+     RE_TRANSLATE_TYPE translate;
+{
+  register const unsigned char *p1 = (const unsigned char *) s1;
+  register const unsigned char *p2 = (const unsigned char *) s2;
+  while (len)
+    {
+      if (translate[*p1++] != translate[*p2++]) return 1;
+      len--;
+    }
+  return 0;
+}
+\f
+/* Entry points for GNU code.  */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in BUFP.
+   Returns 0 if the pattern was valid, otherwise an error string.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in BUFP on entry.
+
+   We call regex_compile to do the actual compilation.  */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+     const char *pattern;
+     size_t length;
+     struct re_pattern_buffer *bufp;
+{
+  reg_errcode_t ret;
+
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  bufp->regs_allocated = REGS_UNALLOCATED;
+
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  bufp->no_sub = 0;
+
+  /* Match anchors at newline.  */
+  bufp->newline_anchor = 1;
+
+  ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+  if (!ret)
+    return NULL;
+  return gettext (re_error_msgid + re_error_msgid_idx[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+\f
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them unless specifically requested.  */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+#ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+   these names if they don't use our functions, and still use
+   regcomp/regexec below without link errors.  */
+weak_function
+#endif
+re_comp (s)
+    const char *s;
+{
+  reg_errcode_t ret;
+
+  if (!s)
+    {
+      if (!re_comp_buf.buffer)
+       return gettext ("No previous regular expression");
+      return 0;
+    }
+
+  if (!re_comp_buf.buffer)
+    {
+      re_comp_buf.buffer = (unsigned char *) malloc (200);
+      if (re_comp_buf.buffer == NULL)
+        return (char *) gettext (re_error_msgid
+                                + re_error_msgid_idx[(int) REG_ESPACE]);
+      re_comp_buf.allocated = 200;
+
+      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+      if (re_comp_buf.fastmap == NULL)
+       return (char *) gettext (re_error_msgid
+                                + re_error_msgid_idx[(int) REG_ESPACE]);
+    }
+
+  /* Since `re_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  re_comp_buf.newline_anchor = 1;
+
+  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+  if (!ret)
+    return NULL;
+
+  /* Yes, we're discarding `const' here if !HAVE_LIBINTL.  */
+  return (char *) gettext (re_error_msgid + re_error_msgid_idx[(int) ret]);
+}
+
+
+int
+#ifdef _LIBC
+weak_function
+#endif
+re_exec (s)
+    const char *s;
+{
+  const int len = strlen (s);
+  return
+    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+
+#endif /* _REGEX_RE_COMP */
+\f
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' to an allocated space for the fastmap;
+     `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+int
+regcomp (preg, pattern, cflags)
+    regex_t *preg;
+    const char *pattern;
+    int cflags;
+{
+  reg_errcode_t ret;
+  reg_syntax_t syntax
+    = (cflags & REG_EXTENDED) ?
+      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->used = 0;
+
+  /* Try to allocate space for the fastmap.  */
+  preg->fastmap = (char *) malloc (1 << BYTEWIDTH);
+
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+
+      preg->translate
+       = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
+                                     * sizeof (*(RE_TRANSLATE_TYPE)0));
+      if (preg->translate == NULL)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i;
+    }
+  else
+    preg->translate = NULL;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we
+     can use strlen here in compiling the pattern.  */
+  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+  if (ret == REG_NOERROR && preg->fastmap)
+    {
+      /* Compute the fastmap now, since regexec cannot modify the pattern
+        buffer.  */
+      if (re_compile_fastmap (preg) == -2)
+       {
+         /* Some error occured while computing the fastmap, just forget
+            about it.  */
+         free (preg->fastmap);
+         preg->fastmap = NULL;
+       }
+    }
+
+  return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    const regex_t *preg;
+    const char *string;
+    size_t nmatch;
+    regmatch_t pmatch[];
+    int eflags;
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+  /* The user has told us exactly how many registers to return
+     information about, via `nmatch'.  We have to pass that on to the
+     matching routines.  */
+  private_preg.regs_allocated = REGS_FIXED;
+
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start = TALLOC (nmatch * 2, regoff_t);
+      if (regs.start == NULL)
+        return (int) REG_NOMATCH;
+      regs.end = regs.start + nmatch;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg, string, len,
+                   /* start: */ 0, /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+#ifdef _LIBC
+weak_alias (__regexec, regexec)
+#endif
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   We don't use PREG here.  */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    const regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+{
+  const char *msg;
+  size_t msg_size;
+
+  if (errcode < 0
+      || errcode >= (int) (sizeof (re_error_msgid_idx)
+                          / sizeof (re_error_msgid_idx[0])))
+    /* Only error codes returned by the rest of the code should be passed
+       to this routine.  If we are given anything else, or if other regex
+       code generates an invalid error code, then the program has a bug.
+       Dump core so we can fix it.  */
+    abort ();
+
+  msg = gettext (re_error_msgid + re_error_msgid_idx[errcode]);
+
+  msg_size = strlen (msg) + 1; /* Includes the null.  */
+
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+#if defined HAVE_MEMPCPY || defined _LIBC
+         *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+          memcpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+#endif
+        }
+      else
+        memcpy (errbuf, msg, msg_size);
+    }
+
+  return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+void
+regfree (preg)
+    regex_t *preg;
+{
+  if (preg->buffer != NULL)
+    free (preg->buffer);
+  preg->buffer = NULL;
+
+  preg->allocated = 0;
+  preg->used = 0;
+
+  if (preg->fastmap != NULL)
+    free (preg->fastmap);
+  preg->fastmap = NULL;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != NULL)
+    free (preg->translate);
+  preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+#endif /* not emacs  */
diff --git a/lib/routemap.c b/lib/routemap.c
new file mode 100644 (file)
index 0000000..b000f2f
--- /dev/null
@@ -0,0 +1,1077 @@
+/* Route map function.
+   Copyright (C) 1998, 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "memory.h"
+#include "vector.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+\f
+/* Vector for route match rules. */
+static vector route_match_vec;
+
+/* Vector for route set rules. */
+static vector route_set_vec;
+
+/* Route map rule. This rule has both `match' rule and `set' rule. */
+struct route_map_rule
+{
+  /* Rule type. */
+  struct route_map_rule_cmd *cmd;
+
+  /* For pretty printing. */
+  char *rule_str;
+
+  /* Pre-compiled match rule. */
+  void *value;
+
+  /* Linked list. */
+  struct route_map_rule *next;
+  struct route_map_rule *prev;
+};
+
+/* Making route map list. */
+struct route_map_list
+{
+  struct route_map *head;
+  struct route_map *tail;
+
+  void (*add_hook) (char *);
+  void (*delete_hook) (char *);
+  void (*event_hook) (route_map_event_t, char *); 
+};
+
+/* Master list of route map. */
+static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
+
+static void
+route_map_rule_delete (struct route_map_rule_list *,
+                      struct route_map_rule *);
+
+static void
+route_map_index_delete (struct route_map_index *, int);
+\f
+/* New route map allocation. Please note route map's name must be
+   specified. */
+static struct route_map *
+route_map_new (char *name)
+{
+  struct route_map *new;
+
+  new =  XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
+  new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
+  return new;
+}
+
+/* Add new name to route_map. */
+static struct route_map *
+route_map_add (char *name)
+{
+  struct route_map *map;
+  struct route_map_list *list;
+
+  map = route_map_new (name);
+  list = &route_map_master;
+    
+  map->next = NULL;
+  map->prev = list->tail;
+  if (list->tail)
+    list->tail->next = map;
+  else
+    list->head = map;
+  list->tail = map;
+
+  /* Execute hook. */
+  if (route_map_master.add_hook)
+    (*route_map_master.add_hook) (name);
+
+  return map;
+}
+
+/* Route map delete from list. */
+static void
+route_map_delete (struct route_map *map)
+{
+  struct route_map_list *list;
+  struct route_map_index *index;
+  char *name;
+  
+  while ((index = map->head) != NULL)
+    route_map_index_delete (index, 0);
+
+  name = map->name;
+
+  list = &route_map_master;
+
+  if (map->next)
+    map->next->prev = map->prev;
+  else
+    list->tail = map->prev;
+
+  if (map->prev)
+    map->prev->next = map->next;
+  else
+    list->head = map->next;
+
+  XFREE (MTYPE_ROUTE_MAP, map);
+
+  /* Execute deletion hook. */
+  if (route_map_master.delete_hook)
+    (*route_map_master.delete_hook) (name);
+
+  if (name)
+    XFREE (MTYPE_ROUTE_MAP_NAME, name);
+
+}
+
+/* Lookup route map by route map name string. */
+struct route_map *
+route_map_lookup_by_name (char *name)
+{
+  struct route_map *map;
+
+  for (map = route_map_master.head; map; map = map->next)
+    if (strcmp (map->name, name) == 0)
+      return map;
+  return NULL;
+}
+
+/* Lookup route map.  If there isn't route map create one and return
+   it. */
+struct route_map *
+route_map_get (char *name)
+{
+  struct route_map *map;
+
+  map = route_map_lookup_by_name (name);
+  if (map == NULL)
+    map = route_map_add (name);
+  return map;
+}
+
+/* Return route map's type string. */
+static char *
+route_map_type_str (enum route_map_type type)
+{
+  switch (type)
+    {
+    case RMAP_PERMIT:
+      return "permit";
+      break;
+    case RMAP_DENY:
+      return "deny";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+int
+route_map_empty (struct route_map *map)
+{
+  if (map->head == NULL && map->tail == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+/* For debug. */
+void
+route_map_print ()
+{
+  struct route_map *map;
+  struct route_map_index *index;
+  struct route_map_rule *rule;
+
+  for (map = route_map_master.head; map; map = map->next)
+    for (index = map->head; index; index = index->next)
+      {
+       printf ("route-map %s %s %d\n", 
+               map->name,
+               route_map_type_str (index->type),
+               index->pref);
+       for (rule = index->match_list.head; rule; rule = rule->next)
+         printf (" match %s %s\n", rule->cmd->str, rule->rule_str);
+       for (rule = index->set_list.head; rule; rule = rule->next)
+         printf (" set %s %s\n", rule->cmd->str, rule->rule_str);
+       if (index->exitpolicy == RMAP_GOTO)
+         printf (" on-match goto %d\n", index->nextpref);
+       if (index->exitpolicy == RMAP_NEXT)
+         printf (" on-match next\n");
+      }
+}
+
+/* New route map allocation. Please note route map's name must be
+   specified. */
+struct route_map_index *
+route_map_index_new ()
+{
+  struct route_map_index *new;
+
+  new =  XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
+  new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
+  return new;
+}
+
+/* Free route map index. */
+static void
+route_map_index_delete (struct route_map_index *index, int notify)
+{
+  struct route_map_rule *rule;
+
+  /* Free route match. */
+  while ((rule = index->match_list.head) != NULL)
+    route_map_rule_delete (&index->match_list, rule);
+
+  /* Free route set. */
+  while ((rule = index->set_list.head) != NULL)
+    route_map_rule_delete (&index->set_list, rule);
+
+  /* Remove index from route map list. */
+  if (index->next)
+    index->next->prev = index->prev;
+  else
+    index->map->tail = index->prev;
+
+  if (index->prev)
+    index->prev->next = index->next;
+  else
+    index->map->head = index->next;
+
+    /* Execute event hook. */
+  if (route_map_master.event_hook && notify)
+    (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
+                                   index->map->name);
+
+  XFREE (MTYPE_ROUTE_MAP_INDEX, index);
+}
+
+/* Lookup index from route map. */
+struct route_map_index *
+route_map_index_lookup (struct route_map *map, enum route_map_type type,
+                       int pref)
+{
+  struct route_map_index *index;
+
+  for (index = map->head; index; index = index->next)
+    if ((index->type == type || type == RMAP_ANY)
+       && index->pref == pref)
+      return index;
+  return NULL;
+}
+
+/* Add new index to route map. */
+struct route_map_index *
+route_map_index_add (struct route_map *map, enum route_map_type type,
+                    int pref)
+{
+  struct route_map_index *index;
+  struct route_map_index *point;
+
+  /* Allocate new route map inex. */
+  index = route_map_index_new ();
+  index->map = map;
+  index->type = type;
+  index->pref = pref;
+  
+  /* Compare preference. */
+  for (point = map->head; point; point = point->next)
+    if (point->pref >= pref)
+      break;
+
+  if (map->head == NULL)
+    {
+      map->head = map->tail = index;
+    }
+  else if (point == NULL)
+    {
+      index->prev = map->tail;
+      map->tail->next = index;
+      map->tail = index;
+    }
+  else if (point == map->head)
+    {
+      index->next = map->head;
+      map->head->prev = index;
+      map->head = index;
+    }
+  else
+    {
+      index->next = point;
+      index->prev = point->prev;
+      if (point->prev)
+       point->prev->next = index;
+      point->prev = index;
+    }
+
+  /* Execute event hook. */
+  if (route_map_master.event_hook)
+    (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
+                                   map->name);
+
+  return index;
+}
+
+/* Get route map index. */
+struct route_map_index *
+route_map_index_get (struct route_map *map, enum route_map_type type, 
+                    int pref)
+{
+  struct route_map_index *index;
+
+  index = route_map_index_lookup (map, RMAP_ANY, pref);
+  if (index && index->type != type)
+    {
+      /* Delete index from route map. */
+      route_map_index_delete (index, 1);
+      index = NULL;
+    }
+  if (index == NULL)
+    index = route_map_index_add (map, type, pref);
+  return index;
+}
+
+/* New route map rule */
+struct route_map_rule *
+route_map_rule_new ()
+{
+  struct route_map_rule *new;
+
+  new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
+  return new;
+}
+\f
+/* Install rule command to the match list. */
+void
+route_map_install_match (struct route_map_rule_cmd *cmd)
+{
+  vector_set (route_match_vec, cmd);
+}
+
+/* Install rule command to the set list. */
+void
+route_map_install_set (struct route_map_rule_cmd *cmd)
+{
+  vector_set (route_set_vec, cmd);
+}
+
+/* Lookup rule command from match list. */
+struct route_map_rule_cmd *
+route_map_lookup_match (char *name)
+{
+  int i;
+  struct route_map_rule_cmd *rule;
+
+  for (i = 0; i < vector_max (route_match_vec); i++)
+    if ((rule = vector_slot (route_match_vec, i)) != NULL)
+      if (strcmp (rule->str, name) == 0)
+       return rule;
+  return NULL;
+}
+
+/* Lookup rule command from set list. */
+struct route_map_rule_cmd *
+route_map_lookup_set (char *name)
+{
+  int i;
+  struct route_map_rule_cmd *rule;
+
+  for (i = 0; i < vector_max (route_set_vec); i++)
+    if ((rule = vector_slot (route_set_vec, i)) != NULL)
+      if (strcmp (rule->str, name) == 0)
+       return rule;
+  return NULL;
+}
+
+/* Add match and set rule to rule list. */
+static void
+route_map_rule_add (struct route_map_rule_list *list,
+                   struct route_map_rule *rule)
+{
+  rule->next = NULL;
+  rule->prev = list->tail;
+  if (list->tail)
+    list->tail->next = rule;
+  else
+    list->head = rule;
+  list->tail = rule;
+}
+
+/* Delete rule from rule list. */
+static void
+route_map_rule_delete (struct route_map_rule_list *list,
+                      struct route_map_rule *rule)
+{
+  if (rule->cmd->func_free)
+    (*rule->cmd->func_free) (rule->value);
+
+  if (rule->rule_str)
+    XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
+
+  if (rule->next)
+    rule->next->prev = rule->prev;
+  else
+    list->tail = rule->prev;
+  if (rule->prev)
+    rule->prev->next = rule->next;
+  else
+    list->head = rule->next;
+
+  XFREE (MTYPE_ROUTE_MAP_RULE, rule);
+}
+
+/* strcmp wrapper function which don't crush even argument is NULL. */
+int
+rulecmp (char *dst, char *src)
+{
+  if (dst == NULL)
+    {
+      if (src ==  NULL)
+       return 0;
+      else
+       return 1;
+    }
+  else
+    {
+      if (src == NULL)
+       return 1;
+      else
+       return strcmp (dst, src);
+    }
+  return 1;
+}
+
+/* Add match statement to route map. */
+int
+route_map_add_match (struct route_map_index *index, char *match_name,
+                    char *match_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule *next;
+  struct route_map_rule_cmd *cmd;
+  void *compile;
+  int replaced = 0;
+
+  /* First lookup rule for add match statement. */
+  cmd = route_map_lookup_match (match_name);
+  if (cmd == NULL)
+    return RMAP_RULE_MISSING;
+
+  /* Next call compile function for this match statement. */
+  if (cmd->func_compile)
+    {
+      compile= (*cmd->func_compile)(match_arg);
+      if (compile == NULL)
+       return RMAP_COMPILE_ERROR;
+    }
+  else
+    compile = NULL;
+
+  /* If argument is completely same ignore it. */
+  for (rule = index->match_list.head; rule; rule = next)
+    {
+      next = rule->next;
+      if (rule->cmd == cmd)
+       {       
+         route_map_rule_delete (&index->match_list, rule);
+         replaced = 1;
+       }
+    }
+
+  /* Add new route map match rule. */
+  rule = route_map_rule_new ();
+  rule->cmd = cmd;
+  rule->value = compile;
+  if (match_arg)
+    rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
+  else
+    rule->rule_str = NULL;
+
+  /* Add new route match rule to linked list. */
+  route_map_rule_add (&index->match_list, rule);
+
+  /* Execute event hook. */
+  if (route_map_master.event_hook)
+    (*route_map_master.event_hook) (replaced ?
+                                   RMAP_EVENT_MATCH_REPLACED:
+                                   RMAP_EVENT_MATCH_ADDED,
+                                   index->map->name);
+
+  return 0;
+}
+
+/* Delete specified route match rule. */
+int
+route_map_delete_match (struct route_map_index *index, char *match_name,
+                       char *match_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule_cmd *cmd;
+
+  cmd = route_map_lookup_match (match_name);
+  if (cmd == NULL)
+    return 1;
+  
+  for (rule = index->match_list.head; rule; rule = rule->next)
+    if (rule->cmd == cmd && 
+       (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
+      {
+       route_map_rule_delete (&index->match_list, rule);
+       /* Execute event hook. */
+       if (route_map_master.event_hook)
+         (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
+                                         index->map->name);
+       return 0;
+      }
+  /* Can't find matched rule. */
+  return 1;
+}
+
+/* Add route-map set statement to the route map. */
+int
+route_map_add_set (struct route_map_index *index, char *set_name,
+                  char *set_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule *next;
+  struct route_map_rule_cmd *cmd;
+  void *compile;
+  int replaced = 0;
+
+  cmd = route_map_lookup_set (set_name);
+  if (cmd == NULL)
+    return RMAP_RULE_MISSING;
+
+  /* Next call compile function for this match statement. */
+  if (cmd->func_compile)
+    {
+      compile= (*cmd->func_compile)(set_arg);
+      if (compile == NULL)
+       return RMAP_COMPILE_ERROR;
+    }
+  else
+    compile = NULL;
+
+ /* Add by WJL. if old set command of same kind exist, delete it first
+    to ensure only one set command of same kind exist under a
+    route_map_index. */
+  for (rule = index->set_list.head; rule; rule = next)
+    {
+      next = rule->next;
+      if (rule->cmd == cmd)
+       {
+         route_map_rule_delete (&index->set_list, rule);
+         replaced = 1;
+       }
+    }
+
+  /* Add new route map match rule. */
+  rule = route_map_rule_new ();
+  rule->cmd = cmd;
+  rule->value = compile;
+  if (set_arg)
+    rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
+  else
+    rule->rule_str = NULL;
+
+  /* Add new route match rule to linked list. */
+  route_map_rule_add (&index->set_list, rule);
+
+  /* Execute event hook. */
+  if (route_map_master.event_hook)
+    (*route_map_master.event_hook) (replaced ?
+                                   RMAP_EVENT_SET_REPLACED:
+                                   RMAP_EVENT_SET_ADDED,
+                                   index->map->name);
+  return 0;
+}
+
+/* Delete route map set rule. */
+int
+route_map_delete_set (struct route_map_index *index, char *set_name,
+                       char *set_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule_cmd *cmd;
+
+  cmd = route_map_lookup_set (set_name);
+  if (cmd == NULL)
+    return 1;
+  
+  for (rule = index->set_list.head; rule; rule = rule->next)
+    if ((rule->cmd == cmd) &&
+         (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
+      {
+        route_map_rule_delete (&index->set_list, rule);
+       /* Execute event hook. */
+       if (route_map_master.event_hook)
+         (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
+                                         index->map->name);
+        return 0;
+      }
+  /* Can't find matched rule. */
+  return 1;
+}
+
+/* Apply route map's each index to the object. */
+/*
+** The matrix for a route-map looks like this:
+** (note, this includes the description for the "NEXT"
+** and "GOTO" frobs now
+**
+**            Match   |   No Match
+**                    |
+**  permit      a     |      c
+**                    |
+**  ------------------+---------------
+**                    |
+**  deny        b     |      d
+**                    |
+**
+** a)   Apply Set statements, accept route
+**      If NEXT is specified, goto NEXT statement
+**      If GOTO is specified, goto the first clause where pref > nextpref
+**      If nothing is specified, do as Cisco and finish
+** b)   Finish route-map processing, and deny route
+** c) & d)   Goto Next index
+**
+** If we get no matches after we've processed all updates, then the route
+** is dropped too.
+**
+** Some notes on the new "NEXT" and "GOTO"
+**   on-match next    - If this clause is matched, then the set statements
+**                      are executed and then we drop through to the next clause
+**   on-match goto n  - If this clause is matched, then the set statments
+**                      are executed and then we goto the nth clause, or the
+**                      first clause greater than this. In order to ensure
+**                      route-maps *always* exit, you cannot jump backwards.
+**                      Sorry ;)
+**
+** We need to make sure our route-map processing matches the above
+*/
+route_map_result_t
+route_map_apply_index (struct route_map_index *index, struct prefix *prefix,
+                       route_map_object_t type, void *object)
+{
+  int ret;
+  struct route_map_rule *match;
+  struct route_map_rule *set;
+  
+  /* Check all match rule and if there is no match rule return 0. */
+  for (match = index->match_list.head; match; match = match->next)
+    {
+      /* Try each match statement in turn. If any return something
+       other than RM_MATCH then we don't need to check anymore and can
+       return */
+      ret = (*match->cmd->func_apply)(match->value, prefix, type, object);
+      if (ret != RMAP_MATCH)
+       return ret;
+    }
+
+  /* We get here if all match statements matched From the matrix
+   above, if this is PERMIT we go on and apply the SET functions.  If
+   we're deny, we return indicating we matched a deny */
+
+  /* Apply set statement to the object. */
+  if (index->type == RMAP_PERMIT)
+    {
+      for (set = index->set_list.head; set; set = set->next)
+       {
+         ret = (*set->cmd->func_apply)(set->value, prefix, type, object);
+       }
+      return RMAP_MATCH;
+    }
+  else 
+    {
+      return RMAP_DENYMATCH;
+    }
+  /* Should not get here! */
+  return RMAP_MATCH;
+}
+
+/* Apply route map to the object. */
+route_map_result_t
+route_map_apply (struct route_map *map, struct prefix *prefix, 
+                route_map_object_t type, void *object)
+{
+  int ret = 0;
+  struct route_map_index *index;
+
+  if (map == NULL)
+    return RMAP_DENYMATCH;
+
+  for (index = map->head; index; index = index->next)
+    {
+      /* Apply this index. End here if we get a RM_NOMATCH */
+      ret = route_map_apply_index (index, prefix, type, object);
+
+      if (ret != RMAP_NOMATCH)
+       {
+         /* We now have to handle the NEXT and GOTO clauses */
+         if(index->exitpolicy == RMAP_EXIT)
+           return ret;
+         if(index->exitpolicy == RMAP_GOTO)
+           {
+             /* Find the next clause to jump to */
+             struct route_map_index *next;
+
+             next = index->next;
+             while (next && next->pref < index->nextpref)
+               {
+                 index = next;
+                 next = next->next;
+               }
+             if (next == NULL)
+               {
+                 /* No clauses match! */
+                 return ret;
+               }
+           }
+         /* Otherwise, we fall through as it was a NEXT */
+       }
+    }
+  /* Finally route-map does not match at all. */
+  return RMAP_DENYMATCH;
+}
+
+void
+route_map_add_hook (void (*func) (char *))
+{
+  route_map_master.add_hook = func;
+}
+
+void
+route_map_delete_hook (void (*func) (char *))
+{
+  route_map_master.delete_hook = func;
+}
+
+void
+route_map_event_hook (void (*func) (route_map_event_t, char *))
+{
+  route_map_master.event_hook = func;
+}
+
+void
+route_map_init ()
+{
+  /* Make vector for match and set. */
+  route_match_vec = vector_init (1);
+  route_set_vec = vector_init (1);
+}
+\f
+/* VTY related functions. */
+DEFUN (route_map,
+       route_map_cmd,
+       "route-map WORD (deny|permit) <1-65535>",
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n"
+       "Route map denies set operations\n"
+       "Route map permits set operations\n"
+       "Sequence to insert to/delete from existing route-map entry\n")
+{
+  int permit;
+  unsigned long pref;
+  struct route_map *map;
+  struct route_map_index *index;
+  char *endptr = NULL;
+
+  /* Permit check. */
+  if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
+    permit = RMAP_PERMIT;
+  else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
+    permit = RMAP_DENY;
+  else
+    {
+      vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Preference check. */
+  pref = strtoul (argv[2], &endptr, 10);
+  if (pref == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "the fourth field must be positive integer%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (pref == 0 || pref > 65535)
+    {
+      vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get route map. */
+  map = route_map_get (argv[0]);
+  index = route_map_index_get (map, permit, pref);
+
+  vty->index = index;
+  vty->node = RMAP_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_route_map_all,
+       no_route_map_all_cmd,
+       "no route-map WORD",
+       NO_STR
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n")
+{
+  struct route_map *map;
+
+  map = route_map_lookup_by_name (argv[0]);
+  if (map == NULL)
+    {
+      vty_out (vty, "%% Could not find route-map %s%s",
+              argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  route_map_delete (map);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_route_map,
+       no_route_map_cmd,
+       "no route-map WORD (deny|permit) <1-65535>",
+       NO_STR
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n"
+       "Route map denies set operations\n"
+       "Route map permits set operations\n"
+       "Sequence to insert to/delete from existing route-map entry\n")
+{
+  int permit;
+  unsigned long pref;
+  struct route_map *map;
+  struct route_map_index *index;
+  char *endptr = NULL;
+
+  /* Permit check. */
+  if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
+    permit = RMAP_PERMIT;
+  else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
+    permit = RMAP_DENY;
+  else
+    {
+      vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Preference. */
+  pref = strtoul (argv[2], &endptr, 10);
+  if (pref == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "the fourth field must be positive integer%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (pref == 0 || pref > 65535)
+    {
+      vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Existence check. */
+  map = route_map_lookup_by_name (argv[0]);
+  if (map == NULL)
+    {
+      vty_out (vty, "%% Could not find route-map %s%s",
+              argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Lookup route map index. */
+  index = route_map_index_lookup (map, permit, pref);
+  if (index == NULL)
+    {
+      vty_out (vty, "%% Could not find route-map entry %s %s%s", 
+              argv[0], argv[2], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Delete index from route map. */
+  route_map_index_delete (index, 1);
+
+  /* If this route rule is the last one, delete route map itself. */
+  if (route_map_empty (map))
+    route_map_delete (map);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (rmap_onmatch_next,
+       rmap_onmatch_next_cmd,
+       "on-match next",
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+  struct route_map_index *index;
+
+  index = vty->index;
+
+  if (index)
+    index->exitpolicy = RMAP_NEXT;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rmap_onmatch_next,
+       no_rmap_onmatch_next_cmd,
+       "no on-match next",
+       NO_STR
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+  struct route_map_index *index;
+
+  index = vty->index;
+  
+  if (index)
+    index->exitpolicy = RMAP_EXIT;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (rmap_onmatch_goto,
+       rmap_onmatch_goto_cmd,
+       "on-match goto <1-65535>",
+       "Exit policy on matches\n"
+       "Goto Clause number\n"
+       "Number\n")
+{
+  struct route_map_index *index;
+  int d = 0;
+
+  if (argv[0])
+    d = atoi(argv[0]);
+
+  index = vty->index;
+  if (index)
+    {
+      if (d <= index->pref)
+       {
+         /* Can't allow you to do that, Dave */
+         vty_out (vty, "can't jump backwards in route-maps%s", 
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      else
+       {
+         index->exitpolicy = RMAP_GOTO;
+         index->nextpref = d;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rmap_onmatch_goto,
+       no_rmap_onmatch_goto_cmd,
+       "no on-match goto",
+       NO_STR
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+  struct route_map_index *index;
+
+  index = vty->index;
+
+  if (index)
+    index->exitpolicy = RMAP_EXIT;
+  
+  return CMD_SUCCESS;
+}
+
+/* Configuration write function. */
+int
+route_map_config_write (struct vty *vty)
+{
+  struct route_map *map;
+  struct route_map_index *index;
+  struct route_map_rule *rule;
+  int first = 1;
+  int write = 0;
+
+  for (map = route_map_master.head; map; map = map->next)
+    for (index = map->head; index; index = index->next)
+      {
+       if (!first)
+         vty_out (vty, "!%s", VTY_NEWLINE);
+       else
+         first = 0;
+
+       vty_out (vty, "route-map %s %s %d%s", 
+                map->name,
+                route_map_type_str (index->type),
+                index->pref, VTY_NEWLINE);
+
+       for (rule = index->match_list.head; rule; rule = rule->next)
+         vty_out (vty, " match %s %s%s", rule->cmd->str, 
+                  rule->rule_str ? rule->rule_str : "",
+                  VTY_NEWLINE);
+
+       for (rule = index->set_list.head; rule; rule = rule->next)
+         vty_out (vty, " set %s %s%s", rule->cmd->str,
+                  rule->rule_str ? rule->rule_str : "",
+                  VTY_NEWLINE);
+       if (index->exitpolicy == RMAP_GOTO)
+         vty_out (vty, " on-match goto %d%s", index->nextpref,
+                  VTY_NEWLINE);
+       if (index->exitpolicy == RMAP_NEXT)
+         vty_out (vty," on-match next%s", VTY_NEWLINE);
+       
+       write++;
+      }
+  return write;
+}
+
+/* Route map node structure. */
+struct cmd_node rmap_node =
+{
+  RMAP_NODE,
+  "%s(config-route-map)# ",
+  1
+};
+
+/* Initialization of route map vector. */
+void
+route_map_init_vty ()
+{
+  /* Install route map top node. */
+  install_node (&rmap_node, route_map_config_write);
+
+  /* Install route map commands. */
+  install_default (RMAP_NODE);
+  install_element (CONFIG_NODE, &route_map_cmd);
+  install_element (CONFIG_NODE, &no_route_map_cmd);
+  install_element (CONFIG_NODE, &no_route_map_all_cmd);
+
+  /* Install the on-match stuff */
+  install_element (RMAP_NODE, &route_map_cmd);
+  install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
+  install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
+  install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
+  install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
+}
diff --git a/lib/routemap.h b/lib/routemap.h
new file mode 100644 (file)
index 0000000..e37f1e7
--- /dev/null
@@ -0,0 +1,194 @@
+/* Route map function.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_ROUTEMAP_H
+#define _ZEBRA_ROUTEMAP_H
+
+/* Route map's type. */
+enum route_map_type
+{
+  RMAP_PERMIT,
+  RMAP_DENY,
+  RMAP_ANY
+};
+
+typedef enum 
+{
+  RMAP_MATCH,
+  RMAP_DENYMATCH,
+  RMAP_NOMATCH,
+  RMAP_ERROR,
+  RMAP_OKAY
+} route_map_result_t;
+
+typedef enum
+{
+  RMAP_RIP,
+  RMAP_RIPNG,
+  RMAP_OSPF,
+  RMAP_OSPF6,
+  RMAP_BGP
+} route_map_object_t;
+
+typedef enum
+{
+  RMAP_EXIT,
+  RMAP_GOTO,
+  RMAP_NEXT
+} route_map_end_t;
+
+typedef enum
+{
+  RMAP_EVENT_SET_ADDED,
+  RMAP_EVENT_SET_DELETED,
+  RMAP_EVENT_SET_REPLACED,
+  RMAP_EVENT_MATCH_ADDED,
+  RMAP_EVENT_MATCH_DELETED,
+  RMAP_EVENT_MATCH_REPLACED,
+  RMAP_EVENT_INDEX_ADDED,
+  RMAP_EVENT_INDEX_DELETED
+} route_map_event_t;
+
+/* Route map rule structure for matching and setting. */
+struct route_map_rule_cmd
+{
+  /* Route map rule name (e.g. as-path, metric) */
+  char *str;
+
+  /* Function for value set or match. */
+  route_map_result_t (*func_apply)(void *, struct prefix *, 
+                                  route_map_object_t, void *);
+
+  /* Compile argument and return result as void *. */
+  void *(*func_compile)(char *);
+
+  /* Free allocated value by func_compile (). */
+  void (*func_free)(void *);
+};
+
+/* Route map apply error. */
+enum
+{
+  /* Route map rule is missing. */
+  RMAP_RULE_MISSING = 1,
+
+  /* Route map rule can't compile */
+  RMAP_COMPILE_ERROR
+};
+
+/* Route map rule list. */
+struct route_map_rule_list
+{
+  struct route_map_rule *head;
+  struct route_map_rule *tail;
+};
+
+/* Route map index structure. */
+struct route_map_index
+{
+  struct route_map *map;
+
+  /* Preference of this route map rule. */
+  int pref;
+
+  /* Route map type permit or deny. */
+  enum route_map_type type;                    
+
+  /* Do we follow old rules, or hop forward? */
+  route_map_end_t exitpolicy;
+
+  /* If we're using "GOTO", to where do we go? */
+  int nextpref;
+
+  /* Matching rule list. */
+  struct route_map_rule_list match_list;
+  struct route_map_rule_list set_list;
+
+  /* Make linked list. */
+  struct route_map_index *next;
+  struct route_map_index *prev;
+};
+
+/* Route map list structure. */
+struct route_map
+{
+  /* Name of route map. */
+  char *name;
+
+  /* Route map's rule. */
+  struct route_map_index *head;
+  struct route_map_index *tail;
+
+  /* Make linked list. */
+  struct route_map *next;
+  struct route_map *prev;
+};
+
+/* Prototypes. */
+void route_map_init ();
+void route_map_init_vty ();
+
+/* Add match statement to route map. */
+int
+route_map_add_match (struct route_map_index *index,
+                    char *match_name,
+                    char *match_arg);
+
+/* Delete specified route match rule. */
+int
+route_map_delete_match (struct route_map_index *index,
+                       char *match_name,
+                       char *match_arg);
+
+/* Add route-map set statement to the route map. */
+int
+route_map_add_set (struct route_map_index *index, 
+                  char *set_name,
+                  char *set_arg);
+
+/* Delete route map set rule. */
+int
+route_map_delete_set (struct route_map_index *index, char *set_name,
+                      char *set_arg);
+
+/* Install rule command to the match list. */
+void
+route_map_install_match (struct route_map_rule_cmd *cmd);
+
+/* Install rule command to the set list. */
+void
+route_map_install_set (struct route_map_rule_cmd *cmd);
+
+/* Lookup route map by name. */
+struct route_map *
+route_map_lookup_by_name (char *name);
+
+/* Apply route map to the object. */
+route_map_result_t
+route_map_apply (struct route_map *map, struct prefix *, 
+                route_map_object_t object_type, void *object);
+
+void route_map_add_hook (void (*func) (char *));
+void route_map_delete_hook (void (*func) (char *));
+void route_map_event_hook (void (*func) (route_map_event_t, char *));
+
+
+#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/lib/smux.c b/lib/smux.c
new file mode 100644 (file)
index 0000000..32f8c8f
--- /dev/null
@@ -0,0 +1,1501 @@
+/* SNMP support
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "smux.h"
+#include "log.h"
+#include "thread.h"
+#include "linklist.h"
+#include "command.h"
+#include "version.h"
+#include "memory.h"
+#include "sockunion.h"
+
+#define min(A,B) ((A) < (B) ? (A) : (B))
+
+enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
+
+void smux_event (enum smux_event, int);
+\f
+
+/* SMUX socket. */
+int smux_sock = -1;
+
+/* SMUX subtree list. */
+struct list *treelist;
+
+/* SMUX oid. */
+oid *smux_oid;
+size_t smux_oid_len;
+
+/* SMUX default oid. */
+oid *smux_default_oid;
+size_t smux_default_oid_len;
+
+/* SMUX password. */
+char *smux_passwd;
+char *smux_default_passwd = "";
+
+/* SMUX read threads. */
+struct thread *smux_read_thread;
+
+/* SMUX connect thrads. */
+struct thread *smux_connect_thread;
+
+/* SMUX debug flag. */
+int debug_smux = 0;
+
+/* SMUX failure count. */
+int fail = 0;
+
+/* SMUX node. */
+struct cmd_node smux_node =
+{
+  SMUX_NODE,
+  ""                            /* SMUX has no interface. */
+};
+\f
+void *
+oid_copy (void *dest, void *src, size_t size)
+{
+  return memcpy (dest, src, size * sizeof (oid));
+}
+
+void
+oid2in_addr (oid oid[], int len, struct in_addr *addr)
+{
+  int i;
+  u_char *pnt;
+  
+  if (len == 0)
+    return;
+
+  pnt = (u_char *) addr;
+
+  for (i = 0; i < len; i++)
+    *pnt++ = oid[i];
+}
+
+void
+oid_copy_addr (oid oid[], struct in_addr *addr, int len)
+{
+  int i;
+  u_char *pnt;
+  
+  if (len == 0)
+    return;
+
+  pnt = (u_char *) addr;
+
+  for (i = 0; i < len; i++)
+    oid[i] = *pnt++;
+}
+
+int
+oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
+{
+  int i;
+
+  for (i = 0; i < min (o1_len, o2_len); i++)
+    {
+      if (o1[i] < o2[i])
+       return -1;
+      else if (o1[i] > o2[i])
+       return 1;
+    }
+  if (o1_len < o2_len)
+    return -1;
+  if (o1_len > o2_len)
+    return 1;
+
+  return 0;
+}
+
+int
+oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
+{
+  int i;
+
+  for (i = 0; i < min (o1_len, o2_len); i++)
+    {
+      if (o1[i] < o2[i])
+       return -1;
+      else if (o1[i] > o2[i])
+       return 1;
+    }
+  if (o1_len < o2_len)
+    return -1;
+
+  return 0;
+}
+\f
+void
+smux_oid_dump (char *prefix, oid *oid, size_t oid_len)
+{
+  int i;
+  int first = 1;
+  char buf[MAX_OID_LEN * 3];
+
+  buf[0] = '\0';
+
+  for (i = 0; i < oid_len; i++)
+    {
+      sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
+      first = 0;
+    }
+  zlog_info ("%s: %s", prefix, buf);
+}
+
+int
+smux_socket ()
+{
+  int ret;
+#ifdef HAVE_IPV6
+  struct addrinfo hints, *res0, *res;
+  int gai;
+#else
+  struct sockaddr_in serv;
+  struct servent *sp;
+#endif
+  int sock = 0;
+
+#ifdef HAVE_IPV6
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = PF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+  gai = getaddrinfo(NULL, "smux", &hints, &res0);
+  if (gai == EAI_SERVICE)
+    {
+      char servbuf[NI_MAXSERV];
+      sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
+      servbuf[sizeof (servbuf) - 1] = '\0';
+      gai = getaddrinfo(NULL, servbuf, &hints, &res0);
+    }
+  if (gai)
+    {
+      zlog_warn("Cannot locate loopback service smux");
+      return -1;
+    }
+  for(res=res0; res; res=res->ai_next)
+    {
+      if (res->ai_family != AF_INET 
+#ifdef HAVE_IPV6
+         && res->ai_family != AF_INET6
+#endif /* HAVE_IPV6 */
+         )
+       continue;
+
+      sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+      if (sock < 0)
+       continue;
+      sockopt_reuseaddr (sock);
+      sockopt_reuseport (sock);
+      ret = connect (sock, res->ai_addr, res->ai_addrlen);
+      if (ret < 0)
+       {
+         close(sock);
+         sock = -1;
+         continue;
+       }
+      break;
+    }
+  freeaddrinfo(res0);
+  if (sock < 0)
+    zlog_warn ("Can't connect to SNMP agent with SMUX");
+#else
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("Can't make socket for SNMP");
+      return -1;
+    }
+
+  memset (&serv, 0, sizeof (struct sockaddr_in));
+  serv.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  serv.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+  sp = getservbyname ("smux", "tcp");
+  if (sp != NULL) 
+    serv.sin_port = sp->s_port;
+  else
+    serv.sin_port = htons (SMUX_PORT_DEFAULT);
+
+  serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  sockopt_reuseaddr (sock);
+  sockopt_reuseport (sock);
+
+  ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
+  if (ret < 0)
+    {
+      close (sock);
+      smux_sock = -1;
+      zlog_warn ("Can't connect to SNMP agent with SMUX");
+      return -1;
+    }
+#endif
+  return sock;
+}
+
+void
+smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
+                  long errindex, u_char val_type, void *arg, size_t arg_len)
+{
+  int ret;
+  u_char buf[BUFSIZ];
+  u_char *ptr, *h1, *h1e, *h2, *h2e;
+  int len, length;
+
+  ptr = buf;
+  len = BUFSIZ;
+  length = len;
+
+  if (debug_smux)
+    {
+      zlog_info ("SMUX GETRSP send");
+      zlog_info ("SMUX GETRSP reqid: %ld", reqid);
+    }
+
+  h1 = ptr;
+  /* Place holder h1 for complete sequence */
+  ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
+  h1e = ptr;
+  ptr = asn_build_int (ptr, &len,
+                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                      &reqid, sizeof (reqid));
+
+  if (debug_smux)
+    zlog_info ("SMUX GETRSP errstat: %ld", errstat);
+
+  ptr = asn_build_int (ptr, &len,
+                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                      &errstat, sizeof (errstat));
+  if (debug_smux)
+    zlog_info ("SMUX GETRSP errindex: %ld", errindex);
+
+  ptr = asn_build_int (ptr, &len,
+                      (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                      &errindex, sizeof (errindex));
+
+  h2 = ptr;
+  /* Place holder h2 for one variable */
+  ptr = asn_build_sequence (ptr, &len, 
+                          (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+                          0);
+  h2e = ptr;
+
+  ptr = snmp_build_var_op (ptr, objid, &objid_len, 
+                          val_type, arg_len, arg, &len);
+
+  /* Now variable size is known, fill in size */
+  asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
+
+  /* Fill in size of whole sequence */
+  asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
+
+  if (debug_smux)
+    zlog_info ("SMUX getresp send: %d", ptr - buf);
+  
+  ret = send (smux_sock, buf, (ptr - buf), 0);
+}
+
+char *
+smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
+          size_t *var_val_len,
+          u_char *var_val_type,
+          void **var_value)
+{
+  u_char type;
+  u_char val_type;
+  size_t val_len;
+  u_char *val;
+
+  if (debug_smux)
+    zlog_info ("SMUX var parse: len %d", len);
+
+  /* Parse header. */
+  ptr = asn_parse_header (ptr, &len, &type);
+  
+  if (debug_smux)
+    {
+      zlog_info ("SMUX var parse: type %d len %d", type, len);
+      zlog_info ("SMUX var parse: type must be %d", 
+                (ASN_SEQUENCE | ASN_CONSTRUCTOR));
+    }
+
+  /* Parse var option. */
+  *objid_len = MAX_OID_LEN;
+  ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, 
+                         &val_len, &val, &len);
+
+  if (var_val_len)
+    *var_val_len = val_len;
+
+  if (var_value)
+    *var_value = (void*) val;
+
+  if (var_val_type)
+    *var_val_type = val_type;
+
+  /* Requested object id length is objid_len. */
+  if (debug_smux)
+    smux_oid_dump ("Request OID", objid, *objid_len);
+
+  if (debug_smux)
+    zlog_info ("SMUX val_type: %d", val_type);
+
+  /* Check request value type. */
+  if (debug_smux)
+  switch (val_type)
+    {
+    case ASN_NULL:
+      /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
+         ASN_NULL. */
+      zlog_info ("ASN_NULL");
+      break;
+
+    case ASN_INTEGER:
+      zlog_info ("ASN_INTEGER");
+      break;
+    case ASN_COUNTER:
+    case ASN_GAUGE:
+    case ASN_TIMETICKS:
+    case ASN_UINTEGER:
+      zlog_info ("ASN_COUNTER");
+      break;
+    case ASN_COUNTER64:
+      zlog_info ("ASN_COUNTER64");
+      break;
+    case ASN_IPADDRESS:
+      zlog_info ("ASN_IPADDRESS");
+      break;
+    case ASN_OCTET_STR:
+      zlog_info ("ASN_OCTET_STR");
+      break;
+    case ASN_OPAQUE:
+    case ASN_NSAP:
+    case ASN_OBJECT_ID:
+      zlog_info ("ASN_OPAQUE");
+      break;
+    case SNMP_NOSUCHOBJECT:
+      zlog_info ("SNMP_NOSUCHOBJECT");
+      break;
+    case SNMP_NOSUCHINSTANCE:
+      zlog_info ("SNMP_NOSUCHINSTANCE");
+      break;
+    case SNMP_ENDOFMIBVIEW:
+      zlog_info ("SNMP_ENDOFMIBVIEW");
+      break;
+    case ASN_BIT_STR:
+      zlog_info ("ASN_BIT_STR");
+      break;
+    default:
+      zlog_info ("Unknown type");
+      break;
+    }
+  return ptr;
+}
+
+/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
+   ucd-snmp smux and as such suppose, that the peer receives in the message
+   only one variable. Fortunately, IBM seems to do the same in AIX. */
+
+int
+smux_set (oid *reqid, size_t *reqid_len,
+          u_char val_type, void *val, size_t val_len, int action)
+{
+  int j;
+  struct subtree *subtree;
+  struct variable *v;
+  int subresult;
+  oid *suffix;
+  int suffix_len;
+  int result;
+  u_char *statP = NULL;
+  WriteMethod *write_method = NULL;
+  struct listnode *node;
+
+  /* Check */
+  for (node = treelist->head; node; node = node->next)
+    {
+      subtree = node->data;
+      subresult = oid_compare_part (reqid, *reqid_len,
+                                    subtree->name, subtree->name_len);
+
+      /* Subtree matched. */
+      if (subresult == 0)
+        {
+          /* Prepare suffix. */
+          suffix = reqid + subtree->name_len;
+          suffix_len = *reqid_len - subtree->name_len;
+          result = subresult;
+
+          /* Check variables. */
+          for (j = 0; j < subtree->variables_num; j++)
+            {
+              v = &subtree->variables[j];
+
+              /* Always check suffix */
+              result = oid_compare_part (suffix, suffix_len,
+                                         v->name, v->namelen);
+
+              /* This is exact match so result must be zero. */
+              if (result == 0)
+                {
+                  if (debug_smux)
+                    zlog_info ("SMUX function call index is %d", v->magic);
+                 
+                  statP = (*v->findVar) (v, suffix, &suffix_len, 1,
+                                        &val_len, &write_method);
+
+                  if (write_method)
+                    {
+                      return (*write_method)(action, val, val_type, val_len,
+                                            statP, suffix, suffix_len, v);
+                    }
+                  else
+                    {
+                      return SNMP_ERR_READONLY;
+                    }
+                }
+
+              /* If above execution is failed or oid is small (so
+                 there is no further match). */
+              if (result < 0)
+                return SNMP_ERR_NOSUCHNAME;
+            }
+        }
+    }
+  return SNMP_ERR_NOSUCHNAME;
+}
+
+int
+smux_get (oid *reqid, size_t *reqid_len, int exact, 
+         u_char *val_type,void **val, size_t *val_len)
+{
+  int j;
+  struct subtree *subtree;
+  struct variable *v;
+  int subresult;
+  oid *suffix;
+  int suffix_len;
+  int result;
+  WriteMethod *write_method=NULL;
+  struct listnode *node;
+
+  /* Check */
+  for (node = treelist->head; node; node = node->next)
+    {
+      subtree = node->data;
+      subresult = oid_compare_part (reqid, *reqid_len, 
+                                   subtree->name, subtree->name_len);
+
+      /* Subtree matched. */
+      if (subresult == 0)
+       {
+         /* Prepare suffix. */
+         suffix = reqid + subtree->name_len;
+         suffix_len = *reqid_len - subtree->name_len;
+         result = subresult;
+
+         /* Check variables. */
+         for (j = 0; j < subtree->variables_num; j++)
+           {
+             v = &subtree->variables[j];
+
+             /* Always check suffix */
+             result = oid_compare_part (suffix, suffix_len,
+                                        v->name, v->namelen);
+
+             /* This is exact match so result must be zero. */
+             if (result == 0)
+               {
+                 if (debug_smux)
+                   zlog_info ("SMUX function call index is %d", v->magic);
+
+                 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
+                                       val_len, &write_method);
+
+                 /* There is no instance. */
+                 if (*val == NULL)
+                   return SNMP_NOSUCHINSTANCE;
+
+                 /* Call is suceed. */
+                 *val_type = v->type;
+
+                 return 0;
+               }
+
+             /* If above execution is failed or oid is small (so
+                 there is no further match). */
+             if (result < 0)
+               return SNMP_ERR_NOSUCHNAME;
+           }
+       }
+    }
+  return SNMP_ERR_NOSUCHNAME;
+}
+
+int
+smux_getnext (oid *reqid, size_t *reqid_len, int exact, 
+             u_char *val_type,void **val, size_t *val_len)
+{
+  int j;
+  oid save[MAX_OID_LEN];
+  int savelen = 0;
+  struct subtree *subtree;
+  struct variable *v;
+  int subresult;
+  oid *suffix;
+  int suffix_len;
+  int result;
+  WriteMethod *write_method=NULL;
+  struct listnode *node;
+
+
+  /* Save incoming request. */
+  oid_copy (save, reqid, *reqid_len);
+  savelen = *reqid_len;
+
+  /* Check */
+  for (node = treelist->head; node; node = node->next)
+    {
+      subtree = node->data;
+      subresult = oid_compare_part (reqid, *reqid_len, 
+                                   subtree->name, subtree->name_len);
+
+      /* If request is in the tree. The agent has to make sure we
+         only receive requests we have registered for. */
+      /* Unfortunately, that's not true. In fact, a SMUX subagent has to
+         behave as if it manages the whole SNMP MIB tree itself. It's the
+         duty of the master agent to collect the best answer and return it
+         to the manager. See RFC 1227 chapter 3.1.6 for the glory details
+         :-). ucd-snmp really behaves bad here as it actually might ask
+         multiple times for the same GETNEXT request as it throws away the
+         answer when it expects it in a different subtree and might come
+         back later with the very same request. --jochen */
+
+      if (subresult <= 0)
+       {
+         /* Prepare suffix. */
+         suffix = reqid + subtree->name_len;
+         suffix_len = *reqid_len - subtree->name_len;
+         if (subresult < 0)
+           {
+             oid_copy(reqid, subtree->name, subtree->name_len);
+             *reqid_len = subtree->name_len;
+           }
+         for (j = 0; j < subtree->variables_num; j++)
+           {
+             result = subresult;
+             v = &subtree->variables[j];
+
+             /* Next then check result >= 0. */
+             if (result == 0)
+               result = oid_compare_part (suffix, suffix_len,
+                                          v->name, v->namelen);
+
+             if (result <= 0)
+               {
+                 if (debug_smux)
+                   zlog_info ("SMUX function call index is %d", v->magic);
+                 if(result<0)
+                   {
+                     oid_copy(suffix, v->name, v->namelen);
+                     suffix_len = v->namelen;
+                   }
+                 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
+                                       val_len, &write_method);
+                 *reqid_len = suffix_len + subtree->name_len;
+                 if (*val)
+                   {
+                     *val_type = v->type;
+                     return 0;
+                   }
+               }
+           }
+       }
+    }
+  memcpy (reqid, save, savelen * sizeof(oid));
+  *reqid_len = savelen;
+
+  return SNMP_ERR_NOSUCHNAME;
+}
+
+/* GET message header. */
+char *
+smux_parse_get_header (char *ptr, size_t *len, long *reqid)
+{
+  u_char type;
+  long errstat;
+  long errindex;
+
+  /* Request ID. */
+  ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
+
+  if (debug_smux)
+    zlog_info ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
+
+  /* Error status. */
+  ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
+
+  if (debug_smux)
+    zlog_info ("SMUX GET errstat %ld len: %d", errstat, *len);
+
+  /* Error index. */
+  ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
+
+  if (debug_smux)
+    zlog_info ("SMUX GET errindex %ld len: %d", errindex, *len);
+
+  return ptr;
+}
+
+void
+smux_parse_set (char *ptr, size_t len, int action)
+{
+  long reqid;
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+  u_char val_type;
+  void *val;
+  size_t val_len;
+  int ret;
+
+  if (debug_smux)
+    zlog_info ("SMUX SET(%s) message parse: len %d",
+               (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
+               len);
+
+  /* Parse SET message header. */
+  ptr = smux_parse_get_header (ptr, &len, &reqid);
+
+  /* Parse SET message object ID. */
+  ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
+
+  ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
+  if (debug_smux)
+    zlog_info ("SMUX SET ret %d", ret);
+
+  /* Return result. */
+  if (RESERVE1 == action)
+    smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
+}
+
+void
+smux_parse_get (char *ptr, size_t len, int exact)
+{
+  long reqid;
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+  u_char val_type;
+  void *val;
+  size_t val_len;
+  int ret;
+
+  if (debug_smux)
+    zlog_info ("SMUX GET message parse: len %d", len);
+  
+  /* Parse GET message header. */
+  ptr = smux_parse_get_header (ptr, &len, &reqid);
+  
+  /* Parse GET message object ID. We needn't the value come */
+  ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
+
+  /* Traditional getstatptr. */
+  if (exact)
+    ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
+  else
+    ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
+
+  /* Return result. */
+  if (ret == 0)
+    smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
+  else
+    smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
+}
+
+/* Parse SMUX_CLOSE message. */
+void
+smux_parse_close (char *ptr, int len)
+{
+  long reason = 0;
+
+  while (len--)
+    {
+      reason = (reason << 8) | (long) *ptr;
+      ptr++;
+    }
+  zlog_info ("SMUX_CLOSE with reason: %ld", reason);
+}
+
+/* SMUX_RRSP message. */
+void
+smux_parse_rrsp (char *ptr, int len)
+{
+  char val;
+  long errstat;
+  
+  ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
+
+  if (debug_smux)
+    zlog_info ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
+}
+
+/* Parse SMUX message. */
+int
+smux_parse (char *ptr, int len)
+{
+  /* This buffer we'll use for SOUT message. We could allocate it with
+     malloc and save only static pointer/lenght, but IMHO static
+     buffer is a faster solusion. */
+  static u_char sout_save_buff[SMUXMAXPKTSIZE];
+  static int sout_save_len = 0;
+
+  int len_income = len; /* see note below: YYY */
+  u_char type;
+  u_char rollback;
+
+  rollback = ptr[2]; /* important only for SMUX_SOUT */
+
+process_rest: /* see note below: YYY */
+
+  /* Parse SMUX message type and subsequent length. */
+  ptr = asn_parse_header (ptr, &len, &type);
+
+  if (debug_smux)
+    zlog_info ("SMUX message received type: %d rest len: %d", type, len);
+
+  switch (type)
+    {
+    case SMUX_OPEN:
+      /* Open must be not send from SNMP agent. */
+      zlog_warn ("SMUX_OPEN received: resetting connection.");
+      return -1;
+      break;
+    case SMUX_RREQ:
+      /* SMUX_RREQ message is invalid for us. */
+      zlog_warn ("SMUX_RREQ received: resetting connection.");
+      return -1;
+      break;
+    case SMUX_SOUT:
+      /* SMUX_SOUT message is now valied for us. */
+      if (debug_smux)
+        zlog_info ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
+
+      if (sout_save_len > 0)
+        {
+          smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
+          sout_save_len = 0;
+        }
+      else
+        zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
+
+      if (len_income > 3) 
+        {
+          /* YYY: this strange code has to solve the "slow peer"
+             problem: When agent sends SMUX_SOUT message it doesn't
+             wait any responce and may send some next message to
+             subagent. Then the peer in 'smux_read()' will recieve
+             from socket the 'concatenated' buffer, contaning both
+             SMUX_SOUT message and the next one
+             (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
+             the buffer is longer than 3 ( length of SMUX_SOUT ), we
+             must process the rest of it.  This effect may be observed
+             if 'debug_smux' is set to '1' */
+          ptr++;
+          len = len_income - 3;
+          goto process_rest;
+        }
+      break;
+    case SMUX_GETRSP:
+      /* SMUX_GETRSP message is invalid for us. */
+      zlog_warn ("SMUX_GETRSP received: resetting connection.");
+      return -1;
+      break;
+    case SMUX_CLOSE:
+      /* Close SMUX connection. */
+      if (debug_smux)
+       zlog_info ("SMUX_CLOSE");
+      smux_parse_close (ptr, len);
+      return -1;
+      break;
+    case SMUX_RRSP:
+      /* This is response for register message. */
+      if (debug_smux)
+       zlog_info ("SMUX_RRSP");
+      smux_parse_rrsp (ptr, len);
+      break;
+    case SMUX_GET:
+      /* Exact request for object id. */
+      if (debug_smux)
+       zlog_info ("SMUX_GET");
+      smux_parse_get (ptr, len, 1);
+      break;
+    case SMUX_GETNEXT:
+      /* Next request for object id. */
+      if (debug_smux)
+       zlog_info ("SMUX_GETNEXT");
+      smux_parse_get (ptr, len, 0);
+      break;
+    case SMUX_SET:
+      /* SMUX_SET is supported with some limitations. */
+      if (debug_smux)
+       zlog_info ("SMUX_SET");
+
+      /* save the data for future SMUX_SOUT */
+      memcpy (sout_save_buff, ptr, len);
+      sout_save_len = len;
+      smux_parse_set (ptr, len, RESERVE1);
+      break;
+    default:
+      zlog_info ("Unknown type: %d", type);
+      break;
+    }
+  return 0;
+}
+
+/* SMUX message read function. */
+int
+smux_read (struct thread *t)
+{
+  int sock;
+  int len;
+  u_char buf[SMUXMAXPKTSIZE];
+  int ret;
+
+  /* Clear thread. */
+  sock = THREAD_FD (t);
+  smux_read_thread = NULL;
+
+  if (debug_smux)
+    zlog_info ("SMUX read start");
+
+  /* Read message from SMUX socket. */
+  len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
+
+  if (len < 0)
+    {
+      zlog_warn ("Can't read all SMUX packet: %s", strerror (errno));
+      close (sock);
+      smux_sock = -1;
+      smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  if (len == 0)
+    {
+      zlog_warn ("SMUX connection closed: %d", sock);
+      close (sock);
+      smux_sock = -1;
+      smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  if (debug_smux)
+    zlog_info ("SMUX read len: %d", len);
+
+  /* Parse the message. */
+  ret = smux_parse (buf, len);
+
+  if (ret < 0)
+    {
+      close (sock);
+      smux_sock = -1;
+      smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  /* Regiser read thread. */
+  smux_event (SMUX_READ, sock);
+
+  return 0;
+}
+
+int
+smux_open (int sock)
+{
+  u_char buf[BUFSIZ];
+  u_char *ptr;
+  int len;
+  u_long version;
+  u_char progname[] = "zebra-" ZEBRA_VERSION;
+
+  if (debug_smux)
+    {
+      smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
+      zlog_info ("SMUX open progname: %s", progname);
+      zlog_info ("SMUX open password: %s", smux_passwd);
+    }
+
+  ptr = buf;
+  len = BUFSIZ;
+
+  /* SMUX Header.  As placeholder. */
+  ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
+
+  /* SMUX Open. */
+  version = 0;
+  ptr = asn_build_int (ptr, &len, 
+                      (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                      &version, sizeof (u_long));
+
+  /* SMUX connection oid. */
+  ptr = asn_build_objid (ptr, &len,
+                        (u_char) 
+                        (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+                        smux_oid, smux_oid_len);
+
+  /* SMUX connection description. */
+  ptr = asn_build_string (ptr, &len, 
+                         (u_char)
+                         (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
+                         progname, strlen (progname));
+
+  /* SMUX connection password. */
+  ptr = asn_build_string (ptr, &len, 
+                         (u_char)
+                         (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
+                         smux_passwd, strlen (smux_passwd));
+
+  /* Fill in real SMUX header.  We exclude ASN header size (2). */
+  len = BUFSIZ;
+  asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
+
+  return send (sock, buf, (ptr - buf), 0);
+}
+
+int
+smux_trap (oid *name, size_t namelen,
+          oid *iname, size_t inamelen,
+          struct trap_object *trapobj, size_t trapobjlen,
+          unsigned int tick)
+{
+  int i;
+  u_char buf[BUFSIZ];
+  u_char *ptr;
+  int len, length;
+  struct in_addr addr;
+  unsigned long val;
+  u_char *h1, *h1e;
+
+  ptr = buf;
+  len = BUFSIZ;
+  length = len;
+
+  /* When SMUX connection is not established. */
+  if (smux_sock < 0)
+    return 0;
+
+  /* SMUX header. */
+  ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
+
+  /* Sub agent enterprise oid. */
+  ptr = asn_build_objid (ptr, &len,
+                        (u_char) 
+                        (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+                        smux_oid, smux_oid_len);
+
+  /* IP address. */
+  addr.s_addr = 0;
+  ptr = asn_build_string (ptr, &len, 
+                         (u_char)
+                         (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
+                         (u_char *)&addr, sizeof (struct in_addr));
+
+  /* Generic trap integer. */
+  val = SNMP_TRAP_ENTERPRISESPECIFIC;
+  ptr = asn_build_int (ptr, &len, 
+                      (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                      &val, sizeof (int));
+
+  /* Specific trap integer. */
+  val = 2;
+  ptr = asn_build_int (ptr, &len, 
+                      (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                      &val, sizeof (int));
+
+  /* Timeticks timestamp. */
+  val = 0;
+  ptr = asn_build_unsigned_int (ptr, &len, 
+                               (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
+                               &val, sizeof (int));
+  
+  /* Variables. */
+  h1 = ptr;
+  ptr = asn_build_sequence (ptr, &len, 
+                           (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
+                           0);
+
+
+  /* Iteration for each objects. */
+  h1e = ptr;
+  for (i = 0; i < trapobjlen; i++)
+    {
+      int ret;
+      oid oid[MAX_OID_LEN];
+      size_t oid_len;
+      void *val;
+      size_t val_len;
+      u_char val_type;
+
+      /* Make OID. */
+      oid_copy (oid, name, namelen);
+      oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
+      oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
+      oid_len = namelen + trapobj[i].namelen + inamelen;
+
+      if (debug_smux)
+       smux_oid_dump ("Trap", oid, oid_len);
+
+      ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
+
+      if (debug_smux)
+       zlog_info ("smux_get result %d", ret);
+
+      if (ret == 0)
+       ptr = snmp_build_var_op (ptr, oid, &oid_len,
+                                val_type, val_len, val, &len);
+    }
+
+  /* Now variable size is known, fill in size */
+  asn_build_sequence(h1, &length,
+                    (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
+                    ptr - h1e);
+
+  /* Fill in size of whole sequence */
+  len = BUFSIZ;
+  asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
+
+  return send (smux_sock, buf, (ptr - buf), 0);
+}
+
+int
+smux_register (int sock)
+{
+  u_char buf[BUFSIZ];
+  u_char *ptr;
+  int len, ret;
+  long priority;
+  long operation;
+  struct subtree *subtree;
+  struct listnode *node;
+
+  ret = 0;
+
+  for (node = treelist->head; node; node = node->next)
+    {
+      ptr = buf;
+      len = BUFSIZ;
+
+      subtree = node->data;
+
+      /* SMUX RReq Header. */
+      ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
+
+      /* Register MIB tree. */
+      ptr = asn_build_objid (ptr, &len,
+                           (u_char)
+                           (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+                           subtree->name, subtree->name_len);
+
+      /* Priority. */
+      priority = -1;
+      ptr = asn_build_int (ptr, &len, 
+                         (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                         &priority, sizeof (u_long));
+
+      /* Operation. */
+      operation = 2; /* Register R/W */
+      ptr = asn_build_int (ptr, &len, 
+                         (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                         &operation, sizeof (u_long));
+
+      if (debug_smux)
+        {
+          smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
+          zlog_info ("SMUX register priority: %ld", priority);
+          zlog_info ("SMUX register operation: %ld", operation);
+        }
+
+      len = BUFSIZ;
+      asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
+      ret = send (sock, buf, (ptr - buf), 0);
+      if (ret < 0)
+        return ret;
+    }
+  return ret;
+}
+
+/* Try to connect to SNMP agent. */
+int
+smux_connect (struct thread *t)
+{
+  int ret;
+
+  if (debug_smux)
+    zlog_info ("SMUX connect try %d", fail + 1);
+
+  /* Clear thread poner of myself. */
+  smux_connect_thread = NULL;
+
+  /* Make socket.  Try to connect. */
+  smux_sock = smux_socket ();
+  if (smux_sock < 0)
+    {
+      if (++fail < SMUX_MAX_FAILURE)
+       smux_event (SMUX_CONNECT, 0);
+      return 0;
+    }
+
+  /* Send OPEN PDU. */
+  ret = smux_open (smux_sock);
+  if (ret < 0)
+    {
+      zlog_warn ("SMUX open message send failed: %s", strerror (errno));
+      close (smux_sock);
+      smux_sock = -1;
+      if (++fail < SMUX_MAX_FAILURE)
+       smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  /* Send any outstanding register PDUs. */
+  ret = smux_register (smux_sock);
+  if (ret < 0)
+    {
+      zlog_warn ("SMUX register message send failed: %s", strerror (errno));
+      close (smux_sock);
+      smux_sock = -1;
+      if (++fail < SMUX_MAX_FAILURE)
+       smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  /* Everything goes fine. */
+  smux_event (SMUX_READ, smux_sock);
+
+  return 0;
+}
+
+/* Clear all SMUX related resources. */
+void
+smux_stop ()
+{
+  if (smux_read_thread)
+    thread_cancel (smux_read_thread);
+  if (smux_connect_thread)
+    thread_cancel (smux_connect_thread);
+
+  if (smux_sock >= 0)
+    {
+      close (smux_sock);
+      smux_sock = -1;
+    }
+}
+\f
+extern struct thread_master *master;
+
+void
+smux_event (enum smux_event event, int sock)
+{
+  switch (event)
+    {
+    case SMUX_SCHEDULE:
+      smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
+      break;
+    case SMUX_CONNECT:
+      smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
+      break;
+    case SMUX_READ:
+      smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
+      break;
+    default:
+      break;
+    }
+}
+\f
+int
+smux_str2oid (char *str, oid *oid, size_t *oid_len)
+{
+  int len;
+  int val;
+
+  len = 0;
+  val = 0;
+  *oid_len = 0;
+
+  if (*str == '.')
+    str++;
+  if (*str == '\0')
+    return 0;
+
+  while (1)
+    {
+      if (! isdigit (*str))
+       return -1;
+
+      while (isdigit (*str))
+       {
+         val *= 10;
+         val += (*str - '0');
+         str++;
+       }
+
+      if (*str == '\0')
+       break;
+      if (*str != '.')
+       return -1;
+
+      oid[len++] = val;
+      val = 0;
+      str++;
+    }
+
+  oid[len++] = val;
+  *oid_len = len;
+
+  return 0;
+}
+
+oid *
+smux_oid_dup (oid *objid, size_t objid_len)
+{
+  oid *new;
+
+  new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
+  oid_copy (new, objid, objid_len);
+
+  return new;
+}
+
+int
+smux_peer_oid (struct vty *vty, char *oid_str, char *passwd_str)
+{
+  int ret;
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+
+  ret = smux_str2oid (oid_str, oid, &oid_len);
+  if (ret != 0)
+    {
+      vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (smux_oid && smux_oid != smux_default_oid)
+    free (smux_oid);
+
+  if (smux_passwd && smux_passwd != smux_default_passwd)
+    {
+      free (smux_passwd);
+      smux_passwd = NULL;
+    }
+
+  smux_oid = smux_oid_dup (oid, oid_len);
+  smux_oid_len = oid_len;
+
+  if (passwd_str)
+    smux_passwd = strdup (passwd_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
+                    size_t *var_len, WriteMethod **write_method)
+{
+  oid fulloid[MAX_OID_LEN];
+  int ret;
+
+  oid_copy (fulloid, v->name, v->namelen);
+  fulloid[v->namelen] = 0;
+  /* Check against full instance. */
+  ret = oid_compare (name, *length, fulloid, v->namelen + 1);
+
+  /* Check single instance. */
+  if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
+       return MATCH_FAILED;
+
+  /* In case of getnext, fill in full instance. */
+  memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
+  *length = v->namelen + 1;
+
+  *write_method = 0;
+  *var_len = sizeof(long);    /* default to 'long' results */
+
+  return MATCH_SUCCEEDED;
+}
+
+int
+smux_peer_default ()
+{
+  if (smux_oid != smux_default_oid)
+    {
+      free (smux_oid);
+      smux_oid = smux_default_oid;
+      smux_oid_len = smux_default_oid_len;
+    }
+  if (smux_passwd != smux_default_passwd)
+    {
+      free (smux_passwd);
+      smux_passwd = smux_default_passwd;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (smux_peer,
+       smux_peer_cmd,
+       "smux peer OID",
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "Object ID used in SMUX peering\n")
+{
+  return smux_peer_oid (vty, argv[0], NULL);
+}
+
+DEFUN (smux_peer_password,
+       smux_peer_password_cmd,
+       "smux peer OID PASSWORD",
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "SMUX peering object ID\n"
+       "SMUX peering password\n")
+{
+  return smux_peer_oid (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_smux_peer,
+       no_smux_peer_cmd,
+       "no smux peer OID",
+       NO_STR
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "Object ID used in SMUX peering\n")
+{
+  return smux_peer_default ();
+}
+
+DEFUN (no_smux_peer_password,
+       no_smux_peer_password_cmd,
+       "no smux peer OID PASSWORD",
+       NO_STR
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "SMUX peering object ID\n"
+       "SMUX peering password\n")
+{
+  return smux_peer_default ();
+}
+
+int
+config_write_smux (struct vty *vty)
+{
+  int first = 1;
+  int i;
+
+  if (smux_oid != smux_default_oid || smux_passwd != smux_default_passwd)
+    {
+      vty_out (vty, "smux peer ");
+      for (i = 0; i < smux_oid_len; i++)
+       {
+         vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
+         first = 0;
+       }
+      vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
+    }
+  return 0;
+}
+
+/* Register subtree to smux master tree. */
+void
+smux_register_mib (char *descr, struct variable *var, size_t width, int num, 
+                  oid name[], size_t namelen)
+{
+  struct subtree *tree;
+
+  tree = (struct subtree *)malloc(sizeof(struct subtree));
+  oid_copy (tree->name, name, namelen);
+  tree->name_len = namelen;
+  tree->variables = var;
+  tree->variables_num = num;
+  tree->variables_width = width;
+  tree->registered = 0;
+  listnode_add_sort(treelist, tree);
+}
+
+void
+smux_reset ()
+{
+  /* Setting configuration to default. */
+  smux_peer_default ();
+}
+
+/* Compare function to keep treelist sorted */
+static int
+smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
+{
+  return oid_compare(tree1->name, tree1->name_len, 
+                    tree2->name, tree2->name_len);
+}
+
+/* Initialize some values then schedule first SMUX connection. */
+void
+smux_init (oid defoid[], size_t defoid_len)
+{
+  /* Set default SMUX oid. */
+  smux_default_oid = defoid;
+  smux_default_oid_len = defoid_len;
+
+  smux_oid = smux_default_oid;
+  smux_oid_len = smux_default_oid_len;
+  smux_passwd = smux_default_passwd;
+  
+  /* Make MIB tree. */
+  treelist = list_new();
+  treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
+
+  /* Install commands. */
+  install_node (&smux_node, config_write_smux);
+
+  install_element (CONFIG_NODE, &smux_peer_cmd);
+  install_element (CONFIG_NODE, &smux_peer_password_cmd);
+  install_element (CONFIG_NODE, &no_smux_peer_cmd);
+  install_element (CONFIG_NODE, &no_smux_peer_password_cmd);
+}
+
+void
+smux_start(void)
+{
+  /* Schedule first connection. */
+  smux_event (SMUX_SCHEDULE, 0);
+}
+#endif /* HAVE_SNMP */
diff --git a/lib/smux.h b/lib/smux.h
new file mode 100644 (file)
index 0000000..91c3d46
--- /dev/null
@@ -0,0 +1,159 @@
+/* SNMP support
+ * Copyright (C) 1999 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.  
+ */
+
+#ifndef _ZEBRA_SNMP_H
+#define _ZEBRA_SNMP_H
+
+#define SMUX_PORT_DEFAULT 199
+
+#define SMUXMAXPKTSIZE    1500
+#define SMUXMAXSTRLEN      256
+
+#define SMUX_OPEN       (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
+#define SMUX_CLOSE      (ASN_APPLICATION | ASN_PRIMITIVE | 1)
+#define SMUX_RREQ       (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
+#define SMUX_RRSP       (ASN_APPLICATION | ASN_PRIMITIVE | 3)
+#define SMUX_SOUT       (ASN_APPLICATION | ASN_PRIMITIVE | 4)
+
+#define SMUX_GET        (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
+#define SMUX_GETNEXT    (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
+#define SMUX_GETRSP     (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
+#define SMUX_SET       (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
+#define SMUX_TRAP      (ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
+
+#define SMUX_MAX_FAILURE 3
+
+/* Structures here are mostly compatible with UCD SNMP 4.1.1 */
+#define MATCH_FAILED     (-1)
+#define MATCH_SUCCEEDED  0
+
+/* SYNTAX TruthValue from SNMPv2-TC. */
+#define SNMP_TRUE  1
+#define SNMP_FALSE 2
+
+/* SYNTAX RowStatus from SNMPv2-TC. */
+#define SNMP_VALID  1
+#define SNMP_INVALID 2
+
+#define IN_ADDR_SIZE sizeof(struct in_addr)
+
+struct variable;
+
+#define REGISTER_MIB(descr, var, vartype, theoid)              \
+    smux_register_mib(descr, (struct variable *)var, sizeof(struct vartype), \
+    sizeof(var)/sizeof(struct vartype),                        \
+    theoid, sizeof(theoid)/sizeof(oid))
+
+typedef int (WriteMethod)(int action,
+                         u_char  *var_val,
+                         u_char   var_val_type,
+                         size_t   var_val_len,
+                         u_char  *statP,
+                         oid     *name,
+                         size_t   length,
+                         struct variable *v);
+
+typedef u_char *(FindVarMethod)(struct variable *v,
+                               oid     *name,
+                               size_t  *length,
+                               int      exact,
+                               size_t  *var_len,
+                               WriteMethod   **write_method);
+
+/* SNMP variable */
+struct variable
+{
+  /* Index of the MIB.*/
+  u_char magic;
+
+  /* Type of variable. */
+  char type;
+
+  /* Access control list. */
+  u_short acl;
+
+  /* Callback function. */
+  FindVarMethod *findVar;
+
+  /* Suffix of the MIB. */
+  u_char namelen;
+  oid name[MAX_OID_LEN];
+};
+
+/* SNMP tree. */
+struct subtree
+{
+  /* Tree's oid. */
+  oid name[MAX_OID_LEN];
+  u_char name_len;
+
+  /* List of the variables. */
+  struct variable *variables;
+
+  /* Length of the variables list. */
+  int variables_num;
+
+  /* Width of the variables list. */
+  int variables_width;
+
+  /* Registered flag. */
+  int registered;
+};
+
+struct trap_object
+{
+  FindVarMethod *findVar;
+  u_char namelen;
+  oid name[MAX_OID_LEN];
+};
+
+/* Declare SMUX return value. */
+#define SNMP_LOCAL_VARIABLES \
+  static int32_t snmp_int_val; \
+  static struct in_addr snmp_in_addr_val;
+
+#define SNMP_INTEGER(V) \
+  ( \
+    *var_len = sizeof (int32_t), \
+    snmp_int_val = V, \
+    (u_char *) &snmp_int_val \
+  )
+
+#define SNMP_IPADDRESS(V) \
+  ( \
+    *var_len = sizeof (struct in_addr), \
+    snmp_in_addr_val = V, \
+    (u_char *) &snmp_in_addr_val \
+  )
+
+void smux_init (oid [], size_t);
+void smux_start (void);
+void smux_register_mib(char *, struct variable *, size_t, int, oid [], size_t);
+int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, 
+    WriteMethod **);
+int smux_trap (oid *, size_t, oid *, size_t, struct trap_object *, size_t, unsigned int);
+
+int oid_compare (oid *, int, oid *, int);
+void oid2in_addr (oid [], int, struct in_addr *);
+void *oid_copy (void *, void *, size_t);
+void oid_copy_addr (oid [], struct in_addr *, int);
+
+#endif /* _ZEBRA_SNMP_H */
diff --git a/lib/sockopt.c b/lib/sockopt.c
new file mode 100644 (file)
index 0000000..e2beca9
--- /dev/null
@@ -0,0 +1,199 @@
+/* setsockopt functions
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include "log.h"
+
+#ifdef HAVE_IPV6
+/* Set IPv6 packet info to the socket. */
+int
+setsockopt_ipv6_pktinfo (int sock, int val)
+{
+  int ret;
+    
+#ifdef IPV6_RECVPKTINFO                /*2292bis-01*/
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno));
+#else  /*RFC2292*/
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno));
+#endif /* INIA_IPV6 */
+  return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_checksum (int sock, int val)
+{
+  int ret;
+
+#ifdef GNU_LINUX
+  ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif /* GNU_LINUX */
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_CHECKSUM");
+  return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_multicast_hops (int sock, int val)
+{
+  int ret;
+
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
+  return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_unicast_hops (int sock, int val)
+{
+  int ret;
+
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
+  return ret;
+}
+
+int
+setsockopt_ipv6_hoplimit (int sock, int val)
+{
+  int ret;
+
+#ifdef IPV6_RECVHOPLIMIT       /*2292bis-01*/
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
+#else  /*RFC2292*/
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
+#endif
+  return ret;
+}
+
+/* Set multicast loop zero to the socket. */
+int
+setsockopt_ipv6_multicast_loop (int sock, int val)
+{
+  int ret;
+    
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+                   sizeof (val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
+  return ret;
+}
+
+#endif /* HAVE_IPV6 */
+
+
+/* Set up a multicast socket options for IPv4
+   This is here so that people only have to do their OS multicast mess 
+   in one place rather than all through zebra, ospfd, and ripd 
+   NB: This is a hookpoint for specific OS functionality */
+int
+setsockopt_multicast_ipv4(int sock, 
+                       int optname, 
+                       struct in_addr if_addr,
+                       unsigned int mcast_addr,
+                       unsigned int ifindex)
+{
+
+  /* Linux 2.2.0 and up */
+#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584
+  /* This is better because it uses ifindex directly */
+  struct ip_mreqn mreqn;
+  
+  switch (optname)
+    {
+    case IP_MULTICAST_IF:
+    case IP_ADD_MEMBERSHIP:
+    case IP_DROP_MEMBERSHIP:
+      memset (&mreqn, 0, sizeof(mreqn));
+
+      if (mcast_addr)
+       mreqn.imr_multiaddr.s_addr = mcast_addr;
+      
+      if (ifindex)
+       mreqn.imr_ifindex = ifindex;
+      else
+       mreqn.imr_address = if_addr;
+      
+      return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn));
+      break;
+
+    default:
+      /* Can out and give an understandable error */
+      errno = EINVAL;
+      return -1;
+      break;
+    }
+
+  /* Example defines for another OS, boilerplate off other code in this
+     function, AND handle optname as per other sections for consistency !! */
+  /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
+  /* Add your favourite OS here! */
+
+#else /* #if OS_TYPE */ 
+  /* default OS support */
+
+  struct in_addr m;
+  struct ip_mreq mreq;
+
+  switch (optname)
+    {
+    case IP_MULTICAST_IF:
+      m = if_addr;
+      
+      return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); 
+      break;
+
+    case IP_ADD_MEMBERSHIP:
+    case IP_DROP_MEMBERSHIP:
+      memset (&mreq, 0, sizeof(mreq));
+      mreq.imr_multiaddr.s_addr = mcast_addr;
+      mreq.imr_interface = if_addr;
+      
+      return setsockopt (sock, 
+                        IPPROTO_IP, 
+                        optname, 
+                        (void *)&mreq, 
+                        sizeof(mreq));
+      break;
+      
+    default:
+      /* Can out and give an understandable error */
+      errno = EINVAL;
+      return -1;
+      break;
+    }
+#endif /* #if OS_TYPE */
+
+}
diff --git a/lib/sockopt.h b/lib/sockopt.h
new file mode 100644 (file)
index 0000000..7fb31c1
--- /dev/null
@@ -0,0 +1,41 @@
+/* Router advertisement
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_SOCKOPT_H
+#define _ZEBRA_SOCKOPT_H
+
+#ifdef HAVE_IPV6
+int setsockopt_ipv6_pktinfo (int, int);
+int setsockopt_ipv6_checksum (int, int);
+int setsockopt_ipv6_multicast_hops (int, int);
+int setsockopt_ipv6_unicast_hops (int, int);
+int setsockopt_ipv6_hoplimit (int, int);
+int setsockopt_ipv6_multicast_loop (int, int);
+#endif /* HAVE_IPV6 */
+
+int setsockopt_multicast_ipv4(int sock, 
+                            int optname, 
+                            struct in_addr if_addr,
+                            unsigned int mcast_addr,
+                            unsigned int ifindex);
+
+
+#endif /*_ZEBRA_SOCKOPT_H */
diff --git a/lib/sockunion.c b/lib/sockunion.c
new file mode 100644 (file)
index 0000000..2137162
--- /dev/null
@@ -0,0 +1,756 @@
+/* Socket union related function.
+ * Copyright (c) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "str.h"
+#include "log.h"
+
+#ifndef HAVE_INET_ATON
+int
+inet_aton (const char *cp, struct in_addr *inaddr)
+{
+  int dots = 0;
+  register u_long addr = 0;
+  register u_long val = 0, base = 10;
+
+  do
+    {
+      register char c = *cp;
+
+      switch (c)
+       {
+       case '0': case '1': case '2': case '3': case '4': case '5':
+       case '6': case '7': case '8': case '9':
+         val = (val * base) + (c - '0');
+         break;
+       case '.':
+         if (++dots > 3)
+           return 0;
+       case '\0':
+         if (val > 255)
+           return 0;
+         addr = addr << 8 | val;
+         val = 0;
+         break;
+       default:
+         return 0;
+       }
+    } while (*cp++) ;
+
+  if (dots < 3)
+    addr <<= 8 * (3 - dots);
+  if (inaddr)
+    inaddr->s_addr = htonl (addr);
+  return 1;
+}
+#endif /* ! HAVE_INET_ATON */
+
+
+#ifndef HAVE_INET_PTON
+int
+inet_pton (int family, const char *strptr, void *addrptr)
+{
+  if (family == AF_INET)
+    {
+      struct in_addr in_val;
+
+      if (inet_aton (strptr, &in_val))
+       {
+         memcpy (addrptr, &in_val, sizeof (struct in_addr));
+         return 1;
+       }
+      return 0;
+    }
+  errno = EAFNOSUPPORT;
+  return -1;
+}
+#endif /* ! HAVE_INET_PTON */
+
+#ifndef HAVE_INET_NTOP
+const char *
+inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
+{
+  unsigned char *p = (unsigned char *) addrptr;
+
+  if (family == AF_INET) 
+    {
+      char temp[INET_ADDRSTRLEN];
+
+      snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+
+      if (strlen(temp) >= len) 
+       {
+         errno = ENOSPC;
+         return NULL;
+       }
+      strcpy(strptr, temp);
+      return strptr;
+    }
+
+  errno = EAFNOSUPPORT;
+  return NULL;
+}
+#endif /* ! HAVE_INET_NTOP */
+
+const char *
+inet_sutop (union sockunion *su, char *str)
+{
+  switch (su->sa.sa_family)
+    {
+    case AF_INET:
+      inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return str;
+}
+
+int
+str2sockunion (char *str, union sockunion *su)
+{
+  int ret;
+
+  memset (su, 0, sizeof (union sockunion));
+
+  ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
+  if (ret > 0)                 /* Valid IPv4 address format. */
+    {
+      su->sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+      return 0;
+    }
+#ifdef HAVE_IPV6
+  ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
+  if (ret > 0)                 /* Valid IPv6 address format. */
+    {
+      su->sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+      su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif /* SIN6_LEN */
+      return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return -1;
+}
+
+const char *
+sockunion2str (union sockunion *su, char *buf, size_t len)
+{
+  if  (su->sa.sa_family == AF_INET)
+    return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
+#ifdef HAVE_IPV6
+  else if (su->sa.sa_family == AF_INET6)
+    return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+union sockunion *
+sockunion_str2su (char *str)
+{
+  int ret;
+  union sockunion *su;
+
+  su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
+  memset (su, 0, sizeof (union sockunion));
+
+  ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
+  if (ret > 0)                 /* Valid IPv4 address format. */
+    {
+      su->sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+      return su;
+    }
+#ifdef HAVE_IPV6
+  ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
+  if (ret > 0)                 /* Valid IPv6 address format. */
+    {
+      su->sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+      su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif /* SIN6_LEN */
+      return su;
+    }
+#endif /* HAVE_IPV6 */
+
+  XFREE (MTYPE_SOCKUNION, su);
+  return NULL;
+}
+
+char *
+sockunion_su2str (union sockunion *su)
+{
+  char str[INET6_ADDRSTRLEN];
+
+  switch (su->sa.sa_family)
+    {
+    case AF_INET:
+      inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str));
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return strdup (str);
+}
+
+/* Return socket of sockunion. */
+int
+sockunion_socket (union sockunion *su)
+{
+  int sock;
+
+  sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno));
+      return -1;
+    }
+
+  return sock;
+}
+
+/* Return accepted new socket file descriptor. */
+int
+sockunion_accept (int sock, union sockunion *su)
+{
+  socklen_t len;
+  int client_sock;
+
+  len = sizeof (union sockunion);
+  client_sock = accept (sock, (struct sockaddr *) su, &len);
+  
+  /* Convert IPv4 compatible IPv6 address to IPv4 address. */
+#ifdef HAVE_IPV6
+  if (su->sa.sa_family == AF_INET6)
+    {
+      if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+       {
+         struct sockaddr_in sin;
+
+         memset (&sin, 0, sizeof (struct sockaddr_in));
+         sin.sin_family = AF_INET;
+         memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+         memcpy (su, &sin, sizeof (struct sockaddr_in));
+       }
+    }
+#endif /* HAVE_IPV6 */
+
+  return client_sock;
+}
+
+/* Return sizeof union sockunion.  */
+int
+sockunion_sizeof (union sockunion *su)
+{
+  int ret;
+
+  ret = 0;
+  switch (su->sa.sa_family)
+    {
+    case AF_INET:
+      ret = sizeof (struct sockaddr_in);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = sizeof (struct sockaddr_in6);
+      break;
+#endif /* AF_INET6 */
+    }
+  return ret;
+}
+
+/* return sockunion structure : this function should be revised. */
+char *
+sockunion_log (union sockunion *su)
+{
+  static char buf[SU_ADDRSTRLEN];
+
+  switch (su->sa.sa_family) 
+    {
+    case AF_INET:
+      snprintf (buf, BUFSIZ, "%s", inet_ntoa (su->sin.sin_addr));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      snprintf (buf, BUFSIZ, "%s",
+               inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, BUFSIZ));
+      break;
+#endif /* HAVE_IPV6 */
+    default:
+      snprintf (buf, BUFSIZ, "af_unknown %d ", su->sa.sa_family);
+      break;
+    }
+  return buf;
+}
+
+/* sockunion_connect returns
+   -1 : error occured
+   0 : connect success
+   1 : connect is in progress */
+enum connect_result
+sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
+                  unsigned int ifindex)
+{
+  int ret;
+  int val;
+  union sockunion su;
+
+  memcpy (&su, peersu, sizeof (union sockunion));
+
+  switch (su.sa.sa_family)
+    {
+    case AF_INET:
+      su.sin.sin_port = port;
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      su.sin6.sin6_port  = port;
+#ifdef KAME
+      if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
+       {
+#ifdef HAVE_SIN6_SCOPE_ID
+         /* su.sin6.sin6_scope_id = ifindex; */
+#endif /* HAVE_SIN6_SCOPE_ID */
+         SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
+       }
+#endif /* KAME */
+      break;
+#endif /* HAVE_IPV6 */
+    }      
+
+  /* Make socket non-block. */
+  val = fcntl (fd, F_GETFL, 0);
+  fcntl (fd, F_SETFL, val|O_NONBLOCK);
+
+  /* Call connect function. */
+  ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
+
+  /* Immediate success */
+  if (ret == 0)
+    {
+      fcntl (fd, F_SETFL, val);
+      return connect_success;
+    }
+
+  /* If connect is in progress then return 1 else it's real error. */
+  if (ret < 0)
+    {
+      if (errno != EINPROGRESS)
+       {
+         zlog_info ("can't connect to %s fd %d : %s",
+                    sockunion_log (&su), fd, strerror (errno));
+         return connect_error;
+       }
+    }
+
+  fcntl (fd, F_SETFL, val);
+
+  return connect_in_progress;
+}
+
+/* Make socket from sockunion union. */
+int
+sockunion_stream_socket (union sockunion *su)
+{
+  int sock;
+
+  if (su->sa.sa_family == 0)
+    su->sa.sa_family = AF_INET_UNION;
+
+  sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
+
+  if (sock < 0)
+    zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
+
+  return sock;
+}
+
+/* Bind socket to specified address. */
+int
+sockunion_bind (int sock, union sockunion *su, unsigned short port, 
+               union sockunion *su_addr)
+{
+  int size = 0;
+  int ret;
+
+  if (su->sa.sa_family == AF_INET)
+    {
+      size = sizeof (struct sockaddr_in);
+      su->sin.sin_port = htons (port);
+#ifdef HAVE_SIN_LEN
+      su->sin.sin_len = size;
+#endif /* HAVE_SIN_LEN */
+      if (su_addr == NULL)
+       su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
+    }
+#ifdef HAVE_IPV6
+  else if (su->sa.sa_family == AF_INET6)
+    {
+      size = sizeof (struct sockaddr_in6);
+      su->sin6.sin6_port = htons (port);
+#ifdef SIN6_LEN
+      su->sin6.sin6_len = size;
+#endif /* SIN6_LEN */
+      if (su_addr == NULL)
+       {
+#if defined(LINUX_IPV6) || defined(NRL)
+         memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
+#else
+         su->sin6.sin6_addr = in6addr_any;
+#endif /* LINUX_IPV6 */
+       }
+    }
+#endif /* HAVE_IPV6 */
+  
+
+  ret = bind (sock, (struct sockaddr *)su, size);
+  if (ret < 0)
+    zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno));
+
+  return ret;
+}
+
+int
+sockopt_reuseaddr (int sock)
+{
+  int ret;
+  int on = 1;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 
+                   (void *) &on, sizeof (on));
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
+      return -1;
+    }
+  return 0;
+}
+
+#ifdef SO_REUSEPORT
+int
+sockopt_reuseport (int sock)
+{
+  int ret;
+  int on = 1;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, 
+                   (void *) &on, sizeof (on));
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
+      return -1;
+    }
+  return 0;
+}
+#else
+int
+sockopt_reuseport (int sock)
+{
+  return 0;
+}
+#endif /* 0 */
+
+int
+sockopt_ttl (int family, int sock, int ttl)
+{
+  int ret;
+
+#ifdef IP_TTL
+  if (family == AF_INET)
+    {
+      ret = setsockopt (sock, IPPROTO_IP, IP_TTL, 
+                       (void *) &ttl, sizeof (int));
+      if (ret < 0)
+       {
+         zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
+         return -1;
+       }
+      return 0;
+    }
+#endif /* IP_TTL */
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    {
+      ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 
+                       (void *) &ttl, sizeof (int));
+      if (ret < 0)
+       {
+         zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
+                   ttl, sock);
+         return -1;
+       }
+      return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* If same family and same prefix return 1. */
+int
+sockunion_same (union sockunion *su1, union sockunion *su2)
+{
+  int ret = 0;
+
+  if (su1->sa.sa_family != su2->sa.sa_family)
+    return 0;
+
+  switch (su1->sa.sa_family)
+    {
+    case AF_INET:
+      ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
+                   sizeof (struct in_addr));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
+                   sizeof (struct in6_addr));
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  if (ret == 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* After TCP connection is established.  Get local address and port. */
+union sockunion *
+sockunion_getsockname (int fd)
+{
+  int ret;
+  int len;
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+    struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+    char tmp_buffer[128];
+  } name;
+  union sockunion *su;
+
+  memset (&name, 0, sizeof name);
+  len = sizeof name;
+
+  ret = getsockname (fd, (struct sockaddr *)&name, &len);
+  if (ret < 0)
+    {
+      zlog_warn ("Can't get local address and port by getsockname: %s",
+                strerror (errno));
+      return NULL;
+    }
+
+  if (name.sa.sa_family == AF_INET)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in));
+      return su;
+    }
+#ifdef HAVE_IPV6
+  if (name.sa.sa_family == AF_INET6)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in6));
+
+      if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+       {
+         struct sockaddr_in sin;
+
+         sin.sin_family = AF_INET;
+         memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+         sin.sin_port = su->sin6.sin6_port;
+         memcpy (su, &sin, sizeof (struct sockaddr_in));
+       }
+      return su;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* After TCP connection is established.  Get remote address and port. */
+union sockunion *
+sockunion_getpeername (int fd)
+{
+  int ret;
+  int len;
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+    struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+    char tmp_buffer[128];
+  } name;
+  union sockunion *su;
+
+  memset (&name, 0, sizeof name);
+  len = sizeof name;
+  ret = getpeername (fd, (struct sockaddr *)&name, &len);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
+           strerror (errno));
+      return NULL;
+    }
+
+  if (name.sa.sa_family == AF_INET)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in));
+      return su;
+    }
+#ifdef HAVE_IPV6
+  if (name.sa.sa_family == AF_INET6)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in6));
+
+      if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+       {
+         struct sockaddr_in sin;
+
+         sin.sin_family = AF_INET;
+         memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+         sin.sin_port = su->sin6.sin6_port;
+         memcpy (su, &sin, sizeof (struct sockaddr_in));
+       }
+      return su;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* Print sockunion structure */
+void
+sockunion_print (union sockunion *su)
+{
+  if (su == NULL)
+    return;
+
+  switch (su->sa.sa_family) 
+    {
+    case AF_INET:
+      printf ("%s\n", inet_ntoa (su->sin.sin_addr));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      {
+       char buf [64];
+
+       printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
+                                buf, sizeof (buf)));
+      }
+      break;
+#endif /* HAVE_IPV6 */
+
+#ifdef AF_LINK
+    case AF_LINK:
+      {
+       struct sockaddr_dl *sdl;
+
+       sdl = (struct sockaddr_dl *)&(su->sa);
+       printf ("link#%d\n", sdl->sdl_index);
+      }
+      break;
+#endif /* AF_LINK */
+    default:
+      printf ("af_unknown %d\n", su->sa.sa_family);
+      break;
+    }
+}
+
+#ifdef HAVE_IPV6
+int
+in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
+{
+  int i;
+  u_char *p1, *p2;
+
+  p1 = (u_char *)addr1;
+  p2 = (u_char *)addr2;
+
+  for (i = 0; i < sizeof (struct in6_addr); i++)
+    {
+      if (p1[i] > p2[i])
+       return 1;
+      else if (p1[i] < p2[i])
+       return -1;
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+int
+sockunion_cmp (union sockunion *su1, union sockunion *su2)
+{
+  if (su1->sa.sa_family > su2->sa.sa_family)
+    return 1;
+  if (su1->sa.sa_family < su2->sa.sa_family)
+    return -1;
+
+  if (su1->sa.sa_family == AF_INET)
+    {
+      if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
+       return 0;
+      if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
+       return 1;
+      else
+       return -1;
+    }
+#ifdef HAVE_IPV6
+  if (su1->sa.sa_family == AF_INET6)
+    return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* Duplicate sockunion. */
+union sockunion *
+sockunion_dup (union sockunion *su)
+{
+  union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
+  memcpy (dup, su, sizeof (union sockunion));
+  return dup;
+}
+
+void
+sockunion_free (union sockunion *su)
+{
+  XFREE (MTYPE_SOCKUNION, su);
+}
diff --git a/lib/sockunion.h b/lib/sockunion.h
new file mode 100644 (file)
index 0000000..99bdf6a
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Socket union header.
+ * Copyright (c) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_SOCKUNION_H
+#define _ZEBRA_SOCKUNION_H
+
+#if 0
+union sockunion {
+  struct sockinet {
+    u_char si_len;
+    u_char si_family;
+    u_short si_port;
+  } su_si;
+  struct sockaddr_in  su_sin;
+  struct sockaddr_in6 su_sin6;
+};
+#define su_len                su_si.si_len
+#define su_family     su_si.si_family
+#define su_port               su_si.si_port
+#endif /* 0 */
+
+union sockunion 
+{
+  struct sockaddr sa;
+  struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+  struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+};
+
+enum connect_result
+{
+  connect_error,
+  connect_success,
+  connect_in_progress
+};
+
+/* Default address family. */
+#ifdef HAVE_IPV6
+#define AF_INET_UNION AF_INET6
+#else
+#define AF_INET_UNION AF_INET
+#endif
+
+/* Sockunion address string length.  Same as INET6_ADDRSTRLEN. */
+#define SU_ADDRSTRLEN 46
+
+/* Macro to set link local index to the IPv6 address.  For KAME IPv6
+   stack. */
+#ifdef KAME
+#define        IN6_LINKLOCAL_IFINDEX(a)  ((a).s6_addr[2] << 8 | (a).s6_addr[3])
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+  do { \
+    (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+    (a).s6_addr[3] = (i) & 0xff; \
+  } while (0)
+#else
+#define        IN6_LINKLOCAL_IFINDEX(a)
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i)
+#endif /* KAME */
+
+/* shortcut macro to specify address field of struct sockaddr */
+#define sock2ip(X)   (((struct sockaddr_in *)(X))->sin_addr.s_addr)
+#ifdef HAVE_IPV6
+#define sock2ip6(X)  (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr)
+#endif /* HAVE_IPV6 */
+
+#define sockunion_family(X)  (X)->sa.sa_family
+
+/* Prototypes. */
+int str2sockunion (char *, union sockunion *);
+const char *sockunion2str (union sockunion *, char *, size_t);
+int sockunion_cmp (union sockunion *, union sockunion *);
+int sockunion_same (union sockunion *, union sockunion *);
+
+char *sockunion_su2str (union sockunion *su);
+union sockunion *sockunion_str2su (char *str);
+struct in_addr sockunion_get_in_addr (union sockunion *su);
+int sockunion_accept (int sock, union sockunion *);
+int sockunion_stream_socket (union sockunion *);
+int sockopt_reuseaddr (int);
+int sockopt_reuseport (int);
+int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *);
+int sockopt_ttl (int family, int sock, int ttl);
+int sockunion_socket (union sockunion *su);
+const char *inet_sutop (union sockunion *su, char *str);
+enum connect_result
+sockunion_connect (int fd, union sockunion *su, unsigned short port, unsigned int);
+union sockunion *sockunion_getsockname (int);
+union sockunion *sockunion_getpeername (int);
+union sockunion *sockunion_dup (union sockunion *);
+void sockunion_free (union sockunion *);
+
+#ifndef HAVE_INET_NTOP
+const char *
+inet_ntop (int family, const void *addrptr, char *strptr, size_t len);
+#endif /* HAVE_INET_NTOP */
+
+#ifndef HAVE_INET_PTON
+int
+inet_pton (int family, const char *strptr, void *addrptr);
+#endif /* HAVE_INET_PTON */
+
+#ifndef HAVE_INET_ATON
+int
+inet_aton (const char *cp, struct in_addr *inaddr);
+#endif
+
+#endif /* _ZEBRA_SOCKUNION_H */
diff --git a/lib/str.c b/lib/str.c
new file mode 100644 (file)
index 0000000..797e9b8
--- /dev/null
+++ b/lib/str.c
@@ -0,0 +1,62 @@
+/*
+ * zebra string function
+ *
+ * these functions are just very basic wrappers around exiting ones and
+ * do not offer the protection that might be expected against buffer
+ * overruns etc
+ */
+
+#include <zebra.h>
+
+#include "str.h"
+
+#ifndef HAVE_SNPRINTF
+/*
+ * snprint() is a real basic wrapper around the standard sprintf()
+ * without any bounds checking
+ */
+int
+snprintf(char *str, size_t size, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+
+  return vsprintf (str, format, args);
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+/*
+ * strlcpy is a safer version of strncpy(), checking the total
+ * size of the buffer
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+  strncpy(dst, src, size);
+
+  return (strlen(dst));
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/*
+ * strlcat is a safer version of strncat(), checking the total
+ * size of the buffer
+ */
+size_t
+strlcat(char *dst, const char *src, size_t size)
+{
+  /* strncpy(dst, src, size - strlen(dst)); */
+
+  /* I've just added below code only for workable under Linux.  So
+     need rewrite -- Kunihiro. */
+  if (strlen (dst) + strlen (src) >= size)
+    return -1;
+
+  strcat (dst, src);
+
+  return (strlen(dst));
+}
+#endif
diff --git a/lib/str.h b/lib/str.h
new file mode 100644 (file)
index 0000000..4098896
--- /dev/null
+++ b/lib/str.h
@@ -0,0 +1,24 @@
+/*
+ * $Id: str.h,v 1.1 2002/12/13 20:15:29 paul Exp $
+ */
+
+#ifndef _ZEBRA_STR_H
+#define _ZEBRA_STR_H
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *, size_t, const char *, ...);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+#define vsnprintf(buf, size, format, args) vsprintf(buf, format, args)
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#endif
diff --git a/lib/stream.c b/lib/stream.c
new file mode 100644 (file)
index 0000000..2d4de76
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Packet interface
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "stream.h"
+#include "memory.h"
+#include "network.h"
+#include "prefix.h"
+
+
+/*A macro to check pointers in order to not
+  go behind the allocated mem block 
+  S -- stream reference
+  Z -- size of data to be written 
+*/
+
+#define CHECK_SIZE(S, Z) \
+       if (((S)->putp + (Z)) > (S)->size) \
+           (Z) = (S)->size - (S)->putp;
+
+/* Stream is fixed length buffer for network output/input. */
+
+/* Make stream buffer. */
+struct stream *
+stream_new (size_t size)
+{
+  struct stream *s;
+
+  s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
+
+  s->data = XCALLOC (MTYPE_STREAM_DATA, size);
+  s->size = size;
+  return s;
+}
+
+/* Free it now. */
+void
+stream_free (struct stream *s)
+{
+  XFREE (MTYPE_STREAM_DATA, s->data);
+  XFREE (MTYPE_STREAM, s);
+}
+\f
+unsigned long
+stream_get_getp (struct stream *s)
+{
+  return s->getp;
+}
+
+unsigned long
+stream_get_putp (struct stream *s)
+{
+  return s->putp;
+}
+
+unsigned long
+stream_get_endp (struct stream *s)
+{
+  return s->endp;
+}
+
+unsigned long
+stream_get_size (struct stream *s)
+{
+  return s->size;
+}
+
+/* Stream structre' stream pointer related functions.  */
+void
+stream_set_getp (struct stream *s, unsigned long pos)
+{
+  s->getp = pos;
+}
+
+void
+stream_set_putp (struct stream *s, unsigned long pos)
+{
+  s->putp = pos;
+}
+
+/* Forward pointer. */
+void
+stream_forward (struct stream *s, int size)
+{
+  s->getp += size;
+}
+\f
+/* Copy from stream to destination. */
+void
+stream_get (void *dst, struct stream *s, size_t size)
+{
+  memcpy (dst, s->data + s->getp, size);
+  s->getp += size;
+}
+
+/* Get next character from the stream. */
+u_char
+stream_getc (struct stream *s)
+{
+  u_char c;
+
+  c = s->data[s->getp];
+  s->getp++;
+  return c;
+}
+
+/* Get next character from the stream. */
+u_char
+stream_getc_from (struct stream *s, unsigned long from)
+{
+  u_char c;
+
+  c = s->data[from];
+  return c;
+}
+
+/* Get next word from the stream. */
+u_int16_t
+stream_getw (struct stream *s)
+{
+  u_int16_t w;
+
+  w = s->data[s->getp++] << 8;
+  w |= s->data[s->getp++];
+  return w;
+}
+
+/* Get next word from the stream. */
+u_int16_t
+stream_getw_from (struct stream *s, unsigned long from)
+{
+  u_int16_t w;
+
+  w = s->data[from++] << 8;
+  w |= s->data[from];
+  return w;
+}
+
+/* Get next long word from the stream. */
+u_int32_t
+stream_getl (struct stream *s)
+{
+  u_int32_t l;
+
+  l  = s->data[s->getp++] << 24;
+  l |= s->data[s->getp++] << 16;
+  l |= s->data[s->getp++] << 8;
+  l |= s->data[s->getp++];
+  return l;
+}
+
+/* Get next long word from the stream. */
+u_int32_t
+stream_get_ipv4 (struct stream *s)
+{
+  u_int32_t l;
+
+  memcpy (&l, s->data + s->getp, 4);
+  s->getp += 4;
+
+  return l;
+}
+\f
+/* Copy to source to stream. */
+void
+stream_put (struct stream *s, void *src, size_t size)
+{
+
+  CHECK_SIZE(s, size);
+
+  if (src)
+    memcpy (s->data + s->putp, src, size);
+  else
+    memset (s->data + s->putp, 0, size);
+
+  s->putp += size;
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+}
+
+/* Put character to the stream. */
+int
+stream_putc (struct stream *s, u_char c)
+{
+  if (s->putp >= s->size) return 0;
+
+  s->data[s->putp] = c;
+  s->putp++;
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 1;
+}
+
+/* Put word to the stream. */
+int
+stream_putw (struct stream *s, u_int16_t w)
+{
+  if ((s->size - s->putp) < 2) return 0;
+
+  s->data[s->putp++] = (u_char)(w >>  8);
+  s->data[s->putp++] = (u_char) w;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 2;
+}
+
+/* Put long word to the stream. */
+int
+stream_putl (struct stream *s, u_int32_t l)
+{
+  if ((s->size - s->putp) < 4) return 0;
+
+  s->data[s->putp++] = (u_char)(l >> 24);
+  s->data[s->putp++] = (u_char)(l >> 16);
+  s->data[s->putp++] = (u_char)(l >>  8);
+  s->data[s->putp++] = (u_char)l;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 4;
+}
+
+int
+stream_putc_at (struct stream *s, unsigned long putp, u_char c)
+{
+  s->data[putp] = c;
+  return 1;
+}
+
+int
+stream_putw_at (struct stream *s, unsigned long putp, u_int16_t w)
+{
+  s->data[putp] = (u_char)(w >>  8);
+  s->data[putp + 1] = (u_char) w;
+  return 2;
+}
+
+int
+stream_putl_at (struct stream *s, unsigned long putp, u_int32_t l)
+{
+  s->data[putp] = (u_char)(l >> 24);
+  s->data[putp + 1] = (u_char)(l >> 16);
+  s->data[putp + 2] = (u_char)(l >>  8);
+  s->data[putp + 3] = (u_char)l;
+  return 4;
+}
+
+/* Put long word to the stream. */
+int
+stream_put_ipv4 (struct stream *s, u_int32_t l)
+{
+  if ((s->size - s->putp) < 4)
+    return 0;
+
+  memcpy (s->data + s->putp, &l, 4);
+  s->putp += 4;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 4;
+}
+
+/* Put long word to the stream. */
+int
+stream_put_in_addr (struct stream *s, struct in_addr *addr)
+{
+  if ((s->size - s->putp) < 4)
+    return 0;
+
+  memcpy (s->data + s->putp, addr, 4);
+  s->putp += 4;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 4;
+}
+
+/* Put prefix by nlri type format. */
+int
+stream_put_prefix (struct stream *s, struct prefix *p)
+{
+  u_char psize;
+
+  psize = PSIZE (p->prefixlen);
+
+  if ((s->size - s->putp) < psize) return 0;
+
+  stream_putc (s, p->prefixlen);
+  memcpy (s->data + s->putp, &p->u.prefix, psize);
+  s->putp += psize;
+  
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+
+  return psize;
+}
+\f
+/* Read size from fd. */
+int
+stream_read (struct stream *s, int fd, size_t size)
+{
+  int nbytes;
+
+  nbytes = readn (fd, s->data + s->putp, size);
+
+  if (nbytes > 0)
+    {
+      s->putp += nbytes;
+      s->endp += nbytes;
+    }
+  return nbytes;
+}
+
+/* Read size from fd. */
+int
+stream_read_unblock (struct stream *s, int fd, size_t size)
+{
+  int nbytes;
+  int val;
+
+  val = fcntl (fd, F_GETFL, 0);
+  fcntl (fd, F_SETFL, val|O_NONBLOCK);
+  nbytes = read (fd, s->data + s->putp, size);
+  fcntl (fd, F_SETFL, val);
+
+  if (nbytes > 0)
+    {
+      s->putp += nbytes;
+      s->endp += nbytes;
+    }
+  return nbytes;
+}
+
+/* Write data to buffer. */
+int
+stream_write (struct stream *s, u_char *ptr, size_t size)
+{
+
+  CHECK_SIZE(s, size);
+
+  memcpy (s->data + s->putp, ptr, size);
+  s->putp += size;
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return size;
+}
+
+/* Return current read pointer. */
+u_char *
+stream_pnt (struct stream *s)
+{
+  return s->data + s->getp;
+}
+
+/* Check does this stream empty? */
+int
+stream_empty (struct stream *s)
+{
+  if (s->putp == 0 && s->endp == 0 && s->getp == 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* Reset stream. */
+void
+stream_reset (struct stream *s)
+{
+  s->putp = 0;
+  s->endp = 0;
+  s->getp = 0;
+}
+
+/* Write stream contens to the file discriptor. */
+int
+stream_flush (struct stream *s, int fd)
+{
+  int nbytes;
+
+  nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
+
+  return nbytes;
+}
+\f
+/* Stream first in first out queue. */
+
+struct stream_fifo *
+stream_fifo_new ()
+{
+  struct stream_fifo *new;
+  new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
+  return new;
+}
+
+/* Add new stream to fifo. */
+void
+stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
+{
+  if (fifo->tail)
+    fifo->tail->next = s;
+  else
+    fifo->head = s;
+     
+  fifo->tail = s;
+
+  fifo->count++;
+}
+
+/* Delete first stream from fifo. */
+struct stream *
+stream_fifo_pop (struct stream_fifo *fifo)
+{
+  struct stream *s;
+  
+  s = fifo->head; 
+
+  if (s)
+    { 
+      fifo->head = s->next;
+
+      if (fifo->head == NULL)
+       fifo->tail = NULL;
+    }
+
+  fifo->count--;
+
+  return s; 
+}
+
+/* Return first fifo entry. */
+struct stream *
+stream_fifo_head (struct stream_fifo *fifo)
+{
+  return fifo->head;
+}
+
+void
+stream_fifo_clean (struct stream_fifo *fifo)
+{
+  struct stream *s;
+  struct stream *next;
+
+  for (s = fifo->head; s; s = next)
+    {
+      next = s->next;
+      stream_free (s);
+    }
+  fifo->head = fifo->tail = NULL;
+  fifo->count = 0;
+}
+
+void
+stream_fifo_free (struct stream_fifo *fifo)
+{
+  stream_fifo_clean (fifo);
+  XFREE (MTYPE_STREAM_FIFO, fifo);
+}
diff --git a/lib/stream.h b/lib/stream.h
new file mode 100644 (file)
index 0000000..c6ef3c8
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Packet interface
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_STREAM_H
+#define _ZEBRA_STREAM_H
+
+/* Stream buffer. */
+struct stream
+{
+  struct stream *next;
+
+  unsigned char *data;
+  
+  /* Put pointer. */
+  unsigned long putp;
+
+  /* Get pointer. */
+  unsigned long getp;
+
+  /* End of pointer. */
+  unsigned long endp;
+
+  /* Data size. */
+  unsigned long size;
+};
+
+/* First in first out queue structure. */
+struct stream_fifo
+{
+  unsigned long count;
+
+  struct stream *head;
+  struct stream *tail;
+};
+
+/* Utility macros. */
+#define STREAM_PNT(S)   ((S)->data + (S)->getp)
+#define STREAM_SIZE(S)  ((S)->size)
+#define STREAM_REMAIN(S) ((S)->size - (S)->putp)
+#define STREAM_DATA(S)  ((S)->data)
+
+/* Stream prototypes. */
+struct stream *stream_new (size_t);
+void stream_free (struct stream *);
+
+unsigned long stream_get_getp (struct stream *);
+unsigned long stream_get_putp (struct stream *);
+unsigned long stream_get_endp (struct stream *);
+unsigned long stream_get_size (struct stream *);
+u_char *stream_get_data (struct stream *);
+
+void stream_set_getp (struct stream *, unsigned long);
+void stream_set_putp (struct stream *, unsigned long);
+
+void stream_forward (struct stream *, int);
+
+void stream_put (struct stream *, void *, size_t);
+int stream_putc (struct stream *, u_char);
+int stream_putc_at (struct stream *, unsigned long, u_char);
+int stream_putw (struct stream *, u_int16_t);
+int stream_putw_at (struct stream *, unsigned long, u_int16_t);
+int stream_putl (struct stream *, u_int32_t);
+int stream_putl_at (struct stream *, unsigned long, u_int32_t);
+int stream_put_ipv4 (struct stream *, u_int32_t);
+int stream_put_in_addr (struct stream *, struct in_addr *);
+
+void stream_get (void *, struct stream *, size_t);
+u_char stream_getc (struct stream *);
+u_char stream_getc_from (struct stream *, unsigned long);
+u_int16_t stream_getw (struct stream *);
+u_int16_t stream_getw_from (struct stream *, unsigned long);
+u_int32_t stream_getl (struct stream *);
+u_int32_t stream_get_ipv4 (struct stream *);
+
+#undef stream_read
+#undef stream_write
+int stream_read (struct stream *, int, size_t);
+int stream_read_unblock (struct stream *, int, size_t);
+int stream_write (struct stream *, u_char *, size_t);
+
+u_char *stream_pnt (struct stream *);
+void stream_reset (struct stream *);
+int stream_flush (struct stream *, int);
+int stream_empty (struct stream *);
+
+/* Stream fifo. */
+struct stream_fifo *stream_fifo_new ();
+void stream_fifo_push (struct stream_fifo *fifo, struct stream *s);
+struct stream *stream_fifo_pop (struct stream_fifo *fifo);
+struct stream *stream_fifo_head (struct stream_fifo *fifo);
+void stream_fifo_clean (struct stream_fifo *fifo);
+void stream_fifo_free (struct stream_fifo *fifo);
+
+#endif /* _ZEBRA_STREAM_H */
diff --git a/lib/table.c b/lib/table.c
new file mode 100644 (file)
index 0000000..00ba58d
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Routing Table functions.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "sockunion.h"
+
+void route_node_delete (struct route_node *);
+void route_table_free (struct route_table *);
+\f
+struct route_table *
+route_table_init (void)
+{
+  struct route_table *rt;
+
+  rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table));
+  return rt;
+}
+
+void
+route_table_finish (struct route_table *rt)
+{
+  route_table_free (rt);
+}
+
+/* Allocate new route node. */
+struct route_node *
+route_node_new ()
+{
+  struct route_node *node;
+  node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node));
+  return node;
+}
+
+/* Allocate new route node with prefix set. */
+struct route_node *
+route_node_set (struct route_table *table, struct prefix *prefix)
+{
+  struct route_node *node;
+  
+  node = route_node_new ();
+
+  prefix_copy (&node->p, prefix);
+  node->table = table;
+
+  return node;
+}
+
+/* Free route node. */
+void
+route_node_free (struct route_node *node)
+{
+  XFREE (MTYPE_ROUTE_NODE, node);
+}
+
+/* Free route table. */
+void
+route_table_free (struct route_table *rt)
+{
+  struct route_node *tmp_node;
+  struct route_node *node;
+  if (rt == NULL)
+    return;
+
+  node = rt->top;
+
+  while (node)
+    {
+      if (node->l_left)
+       {
+         node = node->l_left;
+         continue;
+       }
+
+      if (node->l_right)
+       {
+         node = node->l_right;
+         continue;
+       }
+
+      tmp_node = node;
+      node = node->parent;
+
+      if (node != NULL)
+       {
+         if (node->l_left == tmp_node)
+           node->l_left = NULL;
+         else
+           node->l_right = NULL;
+
+         route_node_free (tmp_node);
+       }
+      else
+       {
+         route_node_free (tmp_node);
+         break;
+       }
+    }
+  XFREE (MTYPE_ROUTE_TABLE, rt);
+  return;
+}
+
+/* Utility mask array. */
+static u_char maskbit[] = 
+{
+  0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+};
+
+/* Common prefix route genaration. */
+static void
+route_common (struct prefix *n, struct prefix *p, struct prefix *new)
+{
+  int i;
+  u_char diff;
+  u_char mask;
+
+  u_char *np = (u_char *)&n->u.prefix;
+  u_char *pp = (u_char *)&p->u.prefix;
+  u_char *newp = (u_char *)&new->u.prefix;
+
+  for (i = 0; i < p->prefixlen / 8; i++)
+    {
+      if (np[i] == pp[i])
+       newp[i] = np[i];
+      else
+       break;
+    }
+
+  new->prefixlen = i * 8;
+
+  if (new->prefixlen != p->prefixlen)
+    {
+      diff = np[i] ^ pp[i];
+      mask = 0x80;
+      while (new->prefixlen < p->prefixlen && !(mask & diff))
+       {
+         mask >>= 1;
+         new->prefixlen++;
+       }
+      newp[i] = np[i] & maskbit[new->prefixlen % 8];
+    }
+}
+
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
+
+/* Check bit of the prefix. */
+static int
+check_bit (u_char *prefix, u_char prefixlen)
+{
+  int offset;
+  int shift;
+  u_char *p = (u_char *)prefix;
+
+  assert (prefixlen <= 128);
+
+  offset = prefixlen / 8;
+  shift = 7 - (prefixlen % 8);
+  
+  return (p[offset] >> shift & 1);
+}
+
+/* Macro version of set_link (). */
+#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\
+                      (Y)->parent = (X)
+
+static void
+set_link (struct route_node *node, struct route_node *new)
+{
+  int bit;
+    
+  bit = check_bit (&new->p.u.prefix, node->p.prefixlen);
+
+  assert (bit == 0 || bit == 1);
+
+  node->link[bit] = new;
+  new->parent = node;
+}
+
+/* Lock node. */
+struct route_node *
+route_lock_node (struct route_node *node)
+{
+  node->lock++;
+  return node;
+}
+
+/* Unlock node. */
+void
+route_unlock_node (struct route_node *node)
+{
+  node->lock--;
+
+  if (node->lock == 0)
+    route_node_delete (node);
+}
+
+/* Dump routing table. */
+void
+route_dump_node (struct route_table *t)
+{
+  struct route_node *node;
+  char buf[46];
+
+  for (node = route_top (t); node != NULL; node = route_next (node))
+    {
+      printf ("[%d] %p %s/%d\n", 
+             node->lock,
+             node->info,
+             inet_ntop (node->p.family, &node->p.u.prefix, buf, 46),
+             node->p.prefixlen);
+    }
+}
+
+/* Find matched prefix. */
+struct route_node *
+route_node_match (struct route_table *table, struct prefix *p)
+{
+  struct route_node *node;
+  struct route_node *matched;
+
+  matched = NULL;
+  node = table->top;
+
+  /* Walk down tree.  If there is matched route then store it to
+     matched. */
+  while (node && node->p.prefixlen <= p->prefixlen && 
+        prefix_match (&node->p, p))
+    {
+      if (node->info)
+       matched = node;
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  /* If matched route found, return it. */
+  if (matched)
+    return route_lock_node (matched);
+
+  return NULL;
+}
+
+struct route_node *
+route_node_match_ipv4 (struct route_table *table, struct in_addr *addr)
+{
+  struct prefix_ipv4 p;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *addr;
+
+  return route_node_match (table, (struct prefix *) &p);
+}
+
+#ifdef HAVE_IPV6
+struct route_node *
+route_node_match_ipv6 (struct route_table *table, struct in6_addr *addr)
+{
+  struct prefix_ipv6 p;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  p.prefix = *addr;
+
+  return route_node_match (table, (struct prefix *) &p);
+}
+#endif /* HAVE_IPV6 */
+
+/* Lookup same prefix node.  Return NULL when we can't find route. */
+struct route_node *
+route_node_lookup (struct route_table *table, struct prefix *p)
+{
+  struct route_node *node;
+
+  node = table->top;
+
+  while (node && node->p.prefixlen <= p->prefixlen && 
+        prefix_match (&node->p, p))
+    {
+      if (node->p.prefixlen == p->prefixlen && node->info)
+       return route_lock_node (node);
+
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  return NULL;
+}
+
+/* Add node to routing table. */
+struct route_node *
+route_node_get (struct route_table *table, struct prefix *p)
+{
+  struct route_node *new;
+  struct route_node *node;
+  struct route_node *match;
+
+  match = NULL;
+  node = table->top;
+  while (node && node->p.prefixlen <= p->prefixlen && 
+        prefix_match (&node->p, p))
+    {
+      if (node->p.prefixlen == p->prefixlen)
+       {
+         route_lock_node (node);
+         return node;
+       }
+      match = node;
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  if (node == NULL)
+    {
+      new = route_node_set (table, p);
+      if (match)
+       set_link (match, new);
+      else
+       table->top = new;
+    }
+  else
+    {
+      new = route_node_new ();
+      route_common (&node->p, p, &new->p);
+      new->p.family = p->family;
+      new->table = table;
+      set_link (new, node);
+
+      if (match)
+       set_link (match, new);
+      else
+       table->top = new;
+
+      if (new->p.prefixlen != p->prefixlen)
+       {
+         match = new;
+         new = route_node_set (table, p);
+         set_link (match, new);
+       }
+    }
+  route_lock_node (new);
+  
+  return new;
+}
+
+/* Delete node from the routing table. */
+void
+route_node_delete (struct route_node *node)
+{
+  struct route_node *child;
+  struct route_node *parent;
+
+  assert (node->lock == 0);
+  assert (node->info == NULL);
+
+  if (node->l_left && node->l_right)
+    return;
+
+  if (node->l_left)
+    child = node->l_left;
+  else
+    child = node->l_right;
+
+  parent = node->parent;
+
+  if (child)
+    child->parent = parent;
+
+  if (parent)
+    {
+      if (parent->l_left == node)
+       parent->l_left = child;
+      else
+       parent->l_right = child;
+    }
+  else
+    node->table->top = child;
+
+  route_node_free (node);
+
+  /* If parent node is stub then delete it also. */
+  if (parent && parent->lock == 0)
+    route_node_delete (parent);
+}
+
+/* Get fist node and lock it.  This function is useful when one want
+   to lookup all the node exist in the routing table. */
+struct route_node *
+route_top (struct route_table *table)
+{
+  /* If there is no node in the routing table return NULL. */
+  if (table->top == NULL)
+    return NULL;
+
+  /* Lock the top node and return it. */
+  route_lock_node (table->top);
+  return table->top;
+}
+
+/* Unlock current node and lock next node then return it. */
+struct route_node *
+route_next (struct route_node *node)
+{
+  struct route_node *next;
+  struct route_node *start;
+
+  /* Node may be deleted from route_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
+    {
+      next = node->l_left;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+
+  start = node;
+  while (node->parent)
+    {
+      if (node->parent->l_left == node && node->parent->l_right)
+       {
+         next = node->parent->l_right;
+         route_lock_node (next);
+         route_unlock_node (start);
+         return next;
+       }
+      node = node->parent;
+    }
+  route_unlock_node (start);
+  return NULL;
+}
+
+/* Unlock current node and lock next node until limit. */
+struct route_node *
+route_next_until (struct route_node *node, struct route_node *limit)
+{
+  struct route_node *next;
+  struct route_node *start;
+
+  /* Node may be deleted from route_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
+    {
+      next = node->l_left;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+
+  start = node;
+  while (node->parent && node != limit)
+    {
+      if (node->parent->l_left == node && node->parent->l_right)
+       {
+         next = node->parent->l_right;
+         route_lock_node (next);
+         route_unlock_node (start);
+         return next;
+       }
+      node = node->parent;
+    }
+  route_unlock_node (start);
+  return NULL;
+}
diff --git a/lib/table.h b/lib/table.h
new file mode 100644 (file)
index 0000000..6f09099
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Routing Table
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_TABLE_H
+#define _ZEBRA_TABLE_H
+
+/* Routing table top structure. */
+struct route_table
+{
+  struct route_node *top;
+};
+
+/* Each routing entry. */
+struct route_node
+{
+  /* Actual prefix of this radix. */
+  struct prefix p;
+
+  /* Tree link. */
+  struct route_table *table;
+  struct route_node *parent;
+  struct route_node *link[2];
+#define l_left   link[0]
+#define l_right  link[1]
+
+  /* Lock of this radix */
+  unsigned int lock;
+
+  /* Each node of route. */
+  void *info;
+
+  /* Aggregation. */
+  void *aggregate;
+};
+
+/* Prototypes. */
+struct route_table *route_table_init (void);
+void route_table_finish (struct route_table *);
+void route_unlock_node (struct route_node *node);
+void route_node_delete (struct route_node *node);
+struct route_node *route_top (struct route_table *);
+struct route_node *route_next (struct route_node *);
+struct route_node *route_next_until (struct route_node *, struct route_node *);
+struct route_node *route_node_get (struct route_table *, struct prefix *);
+struct route_node *route_node_lookup (struct route_table *, struct prefix *);
+struct route_node *route_lock_node (struct route_node *node);
+struct route_node *route_node_match (struct route_table *, struct prefix *);
+struct route_node *route_node_match_ipv4 (struct route_table *,
+                                         struct in_addr *);
+#ifdef HAVE_IPV6
+struct route_node *route_node_match_ipv6 (struct route_table *,
+                                         struct in6_addr *);
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_TABLE_H */
diff --git a/lib/tcpfilter.c b/lib/tcpfilter.c
new file mode 100644 (file)
index 0000000..4895ab5
--- /dev/null
@@ -0,0 +1,69 @@
+/* Route filtering function for TCP and UDP.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+
+#define FILTER_TYPE_IP   1
+#define FILTER_TYPE_TCP  2
+#define FILTER_TYPE_UDP  3
+
+DEFUN (al_tcp_filter,
+       al_tcp_filter_cmd,
+       "access-list WORD (deny|permit) tcp (A.B.C.D/M|any) (A.B.C.D/M|any)",
+       "Add an access list entry\n"
+       "Access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Transmission Control Protocol\n"
+       "Source address prefix\n"
+       "Any source host\n"
+       "Destination address prefix\n"
+       "Any destination host\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (al_tcp_filter_eq,
+       al_tcp_filter_eq_cmd,
+       "access-list WORD (deny|permit) tcp (A.B.C.D/M|any) (A.B.C.D/M|any) eq <0-65535>",
+       "Add an access list entry\n"
+       "Access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Transmission Control Protocol\n"
+       "Source address prefix\n"
+       "Any source host\n"
+       "Destination address prefix\n"
+       "Any destination host\n"
+       "Port number\n")
+{
+  return CMD_SUCCESS;
+}
+
+void
+tcpfilter_init ()
+{
+  install_element (CONFIG_NODE, &al_tcp_filter_cmd);
+  install_element (CONFIG_NODE, &al_tcp_filter_eq_cmd);
+}
diff --git a/lib/tcpfilter.h b/lib/tcpfilter.h
new file mode 100644 (file)
index 0000000..c3d3008
--- /dev/null
@@ -0,0 +1,21 @@
+/* Route filtering function for TCP and UDP.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
diff --git a/lib/thread.c b/lib/thread.c
new file mode 100644 (file)
index 0000000..31bbcd7
--- /dev/null
@@ -0,0 +1,668 @@
+/* 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"
+\f
+/* 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));
+}
+\f
+/* 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");
+}
+\f
+/* 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 simple event thread. */
+struct thread *
+thread_add_event (struct thread_master *m,
+                 int (*func) (struct thread *), void *arg, int val)
+{
+  struct thread *thread;
+
+  assert (m != NULL);
+
+  thread = thread_get (m, THREAD_EVENT, func, arg);
+  thread->u.val = val;
+  thread_list_add (&m->event, thread);
+
+  return thread;
+}
+
+/* Cancel thread from scheduler. */
+void
+thread_cancel (struct thread *thread)
+{
+  switch (thread->type)
+    {
+    case THREAD_READ:
+      assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
+      FD_CLR (thread->u.fd, &thread->master->readfd);
+      thread_list_delete (&thread->master->read, thread);
+      break;
+    case THREAD_WRITE:
+      assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
+      FD_CLR (thread->u.fd, &thread->master->writefd);
+      thread_list_delete (&thread->master->write, thread);
+      break;
+    case THREAD_TIMER:
+      thread_list_delete (&thread->master->timer, thread);
+      break;
+    case THREAD_EVENT:
+      thread_list_delete (&thread->master->event, thread);
+      break;
+    case THREAD_READY:
+      thread_list_delete (&thread->master->ready, thread);
+      break;
+    default:
+      break;
+    }
+  thread->type = THREAD_UNUSED;
+  thread_add_unuse (thread->master, thread);
+}
+
+/* Delete all events which has argument value arg. */
+void
+thread_cancel_event (struct thread_master *m, void *arg)
+{
+  struct thread *thread;
+
+  thread = m->event.head;
+  while (thread)
+    {
+      struct thread *t;
+
+      t = thread;
+      thread = t->next;
+
+      if (t->arg == arg)
+       {
+         thread_list_delete (&m->event, t);
+         t->type = THREAD_UNUSED;
+         thread_add_unuse (m, t);
+       }
+    }
+}
+
+#ifdef TIMER_NO_SORT
+struct timeval *
+thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
+{
+  struct timeval timer_now;
+  struct timeval timer_min;
+  struct timeval *timer_wait;
+
+  gettimeofday (&timer_now, NULL);
+
+  timer_wait = NULL;
+  for (thread = m->timer.head; thread; thread = thread->next)
+    {
+      if (! timer_wait)
+       timer_wait = &thread->u.sands;
+      else if (timeval_cmp (thread->u.sands, *timer_wait) < 0)
+       timer_wait = &thread->u.sands;
+    }
+
+  if (m->timer.head)
+    {
+      timer_min = *timer_wait;
+      timer_min = timeval_subtract (timer_min, timer_now);
+      if (timer_min.tv_sec < 0)
+       {
+         timer_min.tv_sec = 0;
+         timer_min.tv_usec = 10;
+       }
+      timer_wait = &timer_min;
+    }
+  else
+    timer_wait = NULL;
+
+  if (timer_wait)
+    {
+      *timer_val = timer_wait;
+      return timer_val;
+    }
+  return NULL;
+}
+#else /* ! TIMER_NO_SORT */
+struct timeval *
+thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
+{
+  struct timeval timer_now;
+  struct timeval timer_min;
+
+  if (m->timer.head)
+    {
+      gettimeofday (&timer_now, NULL);
+      timer_min = m->timer.head->u.sands;
+      timer_min = timeval_subtract (timer_min, timer_now);
+      if (timer_min.tv_sec < 0)
+       {
+         timer_min.tv_sec = 0;
+         timer_min.tv_usec = 10;
+       }
+      *timer_val = timer_min;
+      return timer_val;
+    }
+  return NULL;
+}
+#endif /* TIMER_NO_SORT */
+
+struct thread *
+thread_run (struct thread_master *m, struct thread *thread,
+           struct thread *fetch)
+{
+  *fetch = *thread;
+  thread->type = THREAD_UNUSED;
+  thread_add_unuse (m, thread);
+  return fetch;
+}
+
+int
+thread_process_fd (struct thread_master *m, struct thread_list *list,
+                  fd_set *fdset, fd_set *mfdset)
+{
+  struct thread *thread;
+  struct thread *next;
+  int ready = 0;
+
+  for (thread = list->head; thread; thread = next)
+    {
+      next = thread->next;
+
+      if (FD_ISSET (THREAD_FD (thread), fdset))
+       {
+         assert (FD_ISSET (THREAD_FD (thread), mfdset));
+         FD_CLR(THREAD_FD (thread), mfdset);
+         thread_list_delete (list, thread);
+         thread_list_add (&m->ready, thread);
+         thread->type = THREAD_READY;
+         ready++;
+       }
+    }
+  return ready;
+}
+
+/* Fetch next ready thread. */
+struct thread *
+thread_fetch (struct thread_master *m, struct thread *fetch)
+{
+  int num;
+  int ready;
+  struct thread *thread;
+  fd_set readfd;
+  fd_set writefd;
+  fd_set exceptfd;
+  struct timeval timer_now;
+  struct timeval timer_val;
+  struct timeval *timer_wait;
+  struct timeval timer_nowait;
+
+  timer_nowait.tv_sec = 0;
+  timer_nowait.tv_usec = 0;
+
+  while (1)
+    {
+      /* Normal event is the highest priority.  */
+      if ((thread = thread_trim_head (&m->event)) != NULL)
+       return thread_run (m, thread, fetch);
+
+      /* Execute timer.  */
+      gettimeofday (&timer_now, NULL);
+
+      for (thread = m->timer.head; thread; thread = thread->next)
+       if (timeval_cmp (timer_now, thread->u.sands) >= 0)
+         {
+           thread_list_delete (&m->timer, thread);
+           return thread_run (m, thread, fetch);
+         }
+
+      /* If there are any ready threads, process top of them.  */
+      if ((thread = thread_trim_head (&m->ready)) != NULL)
+       return thread_run (m, thread, fetch);
+
+      /* Structure copy.  */
+      readfd = m->readfd;
+      writefd = m->writefd;
+      exceptfd = m->exceptfd;
+
+      /* Calculate select wait timer. */
+      timer_wait = thread_timer_wait (m, &timer_val);
+
+      num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
+
+      if (num == 0)
+       continue;
+
+      if (num < 0)
+       {
+         if (errno == EINTR)
+           continue;
+
+         zlog_warn ("select() error: %s", strerror (errno));
+         return NULL;
+       }
+
+      /* Normal priority read thead. */
+      ready = thread_process_fd (m, &m->read, &readfd, &m->readfd);
+
+      /* Write thead. */
+      ready = thread_process_fd (m, &m->write, &writefd, &m->writefd);
+
+      if ((thread = thread_trim_head (&m->ready)) != NULL)
+       return thread_run (m, thread, fetch);
+    }
+}
+
+static unsigned long
+thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start)
+{
+  unsigned long thread_time;
+
+#ifdef HAVE_RUSAGE
+  /* This is 'user + sys' time.  */
+  thread_time = timeval_elapsed (now->ru_utime, start->ru_utime);
+  thread_time += timeval_elapsed (now->ru_stime, start->ru_stime);
+#else
+  /* When rusage is not available, simple elapsed time is used.  */
+  thread_time = timeval_elapsed (*now, *start);
+#endif /* HAVE_RUSAGE */
+
+  return thread_time;
+}
+
+/* We should aim to yield after THREAD_YIELD_TIME_SLOT
+   milliseconds.  */
+int
+thread_should_yield (struct thread *thread)
+{
+  RUSAGE_T ru;
+
+  GETRUSAGE (&ru);
+
+  if (thread_consumed_time (&ru, &thread->ru) > THREAD_YIELD_TIME_SLOT)
+    return 1;
+  else
+    return 0;
+}
+
+/* We check thread consumed time. If the system has getrusage, we'll
+   use that to get indepth stats on the performance of the thread.  If
+   not - we'll use gettimeofday for some guestimation.  */
+void
+thread_call (struct thread *thread)
+{
+  unsigned long thread_time;
+  RUSAGE_T ru;
+
+  GETRUSAGE (&thread->ru);
+
+  (*thread->func) (thread);
+
+  GETRUSAGE (&ru);
+
+  thread_time = thread_consumed_time (&ru, &thread->ru);
+
+#ifdef THREAD_CONSUMED_TIME_CHECK
+  if (thread_time > 200000L)
+    {
+      /*
+       * We have a CPU Hog on our hands.
+       * Whinge about it now, so we're aware this is yet another task
+       * to fix.
+       */
+      zlog_err ("CPU HOG task %lx ran for %ldms",
+                /* FIXME: report the name of the function somehow */
+               (unsigned long) thread->func,
+               thread_time / 1000L);
+    }
+#endif /* THREAD_CONSUMED_TIME_CHECK */
+}
+
+/* Execute thread */
+struct thread *
+thread_execute (struct thread_master *m,
+                int (*func)(struct thread *), 
+                void *arg,
+                int val)
+{
+  struct thread dummy; 
+
+  memset (&dummy, 0, sizeof (struct thread));
+
+  dummy.type = THREAD_EVENT;
+  dummy.master = NULL;
+  dummy.func = func;
+  dummy.arg = arg;
+  dummy.u.val = val;
+  thread_call (&dummy);
+
+  return NULL;
+}
diff --git a/lib/thread.h b/lib/thread.h
new file mode 100644 (file)
index 0000000..9de62cd
--- /dev/null
@@ -0,0 +1,139 @@
+/* Thread management routine header.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_THREAD_H
+#define _ZEBRA_THREAD_H
+
+#ifdef HAVE_RUSAGE
+#define RUSAGE_T        struct rusage
+#define GETRUSAGE(X)    getrusage (RUSAGE_SELF, X);
+#else
+#define RUSAGE_T        struct timeval
+#define GETRUSAGE(X)    gettimeofday (X, NULL);
+#endif /* HAVE_RUSAGE */
+
+/* Linked list of thread. */
+struct thread_list
+{
+  struct thread *head;
+  struct thread *tail;
+  int count;
+};
+
+/* Master of the theads. */
+struct thread_master
+{
+  struct thread_list read;
+  struct thread_list write;
+  struct thread_list timer;
+  struct thread_list event;
+  struct thread_list ready;
+  struct thread_list unuse;
+  fd_set readfd;
+  fd_set writefd;
+  fd_set exceptfd;
+  unsigned long alloc;
+};
+
+/* Thread itself. */
+struct thread
+{
+  unsigned char type;          /* thread type */
+  struct thread *next;         /* next pointer of the thread */
+  struct thread *prev;         /* previous pointer of the thread */
+  struct thread_master *master;        /* pointer to the struct thread_master. */
+  int (*func) (struct thread *); /* event function */
+  void *arg;                   /* event argument */
+  union {
+    int val;                   /* second argument of the event. */
+    int fd;                    /* file descriptor in case of read/write. */
+    struct timeval sands;      /* rest of time sands value. */
+  } u;
+  RUSAGE_T ru;                 /* Indepth usage info.  */
+};
+
+/* Thread types. */
+#define THREAD_READ           0
+#define THREAD_WRITE          1
+#define THREAD_TIMER          2
+#define THREAD_EVENT          3
+#define THREAD_READY          4
+#define THREAD_UNUSED         5
+
+/* Thread yield time.  */
+#define THREAD_YIELD_TIME_SLOT     100 * 1000L /* 100ms */
+
+/* Macros. */
+#define THREAD_ARG(X) ((X)->arg)
+#define THREAD_FD(X)  ((X)->u.fd)
+#define THREAD_VAL(X) ((X)->u.val)
+
+#define THREAD_READ_ON(master,thread,func,arg,sock) \
+  do { \
+    if (! thread) \
+      thread = thread_add_read (master, func, arg, sock); \
+  } while (0)
+
+#define THREAD_WRITE_ON(master,thread,func,arg,sock) \
+  do { \
+    if (! thread) \
+      thread = thread_add_write (master, func, arg, sock); \
+  } while (0)
+
+#define THREAD_TIMER_ON(master,thread,func,arg,time) \
+  do { \
+    if (! thread) \
+      thread = thread_add_timer (master, func, arg, time); \
+  } while (0)
+
+#define THREAD_OFF(thread) \
+  do { \
+    if (thread) \
+      { \
+        thread_cancel (thread); \
+        thread = NULL; \
+      } \
+  } while (0)
+
+#define THREAD_READ_OFF(thread)  THREAD_OFF(thread)
+#define THREAD_WRITE_OFF(thread)  THREAD_OFF(thread)
+#define THREAD_TIMER_OFF(thread)  THREAD_OFF(thread)
+
+/* Prototypes. */
+struct thread_master *thread_master_create ();
+struct thread *thread_add_read (struct thread_master *, 
+                               int (*)(struct thread *), void *, int);
+struct thread *thread_add_write (struct thread_master *,
+                                int (*)(struct thread *), void *, int);
+struct thread *thread_add_timer (struct thread_master *,
+                                int (*)(struct thread *), void *, long);
+struct thread *thread_add_event (struct thread_master *,
+                                int (*)(struct thread *), void *, int );
+void thread_cancel (struct thread *);
+void thread_cancel_event (struct thread_master *, void *);
+
+struct thread *thread_fetch (struct thread_master *, struct thread *);
+struct thread *thread_execute (struct thread_master *,
+                              int (*)(struct thread *), void *, int);
+void thread_call (struct thread *);
+unsigned long thread_timer_remain_second (struct thread *);
+
+#endif /* _ZEBRA_THREAD_H */
diff --git a/lib/vector.c b/lib/vector.c
new file mode 100644 (file)
index 0000000..31cdc77
--- /dev/null
@@ -0,0 +1,189 @@
+/* Generic vector interface routine
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "vector.h"
+#include "memory.h"
+
+/* Initialize vector : allocate memory and return vector. */
+vector
+vector_init (unsigned int size)
+{
+  vector v = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+
+  /* allocate at least one slot */
+  if (size == 0)
+    size = 1;
+
+  v->alloced = size;
+  v->max = 0;
+  v->index = XCALLOC (MTYPE_VECTOR_INDEX, sizeof (void *) * size);
+  return v;
+}
+
+void
+vector_only_wrapper_free (vector v)
+{
+  XFREE (MTYPE_VECTOR, v);
+}
+
+void
+vector_only_index_free (void *index)
+{
+  XFREE (MTYPE_VECTOR_INDEX, index);
+}
+
+void
+vector_free (vector v)
+{
+  XFREE (MTYPE_VECTOR_INDEX, v->index);
+  XFREE (MTYPE_VECTOR, v);
+}
+
+vector
+vector_copy (vector v)
+{
+  unsigned int size;
+  vector new = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+
+  new->max = v->max;
+  new->alloced = v->alloced;
+
+  size = sizeof (void *) * (v->alloced);
+  new->index = XCALLOC (MTYPE_VECTOR_INDEX, size);
+  memcpy (new->index, v->index, size);
+
+  return new;
+}
+
+/* Check assigned index, and if it runs short double index pointer */
+void
+vector_ensure (vector v, unsigned int num)
+{
+  if (v->alloced > num)
+    return;
+
+  v->index = XREALLOC (MTYPE_VECTOR_INDEX, 
+                      v->index, sizeof (void *) * (v->alloced * 2));
+  memset (&v->index[v->alloced], 0, sizeof (void *) * v->alloced);
+  v->alloced *= 2;
+  
+  if (v->alloced <= num)
+    vector_ensure (v, num);
+}
+
+/* This function only returns next empty slot index.  It dose not mean
+   the slot's index memory is assigned, please call vector_ensure()
+   after calling this function. */
+int
+vector_empty_slot (vector v)
+{
+  unsigned int i;
+
+  if (v->max == 0)
+    return 0;
+
+  for (i = 0; i < v->max; i++)
+    if (v->index[i] == 0)
+      return i;
+
+  return i;
+}
+
+/* Set value to the smallest empty slot. */
+int
+vector_set (vector v, void *val)
+{
+  unsigned int i;
+
+  i = vector_empty_slot (v);
+  vector_ensure (v, i);
+
+  v->index[i] = val;
+
+  if (v->max <= i)
+    v->max = i + 1;
+
+  return i;
+}
+
+/* Set value to specified index slot. */
+int
+vector_set_index (vector v, unsigned int i, void *val)
+{
+  vector_ensure (v, i);
+
+  v->index[i] = val;
+
+  if (v->max <= i)
+    v->max = i + 1;
+
+  return i;
+}
+
+/* Look up vector.  */
+void *
+vector_lookup (vector v, unsigned int i)
+{
+  if (i >= v->max)
+    return NULL;
+  return v->index[i];
+}
+
+/* Lookup vector, ensure it. */
+void *
+vector_lookup_ensure (vector v, unsigned int i)
+{
+  vector_ensure (v, i);
+  return v->index[i];
+}
+
+/* Unset value at specified index slot. */
+void
+vector_unset (vector v, unsigned int i)
+{
+  if (i >= v->alloced)
+    return;
+
+  v->index[i] = NULL;
+
+  if (i + 1 == v->max) 
+    {
+      v->max--;
+      while (i && v->index[--i] == NULL && v->max--) 
+       ;                               /* Is this ugly ? */
+    }
+}
+
+/* Count the number of not emplty slot. */
+unsigned int
+vector_count (vector v)
+{
+  unsigned int i;
+  unsigned count = 0;
+
+  for (i = 0; i < v->max; i++) 
+    if (v->index[i] != NULL)
+      count++;
+
+  return count;
+}
diff --git a/lib/vector.h b/lib/vector.h
new file mode 100644 (file)
index 0000000..7e00c39
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Generic vector interface header.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_VECTOR_H
+#define _ZEBRA_VECTOR_H
+
+/* struct for vector */
+struct _vector 
+{
+  unsigned int max;            /* max number of used slot */
+  unsigned int alloced;                /* number of allocated slot */
+  void **index;                        /* index to data */
+};
+typedef struct _vector *vector;
+
+#define VECTOR_MIN_SIZE 1
+
+/* (Sometimes) usefull macros.  This macro convert index expression to
+ array expression. */
+#define vector_slot(V,I)  ((V)->index[(I)])
+#define vector_max(V) ((V)->max)
+
+/* Prototypes. */
+vector vector_init (unsigned int size);
+void vector_ensure (vector v, unsigned int num);
+int vector_empty_slot (vector v);
+int vector_set (vector v, void *val);
+int vector_set_index (vector v, unsigned int i, void *val);
+void vector_unset (vector v, unsigned int i);
+unsigned int vector_count (vector v);
+void vector_only_wrapper_free (vector v);
+void vector_only_index_free (void *index);
+void vector_free (vector v);
+vector vector_copy (vector v);
+
+void *vector_lookup (vector, unsigned int);
+void *vector_lookup_ensure (vector, unsigned int);
+
+#endif /* _ZEBRA_VECTOR_H */
diff --git a/lib/version.h b/lib/version.h
new file mode 100644 (file)
index 0000000..9a90bf4
--- /dev/null
@@ -0,0 +1,39 @@
+/* Zebra version
+ * Copyright (C) 1997, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_VERSION_H
+#define _ZEBRA_VERSION_H
+
+#define ZEBRA_VERSION     "0.93b"
+
+#define ZEBRA_BUG_ADDRESS "bug-zebra@gnu.org"
+
+extern char *host_name;
+
+void print_version(char *);
+pid_t pid_output (char *);
+pid_t pid_output_lock (char *);
+
+#ifndef HAVE_DAEMON
+int daemon(int, int);
+#endif
+
+#endif /* _ZEBRA_VERSION_H */
diff --git a/lib/vty.c b/lib/vty.c
new file mode 100644 (file)
index 0000000..d31521c
--- /dev/null
+++ b/lib/vty.c
@@ -0,0 +1,2792 @@
+/*
+ * 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;
+\f
+/* 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;
+
+\f
+/* 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;
+}
+\f
+char telnet_backward_char = 0x08;
+char telnet_space_char = ' ';
+
+/* Basic function to write buffer to vty. */
+static void
+vty_write (struct vty *vty, char *buf, size_t nbytes)
+{
+  if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+    return;
+
+  /* Should we do buffering here ?  And make vty_flush (vty) ? */
+  buffer_write (vty->obuf, (u_char *)buf, nbytes);
+}
+
+/* Ensure length of input buffer.  Is buffer is short, double it. */
+static void
+vty_ensure (struct vty *vty, int length)
+{
+  if (vty->max <= length)
+    {
+      vty->max *= 2;
+      vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
+    }
+}
+
+/* Basic function to insert character into vty. */
+static void
+vty_self_insert (struct vty *vty, char c)
+{
+  int i;
+  int length;
+
+  vty_ensure (vty, vty->length + 1);
+  length = vty->length - vty->cp;
+  memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
+  vty->buf[vty->cp] = c;
+
+  vty_write (vty, &vty->buf[vty->cp], length + 1);
+  for (i = 0; i < length; i++)
+    vty_write (vty, &telnet_backward_char, 1);
+
+  vty->cp++;
+  vty->length++;
+}
+
+/* Self insert character 'c' in overwrite mode. */
+static void
+vty_self_insert_overwrite (struct vty *vty, char c)
+{
+  vty_ensure (vty, vty->length + 1);
+  vty->buf[vty->cp++] = c;
+
+  if (vty->cp > vty->length)
+    vty->length++;
+
+  if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+    return;
+
+  vty_write (vty, &c, 1);
+}
+
+/* Insert a word into vty interface with overwrite mode. */
+static void
+vty_insert_word_overwrite (struct vty *vty, char *str)
+{
+  int len = strlen (str);
+  vty_write (vty, str, len);
+  strcpy (&vty->buf[vty->cp], str);
+  vty->cp += len;
+  vty->length = vty->cp;
+}
+
+/* Forward character. */
+static void
+vty_forward_char (struct vty *vty)
+{
+  if (vty->cp < vty->length)
+    {
+      vty_write (vty, &vty->buf[vty->cp], 1);
+      vty->cp++;
+    }
+}
+
+/* Backward character. */
+static void
+vty_backward_char (struct vty *vty)
+{
+  if (vty->cp > 0)
+    {
+      vty->cp--;
+      vty_write (vty, &telnet_backward_char, 1);
+    }
+}
+
+/* Move to the beginning of the line. */
+static void
+vty_beginning_of_line (struct vty *vty)
+{
+  while (vty->cp)
+    vty_backward_char (vty);
+}
+
+/* Move to the end of the line. */
+static void
+vty_end_of_line (struct vty *vty)
+{
+  while (vty->cp < vty->length)
+    vty_forward_char (vty);
+}
+
+static void vty_kill_line_from_beginning (struct vty *);
+static void vty_redraw_line (struct vty *);
+
+/* Print command line history.  This function is called from
+   vty_next_line and vty_previous_line. */
+static void
+vty_history_print (struct vty *vty)
+{
+  int length;
+
+  vty_kill_line_from_beginning (vty);
+
+  /* Get previous line from history buffer */
+  length = strlen (vty->hist[vty->hp]);
+  memcpy (vty->buf, vty->hist[vty->hp], length);
+  vty->cp = vty->length = length;
+
+  /* Redraw current line */
+  vty_redraw_line (vty);
+}
+
+/* Show next command line history. */
+void
+vty_next_line (struct vty *vty)
+{
+  int try_index;
+
+  if (vty->hp == vty->hindex)
+    return;
+
+  /* Try is there history exist or not. */
+  try_index = vty->hp;
+  if (try_index == (VTY_MAXHIST - 1))
+    try_index = 0;
+  else
+    try_index++;
+
+  /* If there is not history return. */
+  if (vty->hist[try_index] == NULL)
+    return;
+  else
+    vty->hp = try_index;
+
+  vty_history_print (vty);
+}
+
+/* Show previous command line history. */
+void
+vty_previous_line (struct vty *vty)
+{
+  int try_index;
+
+  try_index = vty->hp;
+  if (try_index == 0)
+    try_index = VTY_MAXHIST - 1;
+  else
+    try_index--;
+
+  if (vty->hist[try_index] == NULL)
+    return;
+  else
+    vty->hp = try_index;
+
+  vty_history_print (vty);
+}
+
+/* This function redraw all of the command line character. */
+static void
+vty_redraw_line (struct vty *vty)
+{
+  vty_write (vty, vty->buf, vty->length);
+  vty->cp = vty->length;
+}
+
+/* Forward word. */
+static void
+vty_forward_word (struct vty *vty)
+{
+  while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+    vty_forward_char (vty);
+  
+  while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+    vty_forward_char (vty);
+}
+
+/* Backward word without skipping training space. */
+static void
+vty_backward_pure_word (struct vty *vty)
+{
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+    vty_backward_char (vty);
+}
+
+/* Backward word. */
+static void
+vty_backward_word (struct vty *vty)
+{
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+    vty_backward_char (vty);
+
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+    vty_backward_char (vty);
+}
+
+/* When '^D' is typed at the beginning of the line we move to the down
+   level. */
+static void
+vty_down_level (struct vty *vty)
+{
+  vty_out (vty, "%s", VTY_NEWLINE);
+  config_exit (NULL, vty, 0, NULL);
+  vty_prompt (vty);
+  vty->cp = 0;
+}
+
+/* When '^Z' is received from vty, move down to the enable mode. */
+void
+vty_end_config (struct vty *vty)
+{
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      /* Nothing to do. */
+      break;
+    case CONFIG_NODE:
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case BGP_NODE:
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+    case RMAP_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case KEYCHAIN_NODE:
+    case KEYCHAIN_KEY_NODE:
+    case MASC_NODE:
+    case VTY_NODE:
+      vty_config_unlock (vty);
+      vty->node = ENABLE_NODE;
+      break;
+    default:
+      /* Unknown node, we have to ignore it. */
+      break;
+    }
+
+  vty_prompt (vty);
+  vty->cp = 0;
+}
+
+/* Delete a charcter at the current point. */
+static void
+vty_delete_char (struct vty *vty)
+{
+  int i;
+  int size;
+
+  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+    return;
+
+  if (vty->length == 0)
+    {
+      vty_down_level (vty);
+      return;
+    }
+
+  if (vty->cp == vty->length)
+    return;                    /* completion need here? */
+
+  size = vty->length - vty->cp;
+
+  vty->length--;
+  memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
+  vty->buf[vty->length] = '\0';
+
+  vty_write (vty, &vty->buf[vty->cp], size - 1);
+  vty_write (vty, &telnet_space_char, 1);
+
+  for (i = 0; i < size; i++)
+    vty_write (vty, &telnet_backward_char, 1);
+}
+
+/* Delete a character before the point. */
+static void
+vty_delete_backward_char (struct vty *vty)
+{
+  if (vty->cp == 0)
+    return;
+
+  vty_backward_char (vty);
+  vty_delete_char (vty);
+}
+
+/* Kill rest of line from current point. */
+static void
+vty_kill_line (struct vty *vty)
+{
+  int i;
+  int size;
+
+  size = vty->length - vty->cp;
+  
+  if (size == 0)
+    return;
+
+  for (i = 0; i < size; i++)
+    vty_write (vty, &telnet_space_char, 1);
+  for (i = 0; i < size; i++)
+    vty_write (vty, &telnet_backward_char, 1);
+
+  memset (&vty->buf[vty->cp], 0, size);
+  vty->length = vty->cp;
+}
+
+/* Kill line from the beginning. */
+static void
+vty_kill_line_from_beginning (struct vty *vty)
+{
+  vty_beginning_of_line (vty);
+  vty_kill_line (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_forward_kill_word (struct vty *vty)
+{
+  while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+    vty_delete_char (vty);
+  while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+    vty_delete_char (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_backward_kill_word (struct vty *vty)
+{
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+    vty_delete_backward_char (vty);
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+    vty_delete_backward_char (vty);
+}
+
+/* Transpose chars before or at the point. */
+static void
+vty_transpose_chars (struct vty *vty)
+{
+  char c1, c2;
+
+  /* If length is short or point is near by the beginning of line then
+     return. */
+  if (vty->length < 2 || vty->cp < 1)
+    return;
+
+  /* In case of point is located at the end of the line. */
+  if (vty->cp == vty->length)
+    {
+      c1 = vty->buf[vty->cp - 1];
+      c2 = vty->buf[vty->cp - 2];
+
+      vty_backward_char (vty);
+      vty_backward_char (vty);
+      vty_self_insert_overwrite (vty, c1);
+      vty_self_insert_overwrite (vty, c2);
+    }
+  else
+    {
+      c1 = vty->buf[vty->cp];
+      c2 = vty->buf[vty->cp - 1];
+
+      vty_backward_char (vty);
+      vty_self_insert_overwrite (vty, c1);
+      vty_self_insert_overwrite (vty, c2);
+    }
+}
+
+/* Do completion at vty interface. */
+static void
+vty_complete_command (struct vty *vty)
+{
+  int i;
+  int ret;
+  char **matched = NULL;
+  vector vline;
+
+  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+    return;
+
+  vline = cmd_make_strvec (vty->buf);
+  if (vline == NULL)
+    return;
+
+  /* In case of 'help \t'. */
+  if (isspace ((int) vty->buf[vty->length - 1]))
+    vector_set (vline, '\0');
+
+  matched = cmd_complete_command (vline, vty, &ret);
+  
+  cmd_free_strvec (vline);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+  switch (ret)
+    {
+    case CMD_ERR_AMBIGUOUS:
+      vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    case CMD_ERR_NO_MATCH:
+      /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    case CMD_COMPLETE_FULL_MATCH:
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      vty_backward_pure_word (vty);
+      vty_insert_word_overwrite (vty, matched[0]);
+      vty_self_insert (vty, ' ');
+      XFREE (MTYPE_TMP, matched[0]);
+      break;
+    case CMD_COMPLETE_MATCH:
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      vty_backward_pure_word (vty);
+      vty_insert_word_overwrite (vty, matched[0]);
+      XFREE (MTYPE_TMP, matched[0]);
+      vector_only_index_free (matched);
+      return;
+      break;
+    case CMD_COMPLETE_LIST_MATCH:
+      for (i = 0; matched[i] != NULL; i++)
+       {
+         if (i != 0 && ((i % 6) == 0))
+           vty_out (vty, "%s", VTY_NEWLINE);
+         vty_out (vty, "%-10s ", matched[i]);
+         XFREE (MTYPE_TMP, matched[i]);
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    case CMD_ERR_NOTHING_TODO:
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    default:
+      break;
+    }
+  if (matched)
+    vector_only_index_free (matched);
+}
+
+void
+vty_describe_fold (struct vty *vty, int cmd_width,
+                 int desc_width, struct desc *desc)
+{
+  char *buf, *cmd, *p;
+  int pos;
+
+  cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
+
+  if (desc_width <= 0)
+    {
+      vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
+      return;
+    }
+
+  buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
+
+  for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
+    {
+      for (pos = desc_width; pos > 0; pos--)
+      if (*(p + pos) == ' ')
+        break;
+
+      if (pos == 0)
+      break;
+
+      strncpy (buf, p, pos);
+      buf[pos] = '\0';
+      vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
+
+      cmd = "";
+    }
+
+  vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
+
+  XFREE (MTYPE_TMP, buf);
+}
+
+/* Describe matched command function. */
+static void
+vty_describe_command (struct vty *vty)
+{
+  int ret;
+  vector vline;
+  vector describe;
+  int i, width, desc_width;
+  struct desc *desc, *desc_cr = NULL;
+
+  vline = cmd_make_strvec (vty->buf);
+
+  /* In case of '> ?'. */
+  if (vline == NULL)
+    {
+      vline = vector_init (1);
+      vector_set (vline, '\0');
+    }
+  else 
+    if (isspace ((int) vty->buf[vty->length - 1]))
+      vector_set (vline, '\0');
+
+  describe = cmd_describe_command (vline, vty, &ret);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  /* Ambiguous error. */
+  switch (ret)
+    {
+    case CMD_ERR_AMBIGUOUS:
+      cmd_free_strvec (vline);
+      vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      return;
+      break;
+    case CMD_ERR_NO_MATCH:
+      cmd_free_strvec (vline);
+      vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      return;
+      break;
+    }  
+
+  /* Get width of command string. */
+  width = 0;
+  for (i = 0; i < vector_max (describe); i++)
+    if ((desc = vector_slot (describe, i)) != NULL)
+      {
+       int len;
+
+       if (desc->cmd[0] == '\0')
+         continue;
+
+       len = strlen (desc->cmd);
+       if (desc->cmd[0] == '.')
+         len--;
+
+       if (width < len)
+         width = len;
+      }
+
+  /* Get width of description string. */
+  desc_width = vty->width - (width + 6);
+
+  /* Print out description. */
+  for (i = 0; i < vector_max (describe); i++)
+    if ((desc = vector_slot (describe, i)) != NULL)
+      {
+       if (desc->cmd[0] == '\0')
+         continue;
+       
+       if (strcmp (desc->cmd, "<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 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;
+#if 0 /* More line does not work for "show ip bgp".  */
+           case '\n':
+           case '\r':
+             vty->status = VTY_MORELINE;
+             break;
+#endif
+           default:
+             if (vty->output_func)
+               (*vty->output_func) (vty, 0);
+             break;
+           }
+         continue;
+       }
+
+      /* Escape character. */
+      if (vty->escape == VTY_ESCAPE)
+       {
+         vty_escape_map (buf[i], vty);
+         continue;
+       }
+
+      /* Pre-escape status. */
+      if (vty->escape == VTY_PRE_ESCAPE)
+       {
+         switch (buf[i])
+           {
+           case '[':
+             vty->escape = VTY_ESCAPE;
+             break;
+           case 'b':
+             vty_backward_word (vty);
+             vty->escape = VTY_NORMAL;
+             break;
+           case 'f':
+             vty_forward_word (vty);
+             vty->escape = VTY_NORMAL;
+             break;
+           case 'd':
+             vty_forward_kill_word (vty);
+             vty->escape = VTY_NORMAL;
+             break;
+           case CONTROL('H'):
+           case 0x7f:
+             vty_backward_kill_word (vty);
+             vty->escape = VTY_NORMAL;
+             break;
+           default:
+             vty->escape = VTY_NORMAL;
+             break;
+           }
+         continue;
+       }
+
+      switch (buf[i])
+       {
+       case CONTROL('A'):
+         vty_beginning_of_line (vty);
+         break;
+       case CONTROL('B'):
+         vty_backward_char (vty);
+         break;
+       case CONTROL('C'):
+         vty_stop_input (vty);
+         break;
+       case CONTROL('D'):
+         vty_delete_char (vty);
+         break;
+       case CONTROL('E'):
+         vty_end_of_line (vty);
+         break;
+       case CONTROL('F'):
+         vty_forward_char (vty);
+         break;
+       case CONTROL('H'):
+       case 0x7f:
+         vty_delete_backward_char (vty);
+         break;
+       case CONTROL('K'):
+         vty_kill_line (vty);
+         break;
+       case CONTROL('N'):
+         vty_next_line (vty);
+         break;
+       case CONTROL('P'):
+         vty_previous_line (vty);
+         break;
+       case CONTROL('T'):
+         vty_transpose_chars (vty);
+         break;
+       case CONTROL('U'):
+         vty_kill_line_from_beginning (vty);
+         break;
+       case CONTROL('W'):
+         vty_backward_kill_word (vty);
+         break;
+       case CONTROL('Z'):
+         vty_end_config (vty);
+         break;
+       case '\n':
+       case '\r':
+         vty_out (vty, "%s", VTY_NEWLINE);
+         vty_execute (vty);
+         break;
+       case '\t':
+         vty_complete_command (vty);
+         break;
+       case '?':
+         if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+           vty_self_insert (vty, buf[i]);
+         else
+           vty_describe_command (vty);
+         break;
+       case '\033':
+         if (i + 1 < nbytes && buf[i + 1] == '[')
+           {
+             vty->escape = VTY_ESCAPE;
+             i++;
+           }
+         else
+           vty->escape = VTY_PRE_ESCAPE;
+         break;
+       default:
+         if (buf[i] > 31 && buf[i] < 127)
+           vty_self_insert (vty, buf[i]);
+         break;
+       }
+    }
+
+  /* Check status. */
+  if (vty->status == VTY_CLOSE)
+    vty_close (vty);
+  else
+    {
+      vty_event (VTY_WRITE, vty_sock, vty);
+      vty_event (VTY_READ, vty_sock, vty);
+    }
+  return 0;
+}
+
+/* Flush buffer to the vty. */
+static int
+vty_flush (struct thread *thread)
+{
+  int erase;
+  int dont_more;
+  int vty_sock = THREAD_FD (thread);
+  struct vty *vty = THREAD_ARG (thread);
+  vty->t_write = NULL;
+
+  /* Tempolary disable read thread. */
+  if (vty->lines == 0)
+    if (vty->t_read)
+      {
+       thread_cancel (vty->t_read);
+       vty->t_read = NULL;
+      }
+
+  /* Function execution continue. */
+  if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
+    {
+      if (vty->status == VTY_CONTINUE)
+       erase = 1;
+      else
+       erase = 0;
+
+      if (vty->output_func == NULL)
+       dont_more = 1;
+      else
+       dont_more = 0;
+
+      if (vty->lines == 0)
+       {
+         erase = 0;
+         dont_more = 1;
+       }
+
+      buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
+
+      if (vty->status == VTY_CLOSE)
+       {
+         vty_close (vty);
+         return 0;
+       }
+
+      if (vty->output_func == NULL)
+       {
+         vty->status = VTY_NORMAL;
+         vty_prompt (vty);
+         vty_event (VTY_WRITE, vty_sock, vty);
+       }
+      else
+       vty->status = VTY_MORE;
+
+      if (vty->lines == 0)
+       {
+         if (vty->output_func == NULL)
+           vty_event (VTY_READ, vty_sock, vty);
+         else
+           {
+             if (vty->output_func)
+               (*vty->output_func) (vty, 0);
+             vty_event (VTY_WRITE, vty_sock, vty);
+           }
+       }
+    }
+  else
+    {
+      if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
+       erase = 1;
+      else
+       erase = 0;
+
+      if (vty->lines == 0)
+       buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
+      else if (vty->status == VTY_MORELINE)
+       buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
+      else
+       buffer_flush_window (vty->obuf, vty->fd, vty->width,
+                            vty->lines >= 0 ? vty->lines : vty->height,
+                            erase, 0);
+  
+      if (buffer_empty (vty->obuf))
+       {
+         if (vty->status == VTY_CLOSE)
+           vty_close (vty);
+         else
+           {
+             vty->status = VTY_NORMAL;
+         
+             if (vty->lines == 0)
+               vty_event (VTY_READ, vty_sock, vty);
+           }
+       }
+      else
+       {
+         vty->status = VTY_MORE;
+
+         if (vty->lines == 0)
+           vty_event (VTY_WRITE, vty_sock, vty);
+       }
+    }
+
+  return 0;
+}
+
+/* Create new vty structure. */
+struct vty *
+vty_create (int vty_sock, union sockunion *su)
+{
+  struct vty *vty;
+
+  /* Allocate new vty structure and set up default values. */
+  vty = vty_new ();
+  vty->fd = vty_sock;
+  vty->type = VTY_TERM;
+  vty->address = sockunion_su2str (su);
+  if (no_password_check)
+    {
+      if (host.advanced)
+       vty->node = ENABLE_NODE;
+      else
+       vty->node = VIEW_NODE;
+    }
+  else
+    vty->node = AUTH_NODE;
+  vty->fail = 0;
+  vty->cp = 0;
+  vty_clear_buf (vty);
+  vty->length = 0;
+  memset (vty->hist, 0, sizeof (vty->hist));
+  vty->hp = 0;
+  vty->hindex = 0;
+  vector_set_index (vtyvec, vty_sock, vty);
+  vty->status = VTY_NORMAL;
+  vty->v_timeout = vty_timeout_val;
+  if (host.lines >= 0)
+    vty->lines = host.lines;
+  else
+    vty->lines = -1;
+  vty->iac = 0;
+  vty->iac_sb_in_progress = 0;
+  vty->sb_buffer = buffer_new (1024);
+
+  if (! no_password_check)
+    {
+      /* Vty is not available if password isn't set. */
+      if (host.password == NULL && host.password_encrypt == NULL)
+       {
+         vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+         vty->status = VTY_CLOSE;
+         vty_close (vty);
+         return NULL;
+       }
+    }
+
+  /* Say hello to the world. */
+  vty_hello (vty);
+  if (! no_password_check)
+    vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+  /* Setting up terminal. */
+  vty_will_echo (vty);
+  vty_will_suppress_go_ahead (vty);
+
+  vty_dont_linemode (vty);
+  vty_do_window_size (vty);
+  /* vty_dont_lflow_ahead (vty); */
+
+  vty_prompt (vty);
+
+  /* Add read/write thread. */
+  vty_event (VTY_WRITE, vty_sock, vty);
+  vty_event (VTY_READ, vty_sock, vty);
+
+  return vty;
+}
+
+/* Accept connection from the network. */
+static int
+vty_accept (struct thread *thread)
+{
+  int vty_sock;
+  struct vty *vty;
+  union sockunion su;
+  int ret;
+  unsigned int on;
+  int accept_sock;
+  struct prefix *p = NULL;
+  struct access_list *acl = NULL;
+
+  accept_sock = THREAD_FD (thread);
+
+  /* We continue hearing vty socket. */
+  vty_event (VTY_SERV, accept_sock, NULL);
+
+  memset (&su, 0, sizeof (union sockunion));
+
+  /* We can handle IPv4 or IPv6 socket. */
+  vty_sock = sockunion_accept (accept_sock, &su);
+  if (vty_sock < 0)
+    {
+      zlog_warn ("can't accept vty socket : %s", strerror (errno));
+      return -1;
+    }
+
+  p = sockunion2hostprefix (&su);
+
+  /* VTY's accesslist apply. */
+  if (p->family == AF_INET && vty_accesslist_name)
+    {
+      if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
+         (access_list_apply (acl, p) == FILTER_DENY))
+       {
+         char *buf;
+         zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+               (buf = sockunion_su2str (&su)));
+         free (buf);
+         close (vty_sock);
+         
+         /* continue accepting connections */
+         vty_event (VTY_SERV, accept_sock, NULL);
+         
+         prefix_free (p);
+
+         return 0;
+       }
+    }
+
+#ifdef HAVE_IPV6
+  /* VTY's ipv6 accesslist apply. */
+  if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
+    {
+      if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
+         (access_list_apply (acl, p) == FILTER_DENY))
+       {
+         char *buf;
+         zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+               (buf = sockunion_su2str (&su)));
+         free (buf);
+         close (vty_sock);
+         
+         /* continue accepting connections */
+         vty_event (VTY_SERV, accept_sock, NULL);
+         
+         prefix_free (p);
+
+         return 0;
+       }
+    }
+#endif /* HAVE_IPV6 */
+  
+  prefix_free (p);
+
+  on = 1;
+  ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, 
+                   (char *) &on, sizeof (on));
+  if (ret < 0)
+    zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
+         strerror (errno));
+
+  vty = vty_create (vty_sock, &su);
+
+  return 0;
+}
+
+#if defined(HAVE_IPV6) && !defined(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;
+}
+\f
+/* 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;
+    }
+}
+\f
+DEFUN (config_who,
+       config_who_cmd,
+       "who",
+       "Display who is on vty\n")
+{
+  int i;
+  struct vty *v;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((v = vector_slot (vtyvec, i)) != NULL)
+      vty_out (vty, "%svty[%d] connected from %s.%s",
+              v->config ? "*" : " ",
+              i, v->address, VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+/* Move to vty configuration mode. */
+DEFUN (line_vty,
+       line_vty_cmd,
+       "line vty",
+       "Configure a terminal line\n"
+       "Virtual terminal\n")
+{
+  vty->node = VTY_NODE;
+  return CMD_SUCCESS;
+}
+
+/* Set time out value. */
+int
+exec_timeout (struct vty *vty, char *min_str, char *sec_str)
+{
+  unsigned long timeout = 0;
+
+  /* min_str and sec_str are already checked by parser.  So it must be
+     all digit string. */
+  if (min_str)
+    {
+      timeout = strtol (min_str, NULL, 10);
+      timeout *= 60;
+    }
+  if (sec_str)
+    timeout += strtol (sec_str, NULL, 10);
+
+  vty_timeout_val = timeout;
+  vty->v_timeout = timeout;
+  vty_event (VTY_TIMEOUT_RESET, 0, vty);
+
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (exec_timeout_min,
+       exec_timeout_min_cmd,
+       "exec-timeout <0-35791>",
+       "Set timeout value\n"
+       "Timeout value in minutes\n")
+{
+  return exec_timeout (vty, argv[0], NULL);
+}
+
+DEFUN (exec_timeout_sec,
+       exec_timeout_sec_cmd,
+       "exec-timeout <0-35791> <0-2147483>",
+       "Set the EXEC timeout\n"
+       "Timeout in minutes\n"
+       "Timeout in seconds\n")
+{
+  return exec_timeout (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_exec_timeout,
+       no_exec_timeout_cmd,
+       "no exec-timeout",
+       NO_STR
+       "Set the EXEC timeout\n")
+{
+  return exec_timeout (vty, NULL, NULL);
+}
+
+/* Set vty access class. */
+DEFUN (vty_access_class,
+       vty_access_class_cmd,
+       "access-class WORD",
+       "Filter connections based on an IP access list\n"
+       "IP access list\n")
+{
+  if (vty_accesslist_name)
+    XFREE(MTYPE_VTY, vty_accesslist_name);
+
+  vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+/* Clear vty access class. */
+DEFUN (no_vty_access_class,
+       no_vty_access_class_cmd,
+       "no access-class [WORD]",
+       NO_STR
+       "Filter connections based on an IP access list\n"
+       "IP access list\n")
+{
+  if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
+    {
+      vty_out (vty, "Access-class is not currently applied to vty%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  XFREE(MTYPE_VTY, vty_accesslist_name);
+
+  vty_accesslist_name = NULL;
+
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Set vty access class. */
+DEFUN (vty_ipv6_access_class,
+       vty_ipv6_access_class_cmd,
+       "ipv6 access-class WORD",
+       IPV6_STR
+       "Filter connections based on an IP access list\n"
+       "IPv6 access list\n")
+{
+  if (vty_ipv6_accesslist_name)
+    XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+
+  vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+/* Clear vty access class. */
+DEFUN (no_vty_ipv6_access_class,
+       no_vty_ipv6_access_class_cmd,
+       "no ipv6 access-class [WORD]",
+       NO_STR
+       IPV6_STR
+       "Filter connections based on an IP access list\n"
+       "IPv6 access list\n")
+{
+  if (! vty_ipv6_accesslist_name ||
+      (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
+    {
+      vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+
+  vty_ipv6_accesslist_name = NULL;
+
+  return CMD_SUCCESS;
+}
+#endif /* HAVE_IPV6 */
+
+/* vty login. */
+DEFUN (vty_login,
+       vty_login_cmd,
+       "login",
+       "Enable password checking\n")
+{
+  no_password_check = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_vty_login,
+       no_vty_login_cmd,
+       "no login",
+       NO_STR
+       "Enable password checking\n")
+{
+  no_password_check = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (service_advanced_vty,
+       service_advanced_vty_cmd,
+       "service advanced-vty",
+       "Set up miscellaneous service\n"
+       "Enable advanced mode vty interface\n")
+{
+  host.advanced = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_service_advanced_vty,
+       no_service_advanced_vty_cmd,
+       "no service advanced-vty",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Enable advanced mode vty interface\n")
+{
+  host.advanced = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (terminal_monitor,
+       terminal_monitor_cmd,
+       "terminal monitor",
+       "Set terminal line parameters\n"
+       "Copy debug output to the current terminal line\n")
+{
+  vty->monitor = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (terminal_no_monitor,
+       terminal_no_monitor_cmd,
+       "terminal no monitor",
+       "Set terminal line parameters\n"
+       NO_STR
+       "Copy debug output to the current terminal line\n")
+{
+  vty->monitor = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_history,
+       show_history_cmd,
+       "show history",
+       SHOW_STR
+       "Display the session command history\n")
+{
+  int index;
+
+  for (index = vty->hindex + 1; index != vty->hindex;)
+    {
+      if (index == VTY_MAXHIST)
+       {
+         index = 0;
+         continue;
+       }
+
+      if (vty->hist[index] != NULL)
+       vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
+
+      index++;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Display current configuration. */
+int
+vty_config_write (struct vty *vty)
+{
+  vty_out (vty, "line vty%s", VTY_NEWLINE);
+
+  if (vty_accesslist_name)
+    vty_out (vty, " access-class %s%s",
+            vty_accesslist_name, VTY_NEWLINE);
+
+  if (vty_ipv6_accesslist_name)
+    vty_out (vty, " ipv6 access-class %s%s",
+            vty_ipv6_accesslist_name, VTY_NEWLINE);
+
+  /* exec-timeout */
+  if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
+    vty_out (vty, " exec-timeout %ld %ld%s", 
+            vty_timeout_val / 60,
+            vty_timeout_val % 60, VTY_NEWLINE);
+
+  /* login */
+  if (no_password_check)
+    vty_out (vty, " no login%s", VTY_NEWLINE);
+
+  vty_out (vty, "!%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+struct cmd_node vty_node =
+{
+  VTY_NODE,
+  "%s(config-line)# ",
+};
+
+/* Reset all VTY status. */
+void
+vty_reset ()
+{
+  int i;
+  struct vty *vty;
+  struct thread *vty_serv_thread;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((vty = vector_slot (vtyvec, i)) != NULL)
+      {
+       buffer_reset (vty->obuf);
+       vty->status = VTY_CLOSE;
+       vty_close (vty);
+      }
+
+  for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+    if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+      {
+       thread_cancel (vty_serv_thread);
+       vector_slot (Vvty_serv_thread, i) = NULL;
+        close (i);
+      }
+
+  vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+  if (vty_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_accesslist_name);
+      vty_accesslist_name = NULL;
+    }
+
+  if (vty_ipv6_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+      vty_ipv6_accesslist_name = NULL;
+    }
+}
+
+/* for ospf6d easy temprary reload function */
+/* vty_reset + close accept socket */
+void
+vty_finish ()
+{
+  int i;
+  struct vty *vty;
+  struct thread *vty_serv_thread;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((vty = vector_slot (vtyvec, i)) != NULL)
+      {
+       buffer_reset (vty->obuf);
+       vty->status = VTY_CLOSE;
+       vty_close (vty);
+      }
+
+  for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+    if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+      {
+       thread_cancel (vty_serv_thread);
+       vector_slot (Vvty_serv_thread, i) = NULL;
+        close (i);
+      }
+
+  vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+  if (vty_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_accesslist_name);
+      vty_accesslist_name = NULL;
+    }
+
+  if (vty_ipv6_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+      vty_ipv6_accesslist_name = NULL;
+    }
+}
+
+void
+vty_save_cwd ()
+{
+  char *cwd;
+
+  cwd = getcwd (NULL, MAXPATHLEN);
+
+  vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
+  strcpy (vty_cwd, cwd);
+}
+
+char *
+vty_get_cwd ()
+{
+  return vty_cwd;
+}
+
+int
+vty_shell (struct vty *vty)
+{
+  return vty->type == VTY_SHELL ? 1 : 0;
+}
+
+int
+vty_shell_serv (struct vty *vty)
+{
+  return vty->type == VTY_SHELL_SERV ? 1 : 0;
+}
+
+void
+vty_init_vtysh ()
+{
+  vtyvec = vector_init (VECTOR_MIN_SIZE);
+}
+
+/* Install vty's own commands like `who' command. */
+void
+vty_init ()
+{
+  /* For further configuration read, preserve current directory. */
+  vty_save_cwd ();
+
+  vtyvec = vector_init (VECTOR_MIN_SIZE);
+
+  /* Initilize server thread vector. */
+  Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
+
+  /* Install bgp top node. */
+  install_node (&vty_node, vty_config_write);
+
+  install_element (VIEW_NODE, &config_who_cmd);
+  install_element (VIEW_NODE, &show_history_cmd);
+  install_element (ENABLE_NODE, &config_who_cmd);
+  install_element (CONFIG_NODE, &line_vty_cmd);
+  install_element (CONFIG_NODE, &service_advanced_vty_cmd);
+  install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
+  install_element (CONFIG_NODE, &show_history_cmd);
+  install_element (ENABLE_NODE, &terminal_monitor_cmd);
+  install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
+  install_element (ENABLE_NODE, &show_history_cmd);
+
+  install_default (VTY_NODE);
+  install_element (VTY_NODE, &exec_timeout_min_cmd);
+  install_element (VTY_NODE, &exec_timeout_sec_cmd);
+  install_element (VTY_NODE, &no_exec_timeout_cmd);
+  install_element (VTY_NODE, &vty_access_class_cmd);
+  install_element (VTY_NODE, &no_vty_access_class_cmd);
+  install_element (VTY_NODE, &vty_login_cmd);
+  install_element (VTY_NODE, &no_vty_login_cmd);
+#ifdef HAVE_IPV6
+  install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
+  install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
+#endif /* HAVE_IPV6 */
+}
diff --git a/lib/vty.h b/lib/vty.h
new file mode 100644 (file)
index 0000000..4d2a6a0
--- /dev/null
+++ b/lib/vty.h
@@ -0,0 +1,205 @@
+/* Virtual terminal [aka TeletYpe] interface routine
+   Copyright (C) 1997 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef _ZEBRA_VTY_H
+#define _ZEBRA_VTY_H
+
+#define VTY_BUFSIZ 512
+#define VTY_MAXHIST 20
+
+/* VTY struct. */
+struct vty 
+{
+  /* File descripter of this vty. */
+  int fd;
+
+  /* Is this vty connect to file or not */
+  enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type;
+
+  /* Node status of this vty */
+  int node;
+
+  /* What address is this vty comming from. */
+  char *address;
+
+  /* Privilege level of this vty. */
+  int privilege;
+
+  /* Failure count */
+  int fail;
+
+  /* Output buffer. */
+  struct buffer *obuf;
+
+  /* Command input buffer */
+  char *buf;
+
+  /* Command cursor point */
+  int cp;
+
+  /* Command length */
+  int length;
+
+  /* Command max length. */
+  int max;
+
+  /* Histry of command */
+  char *hist[VTY_MAXHIST];
+
+  /* History lookup current point */
+  int hp;
+
+  /* History insert end point */
+  int hindex;
+
+  /* For current referencing point of interface, route-map,
+     access-list etc... */
+  void *index;
+
+  /* For multiple level index treatment such as key chain and key. */
+  void *index_sub;
+
+  /* For escape character. */
+  unsigned char escape;
+
+  /* Current vty status. */
+  enum {VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE,
+        VTY_START, VTY_CONTINUE} status;
+
+  /* IAC handling */
+  unsigned char iac;
+
+  /* IAC SB handling */
+  unsigned char iac_sb_in_progress;
+  struct buffer *sb_buffer;
+
+  /* Window width/height. */
+  int width;
+  int height;
+
+  int scroll_one;
+
+  /* Configure lines. */
+  int lines;
+
+  /* Current executing function pointer. */
+  int (*func) (struct vty *, void *arg);
+
+  /* Terminal monitor. */
+  int monitor;
+
+  /* In configure mode. */
+  int config;
+
+  /* Read and write thread. */
+  struct thread *t_read;
+  struct thread *t_write;
+
+  /* Timeout seconds and thread. */
+  unsigned long v_timeout;
+  struct thread *t_timeout;
+
+  /* Thread output function. */
+  struct thread *t_output;
+
+  /* Output data pointer. */
+  int (*output_func) (struct vty *, int);
+  void (*output_clean) (struct vty *);
+  void *output_rn;
+  unsigned long output_count;
+  int output_type;
+  void *output_arg;
+};
+
+/* Integrated configuration file. */
+#define INTEGRATE_DEFAULT_CONFIG "Zebra.conf"
+
+/* Small macro to determine newline is newline only or linefeed needed. */
+#define VTY_NEWLINE  ((vty->type == VTY_TERM) ? "\r\n" : "\n")
+
+/* Default time out value */
+#define VTY_TIMEOUT_DEFAULT 600
+
+/* Vty read buffer size. */
+#define VTY_READ_BUFSIZ 512
+
+/* Directory separator. */
+#ifndef DIRECTORY_SEP
+#define DIRECTORY_SEP '/'
+#endif /* DIRECTORY_SEP */
+
+#ifndef IS_DIRECTORY_SEP
+#define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP)
+#endif
+
+/* GCC have printf type attribute check.  */
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* __GNUC__ */
+
+/* Utility macro to convert VTY argument to unsigned integer.  */
+#define VTY_GET_INTEGER(NAME,V,STR)                              \
+{                                                                \
+  char *endptr = NULL;                                           \
+  (V) = strtoul ((STR), &endptr, 10);                            \
+  if ((V) == ULONG_MAX || *endptr != '\0')                       \
+    {                                                            \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
+      return CMD_WARNING;                                        \
+    }                                                            \
+}
+
+#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX)                \
+{                                                                \
+  char *endptr = NULL;                                           \
+  (V) = strtoul ((STR), &endptr, 10);                            \
+  if ((V) == ULONG_MAX || *endptr != '\0'                        \
+      || (V) < (MIN) || (V) > (MAX))                             \
+    {                                                            \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
+      return CMD_WARNING;                                        \
+    }                                                            \
+}
+
+/* Exported variables */
+extern char integrate_default[];
+
+/* Prototypes. */
+void vty_init (void);
+void vty_init_vtysh (void);
+void vty_reset (void);
+void vty_finish (void);
+struct vty *vty_new (void);
+int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+void vty_read_config (char *, char *, char *);
+void vty_time_print (struct vty *, int);
+void vty_serv_sock (const char *, unsigned short, char *);
+void vty_close (struct vty *);
+char *vty_get_cwd (void);
+void vty_log (const char *, const char *, va_list);
+int vty_config_lock (struct vty *);
+int vty_config_unlock (struct vty *);
+int vty_shell (struct vty *);
+int vty_shell_serv (struct vty *);
+void vty_hello (struct vty *);
+
+#endif /* _ZEBRA_VTY_H */
diff --git a/lib/zclient.c b/lib/zclient.c
new file mode 100644 (file)
index 0000000..5e37154
--- /dev/null
@@ -0,0 +1,901 @@
+/* Zebra's client library.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "stream.h"
+#include "network.h"
+#include "if.h"
+#include "log.h"
+#include "thread.h"
+#include "zclient.h"
+#include "memory.h"
+#include "table.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+\f
+/* Zebra client events. */
+enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT};
+
+/* Prototype for event manager. */
+static void zclient_event (enum event, struct zclient *);
+
+/* This file local debug flag. */
+int zclient_debug = 0;
+\f
+/* Allocate zclient structure. */
+struct zclient *
+zclient_new ()
+{
+  struct zclient *zclient;
+  zclient = XMALLOC (MTYPE_ZCLIENT, sizeof (struct zclient));
+  memset (zclient, 0, sizeof (struct zclient));
+
+  zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+  zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+
+  return zclient;
+}
+
+/* Free zclient structure. */
+void
+zclient_free (struct zclient *zclient)
+{
+  XFREE (MTYPE_ZCLIENT, zclient);
+}
+
+/* Initialize zebra client.  Argument redist_default is unwanted
+   redistribute route type. */
+void
+zclient_init (struct zclient *zclient, int redist_default)
+{
+  int i;
+  
+  /* Enable zebra client connection by default. */
+  zclient->enable = 1;
+
+  /* Set -1 to the default socket value. */
+  zclient->sock = -1;
+
+  /* Clear redistribution flags. */
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    zclient->redist[i] = 0;
+
+  /* Set unwanted redistribute route.  bgpd does not need BGP route
+     redistribution. */
+  zclient->redist_default = redist_default;
+  zclient->redist[redist_default] = 1;
+
+  /* Set default-information redistribute to zero. */
+  zclient->default_information = 0;
+
+  /* Schedule first zclient connection. */
+  if (zclient_debug)
+    zlog_info ("zclient start scheduled");
+
+  zclient_event (ZCLIENT_SCHEDULE, zclient);
+}
+
+/* Stop zebra client services. */
+void
+zclient_stop (struct zclient *zclient)
+{
+  if (zclient_debug)
+    zlog_info ("zclient stopped");
+
+  /* Stop threads. */
+  if (zclient->t_read)
+    {
+      thread_cancel (zclient->t_read);
+      zclient->t_read = NULL;
+   }
+  if (zclient->t_connect)
+    {
+      thread_cancel (zclient->t_connect);
+      zclient->t_connect = NULL;
+    }
+
+  /* Close socket. */
+  if (zclient->sock >= 0)
+    {
+      close (zclient->sock);
+      zclient->sock = -1;
+    }
+  zclient->fail = 0;
+}
+
+void
+zclient_reset (struct zclient *zclient)
+{
+  zclient_stop (zclient);
+  zclient_init (zclient, zclient->redist_default);
+}
+
+/* Make socket to zebra daemon. Return zebra socket. */
+int
+zclient_socket ()
+{
+  int sock;
+  int ret;
+  struct sockaddr_in serv;
+
+  /* We should think about IPv6 connection. */
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+  
+  /* Make server socket. */ 
+  memset (&serv, 0, sizeof (struct sockaddr_in));
+  serv.sin_family = AF_INET;
+  serv.sin_port = htons (ZEBRA_PORT);
+#ifdef HAVE_SIN_LEN
+  serv.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  /* Connect to zebra. */
+  ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv));
+  if (ret < 0)
+    {
+      close (sock);
+      return -1;
+    }
+  return sock;
+}
+
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+int
+zclient_socket_un (char *path)
+{
+  int ret;
+  int sock, len;
+  struct sockaddr_un addr;
+
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+  
+  /* Make server socket. */ 
+  memset (&addr, 0, sizeof (struct sockaddr_un));
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+  len = addr.sun_len = SUN_LEN(&addr);
+#else
+  len = sizeof (addr.sun_family) + strlen (addr.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+  ret = connect (sock, (struct sockaddr *) &addr, len);
+  if (ret < 0)
+    {
+      close (sock);
+      return -1;
+    }
+  return sock;
+}
+
+/* Send simple Zebra message. */
+int
+zebra_message_send (struct zclient *zclient, int command)
+{
+  struct stream *s;
+
+  /* Get zclient output buffer. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Send very simple command only Zebra message. */
+  stream_putw (s, 3);
+  stream_putc (s, command);
+
+  return writen (zclient->sock, s->data, 3);
+}
+
+/* Make connection to zebra daemon. */
+int
+zclient_start (struct zclient *zclient)
+{
+  int i;
+
+  if (zclient_debug)
+    zlog_info ("zclient_start is called");
+
+  /* zclient is disabled. */
+  if (! zclient->enable)
+    return 0;
+
+  /* If already connected to the zebra. */
+  if (zclient->sock >= 0)
+    return 0;
+
+  /* Check connect thread. */
+  if (zclient->t_connect)
+    return 0;
+
+  /* Make socket. */
+#ifdef HAVE_TCP_ZEBRA
+  zclient->sock = zclient_socket ();
+#else
+  zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+  if (zclient->sock < 0)
+    {
+      if (zclient_debug)
+       zlog_info ("zclient connection fail");
+      zclient->fail++;
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return -1;
+    }
+
+  /* Clear fail count. */
+  zclient->fail = 0;
+  if (zclient_debug)
+    zlog_info ("zclient connect success with socket [%d]", zclient->sock);
+      
+  /* Create read thread. */
+  zclient_event (ZCLIENT_READ, zclient);
+
+  /* We need interface information. */
+  zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
+
+  /* Flush all redistribute request. */
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    if (i != zclient->redist_default && zclient->redist[i])
+      zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, i);
+
+  /* If default information is needed. */
+  if (zclient->default_information)
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD);
+
+  return 0;
+}
+
+/* This function is a wrapper function for calling zclient_start from
+   timer or event thread. */
+int
+zclient_connect (struct thread *t)
+{
+  struct zclient *zclient;
+
+  zclient = THREAD_ARG (t);
+  zclient->t_connect = NULL;
+
+  if (zclient_debug)
+    zlog_info ("zclient_connect is called");
+
+  return zclient_start (zclient);
+}
+\f
+int
+zapi_ipv4_add (struct zclient *zclient, struct prefix_ipv4 *p,
+              struct zapi_ipv4 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+       {
+         stream_putc (s, 1);
+         stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+       }
+      else
+       stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+         stream_put_in_addr (s, api->nexthop[i]);
+       }
+      for (i = 0; i < api->ifindex_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+         stream_putl (s, api->ifindex[i]);
+       }
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+int
+zapi_ipv4_delete (struct zclient *zclient, struct prefix_ipv4 *p,
+                 struct zapi_ipv4 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+       {
+         stream_putc (s, 1);
+         stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+       }
+      else
+       stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+         stream_put_in_addr (s, api->nexthop[i]);
+       }
+      for (i = 0; i < api->ifindex_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+         stream_putl (s, api->ifindex[i]);
+       }
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+#ifdef HAVE_IPV6
+int
+zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p,
+              struct zapi_ipv6 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_ADD);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+         stream_write (s, (u_char *)api->nexthop[i], 16);
+       }
+      for (i = 0; i < api->ifindex_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+         stream_putl (s, api->ifindex[i]);
+       }
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+int
+zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p,
+                 struct zapi_ipv6 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+         stream_write (s, (u_char *)api->nexthop[i], 16);
+       }
+      for (i = 0; i < api->ifindex_num; i++)
+       {
+         stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+         stream_putl (s, api->ifindex[i]);
+       }
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+#endif /* HAVE_IPV6 */
+
+int
+zebra_redistribute_send (int command, int sock, int type)
+{
+  int ret;
+  struct stream *s;
+
+  s = stream_new (ZEBRA_MAX_PACKET_SIZ);
+
+  /* Total length of the messages. */
+  stream_putw (s, 4);
+  
+  stream_putc (s, command);
+  stream_putc (s, type);
+
+  ret = writen (sock, s->data, 4);
+
+  stream_free (s);
+
+  return ret;
+}
+
+/* Interface addition from zebra daemon. */
+struct interface *
+zebra_interface_add_read (struct stream *s)
+{
+  struct interface *ifp;
+  u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+  /* Read interface name. */
+  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+  /* Lookup this by interface name. */
+  ifp = if_lookup_by_name (ifname_tmp);
+
+  /* If such interface does not exist, make new one. */
+  if (! ifp)
+    {
+      ifp = if_create ();
+      strncpy (ifp->name, ifname_tmp, IFNAMSIZ);
+    }
+
+  /* Read interface's index. */
+  ifp->ifindex = stream_getl (s);
+
+  /* Read interface's value. */
+  ifp->flags = stream_getl (s);
+  ifp->metric = stream_getl (s);
+  ifp->mtu = stream_getl (s);
+  ifp->bandwidth = stream_getl (s);
+#ifdef HAVE_SOCKADDR_DL
+  stream_get (&ifp->sdl, s, sizeof (ifp->sdl));
+#else
+  ifp->hw_addr_len = stream_getl (s);
+  if (ifp->hw_addr_len)
+    stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
+#endif /* HAVE_SOCKADDR_DL */
+  
+  return ifp;
+}
+
+/* Read interface up/down msg from zebra daemon. */
+struct interface *
+zebra_interface_state_read (struct stream *s)
+{
+  struct interface *ifp;
+  u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+  /* Read interface name. */
+  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+  /* Lookup this by interface index. */
+  ifp = if_lookup_by_name (ifname_tmp);
+
+  /* If such interface does not exist, indicate an error */
+  if (! ifp)
+     return NULL;
+
+  /* Read interface's index. */
+  ifp->ifindex = stream_getl (s);
+
+  /* Read interface's value. */
+  ifp->flags = stream_getl (s);
+  ifp->metric = stream_getl (s);
+  ifp->mtu = stream_getl (s);
+  ifp->bandwidth = stream_getl (s);
+
+  return ifp;
+}
+
+struct connected *
+zebra_interface_address_add_read (struct stream *s)
+{
+  unsigned int ifindex;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+  int family;
+  int plen;
+
+  /* Get interface index. */
+  ifindex = stream_getl (s);
+
+  /* Lookup index. */
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    {
+      zlog_warn ("zebra_interface_address_add_read: Can't find interface by ifindex: %d ", ifindex);
+      return NULL;
+    }
+
+  /* Allocate new connected address. */
+  ifc = connected_new ();
+  ifc->ifp = ifp;
+
+  /* Fetch flag. */
+  ifc->flags = stream_getc (s);
+
+  /* Fetch interface address. */
+  p = prefix_new ();
+  family = p->family = stream_getc (s);
+
+  plen = prefix_blen (p);
+  stream_get (&p->u.prefix, s, plen);
+  p->prefixlen = stream_getc (s);
+  ifc->address = p;
+
+  /* Fetch destination address. */
+  p = prefix_new ();
+  stream_get (&p->u.prefix, s, plen);
+  p->family = family;
+
+  ifc->destination = p;
+
+  p = ifc->address;
+
+  /* Add connected address to the interface. */
+  listnode_add (ifp->connected, ifc);
+
+  return ifc;
+}
+
+struct connected *
+zebra_interface_address_delete_read (struct stream *s)
+{
+  unsigned int ifindex;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix p;
+  struct prefix d;
+  int family;
+  int len;
+  u_char flags;
+
+  /* Get interface index. */
+  ifindex = stream_getl (s);
+
+  /* Lookup index. */
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    {
+      zlog_warn ("zebra_interface_address_delete_read: Can't find interface by ifindex: %d ", ifindex);
+      return NULL;
+    }
+
+  /* Fetch flag. */
+  flags = stream_getc (s);
+
+  /* Fetch interface address. */
+  family = p.family = stream_getc (s);
+
+  len = prefix_blen (&p);
+  stream_get (&p.u.prefix, s, len);
+  p.prefixlen = stream_getc (s);
+
+  /* Fetch destination address. */
+  stream_get (&d.u.prefix, s, len);
+  d.family = family;
+
+  ifc = connected_delete_by_prefix (ifp, &p);
+
+  return ifc;
+}
+\f
+/* Zebra client message read function. */
+int
+zclient_read (struct thread *thread)
+{
+  int ret;
+  int nbytes;
+  int sock;
+  zebra_size_t length;
+  zebra_command_t command;
+  struct zclient *zclient;
+
+  /* Get socket to zebra. */
+  sock = THREAD_FD (thread);
+  zclient = THREAD_ARG (thread);
+  zclient->t_read = NULL;
+
+  /* Clear input buffer. */
+  stream_reset (zclient->ibuf);
+
+  /* Read zebra header. */
+  nbytes = stream_read (zclient->ibuf, sock, ZEBRA_HEADER_SIZE);
+
+  /* zebra socket is closed. */
+  if (nbytes == 0) 
+    {
+      if (zclient_debug)
+       zlog_info ("zclient connection closed socket [%d].", sock);
+      zclient->fail++;
+      zclient_stop (zclient);
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return -1;
+    }
+
+  /* zebra read error. */
+  if (nbytes < 0 || nbytes != ZEBRA_HEADER_SIZE)
+    {
+      if (zclient_debug)
+       zlog_info ("Can't read all packet (length %d).", nbytes);
+      zclient->fail++;
+      zclient_stop (zclient);
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return -1;
+    }
+
+  /* Fetch length and command. */
+  length = stream_getw (zclient->ibuf);
+  command = stream_getc (zclient->ibuf);
+
+  /* Length check. */
+  if (length >= zclient->ibuf->size)
+    {
+      stream_free (zclient->ibuf);
+      zclient->ibuf = stream_new (length + 1);
+    }
+  length -= ZEBRA_HEADER_SIZE;
+
+  /* Read rest of zebra packet. */
+  nbytes = stream_read (zclient->ibuf, sock, length);
+ if (nbytes != length)
+   {
+     if (zclient_debug)
+       zlog_info ("zclient connection closed socket [%d].", sock);
+     zclient->fail++;
+     zclient_stop (zclient);
+     zclient_event (ZCLIENT_CONNECT, zclient);
+     return -1;
+   }
+
+  switch (command)
+    {
+    case ZEBRA_INTERFACE_ADD:
+      if (zclient->interface_add)
+       ret = (*zclient->interface_add) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_DELETE:
+      if (zclient->interface_delete)
+       ret = (*zclient->interface_delete) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_ADDRESS_ADD:
+      if (zclient->interface_address_add)
+       ret = (*zclient->interface_address_add) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_ADDRESS_DELETE:
+      if (zclient->interface_address_delete)
+       ret = (*zclient->interface_address_delete) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_UP:
+      if (zclient->interface_up)
+       ret = (*zclient->interface_up) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_DOWN:
+      if (zclient->interface_down)
+       ret = (*zclient->interface_down) (command, zclient, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_ADD:
+      if (zclient->ipv4_route_add)
+       ret = (*zclient->ipv4_route_add) (command, zclient, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_DELETE:
+      if (zclient->ipv4_route_delete)
+       ret = (*zclient->ipv4_route_delete) (command, zclient, length);
+      break;
+    case ZEBRA_IPV6_ROUTE_ADD:
+      if (zclient->ipv6_route_add)
+       ret = (*zclient->ipv6_route_add) (command, zclient, length);
+      break;
+    case ZEBRA_IPV6_ROUTE_DELETE:
+      if (zclient->ipv6_route_delete)
+       ret = (*zclient->ipv6_route_delete) (command, zclient, length);
+      break;
+    default:
+      break;
+    }
+
+  /* Register read thread. */
+  zclient_event (ZCLIENT_READ, zclient);
+
+  return 0;
+}
+
+void
+zclient_redistribute_set (struct zclient *zclient, int type)
+{
+  if (zclient->redist[type])
+    return;
+
+  zclient->redist[type] = 1;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+}
+
+void
+zclient_redistribute_unset (struct zclient *zclient, int type)
+{
+  if (! zclient->redist[type])
+    return;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+}
+
+void
+zclient_redistribute_default_set (struct zclient *zclient)
+{
+  if (zclient->default_information)
+    return;
+
+  zclient->default_information = 1;
+
+  if (zclient->sock > 0)
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD);
+}
+
+void
+zclient_redistribute_default_unset (struct zclient *zclient)
+{
+  if (! zclient->default_information)
+    return;
+
+  zclient->default_information = 0;
+
+  if (zclient->sock > 0)
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_DELETE);
+}
+\f
+extern struct thread_master *master;
+
+static void
+zclient_event (enum event event, struct zclient *zclient)
+{
+  switch (event)
+    {
+    case ZCLIENT_SCHEDULE:
+      if (! zclient->t_connect)
+       zclient->t_connect =
+         thread_add_event (master, zclient_connect, zclient, 0);
+      break;
+    case ZCLIENT_CONNECT:
+      if (zclient->fail >= 10)
+       return;
+      if (zclient_debug)
+       zlog_info ("zclient connect schedule interval is %d", 
+                  zclient->fail < 3 ? 10 : 60);
+      if (! zclient->t_connect)
+       zclient->t_connect = 
+         thread_add_timer (master, zclient_connect, zclient,
+                           zclient->fail < 3 ? 10 : 60);
+      break;
+    case ZCLIENT_READ:
+      zclient->t_read = 
+       thread_add_read (master, zclient_read, zclient, zclient->sock);
+      break;
+    }
+}
diff --git a/lib/zclient.h b/lib/zclient.h
new file mode 100644 (file)
index 0000000..66307c9
--- /dev/null
@@ -0,0 +1,164 @@
+/* Zebra's client header.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_ZCLIENT_H
+#define _ZEBRA_ZCLIENT_H
+
+/* For struct interface and struct connected. */
+#include "if.h"
+
+/* For input/output buffer to zebra. */
+#define ZEBRA_MAX_PACKET_SIZ          4096
+
+/* Zebra header size. */
+#define ZEBRA_HEADER_SIZE                3
+
+/* Structure for the zebra client. */
+struct zclient
+{
+  /* Socket to zebra daemon. */
+  int sock;
+
+  /* Flag of communication to zebra is enabled or not.  Default is on.
+     This flag is disabled by `no router zebra' statement. */
+  int enable;
+
+  /* Connection failure count. */
+  int fail;
+
+  /* Input buffer for zebra message. */
+  struct stream *ibuf;
+
+  /* Output buffer for zebra message. */
+  struct stream *obuf;
+
+  /* Read and connect thread. */
+  struct thread *t_read;
+  struct thread *t_connect;
+
+  /* Redistribute information. */
+  u_char redist_default;
+  u_char redist[ZEBRA_ROUTE_MAX];
+
+  /* Redistribute defauilt. */
+  u_char default_information;
+
+  /* Pointer to the callback functions. */
+  int (*interface_add) (int, struct zclient *, zebra_size_t);
+  int (*interface_delete) (int, struct zclient *, zebra_size_t);
+  int (*interface_up) (int, struct zclient *, zebra_size_t);
+  int (*interface_down) (int, struct zclient *, zebra_size_t);
+  int (*interface_address_add) (int, struct zclient *, zebra_size_t);
+  int (*interface_address_delete) (int, struct zclient *, zebra_size_t);
+  int (*ipv4_route_add) (int, struct zclient *, zebra_size_t);
+  int (*ipv4_route_delete) (int, struct zclient *, zebra_size_t);
+  int (*ipv6_route_add) (int, struct zclient *, zebra_size_t);
+  int (*ipv6_route_delete) (int, struct zclient *, zebra_size_t);
+};
+
+/* Zebra API message flag. */
+#define ZAPI_MESSAGE_NEXTHOP  0x01
+#define ZAPI_MESSAGE_IFINDEX  0x02
+#define ZAPI_MESSAGE_DISTANCE 0x04
+#define ZAPI_MESSAGE_METRIC   0x08
+
+/* Zebra IPv4 route message API. */
+struct zapi_ipv4
+{
+  u_char type;
+
+  u_char flags;
+
+  u_char message;
+
+  u_char nexthop_num;
+  struct in_addr **nexthop;
+
+  u_char ifindex_num;
+  unsigned int *ifindex;
+
+  u_char distance;
+
+  u_int32_t metric;
+};
+
+int
+zapi_ipv4_add (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *);
+
+int
+zapi_ipv4_delete (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *);
+
+/* Prototypes of zebra client service functions. */
+struct zclient *zclient_new (void);
+void zclient_free (struct zclient *);
+void zclient_init (struct zclient *, int);
+int zclient_start (struct zclient *);
+void zclient_stop (struct zclient *);
+void zclient_reset (struct zclient *);
+int zclient_socket ();
+int zclient_socket_un (char *);
+
+void zclient_redistribute_set (struct zclient *, int);
+void zclient_redistribute_unset (struct zclient *, int);
+
+void zclient_redistribute_default_set (struct zclient *);
+void zclient_redistribute_default_unset (struct zclient *);
+
+/* struct zebra *zebra_new (); */
+int zebra_redistribute_send (int, int, int);
+
+struct interface *zebra_interface_add_read (struct stream *);
+struct interface *zebra_interface_state_read (struct stream *s);
+struct connected *zebra_interface_address_add_read (struct stream *);
+struct connected *zebra_interface_address_delete_read (struct stream *);
+
+#ifdef HAVE_IPV6
+/* IPv6 prefix add and delete function prototype. */
+
+struct zapi_ipv6
+{
+  u_char type;
+
+  u_char flags;
+
+  u_char message;
+
+  u_char nexthop_num;
+  struct in6_addr **nexthop;
+
+  u_char ifindex_num;
+  unsigned int *ifindex;
+
+  u_char distance;
+
+  u_int32_t metric;
+};
+
+int
+zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p,
+              struct zapi_ipv6 *api);
+int
+zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p,
+                 struct zapi_ipv6 *api);
+
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_ZCLIENT_H */
diff --git a/lib/zebra.h b/lib/zebra.h
new file mode 100644 (file)
index 0000000..06302b3
--- /dev/null
@@ -0,0 +1,312 @@
+/* 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_BGP                  8
+#define ZEBRA_ROUTE_MAX                  9
+
+/* Zebra's family types. */
+#define ZEBRA_FAMILY_IPV4                1
+#define ZEBRA_FAMILY_IPV6                2
+#define ZEBRA_FAMILY_MAX                 3
+
+/* Error codes of zebra. */
+#define ZEBRA_ERR_RTEXIST               -1
+#define ZEBRA_ERR_RTUNREACH             -2
+#define ZEBRA_ERR_EPERM                 -3
+#define ZEBRA_ERR_RTNOEXIST             -4
+
+/* Zebra message flags */
+#define ZEBRA_FLAG_INTERNAL           0x01
+#define ZEBRA_FLAG_SELFROUTE          0x02
+#define ZEBRA_FLAG_BLACKHOLE          0x04
+#define ZEBRA_FLAG_IBGP               0x08
+#define ZEBRA_FLAG_SELECTED           0x10
+#define ZEBRA_FLAG_CHANGED            0x20
+#define ZEBRA_FLAG_STATIC             0x40
+
+/* Zebra nexthop flags. */
+#define ZEBRA_NEXTHOP_IFINDEX            1
+#define ZEBRA_NEXTHOP_IFNAME             2
+#define ZEBRA_NEXTHOP_IPV4               3
+#define ZEBRA_NEXTHOP_IPV4_IFINDEX       4
+#define ZEBRA_NEXTHOP_IPV4_IFNAME        5
+#define ZEBRA_NEXTHOP_IPV6               6
+#define ZEBRA_NEXTHOP_IPV6_IFINDEX       7
+#define ZEBRA_NEXTHOP_IPV6_IFNAME        8
+#define ZEBRA_NEXTHOP_BLACKHOLE          9 
+
+#ifndef INADDR_LOOPBACK
+#define        INADDR_LOOPBACK 0x7f000001      /* Internet address 127.0.0.1.  */
+#endif
+
+/* Address family numbers from RFC1700. */
+#define AFI_IP                    1
+#define AFI_IP6                   2
+#define AFI_MAX                   3
+
+/* Subsequent Address Family Identifier. */
+#define SAFI_UNICAST              1
+#define SAFI_MULTICAST            2
+#define SAFI_UNICAST_MULTICAST    3
+#define SAFI_MPLS_VPN             4
+#define SAFI_MAX                  5
+
+/* Filter direction.  */
+#define FILTER_IN                 0
+#define FILTER_OUT                1
+#define FILTER_MAX                2
+
+/* Default Administrative Distance of each protocol. */
+#define ZEBRA_KERNEL_DISTANCE_DEFAULT      0
+#define ZEBRA_CONNECT_DISTANCE_DEFAULT     0
+#define ZEBRA_STATIC_DISTANCE_DEFAULT      1
+#define ZEBRA_RIP_DISTANCE_DEFAULT       120
+#define ZEBRA_RIPNG_DISTANCE_DEFAULT     120
+#define ZEBRA_OSPF_DISTANCE_DEFAULT      110
+#define ZEBRA_OSPF6_DISTANCE_DEFAULT     110
+#define ZEBRA_IBGP_DISTANCE_DEFAULT      200
+#define ZEBRA_EBGP_DISTANCE_DEFAULT       20
+
+/* Flag manipulation macros. */
+#define CHECK_FLAG(V,F)      ((V) & (F))
+#define SET_FLAG(V,F)        (V) = (V) | (F)
+#define UNSET_FLAG(V,F)      (V) = (V) & ~(F)
+
+/* AFI and SAFI type. */
+typedef u_int16_t afi_t;
+typedef u_char safi_t;
+
+/* Zebra types. */
+typedef u_int16_t zebra_size_t;
+typedef u_int8_t zebra_command_t;
+
+#endif /* _ZEBRA_H */
diff --git a/missing b/missing
new file mode 100755 (executable)
index 0000000..dd58370
--- /dev/null
+++ b/missing
@@ -0,0 +1,336 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing 0.4 - GNU automake"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+                                      sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+          sed 's/\.am$/.in/' |
+          while read f; do touch "$f"; done
+    ;;
+
+  autom4te)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1Help2man' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+    test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo "#! /bin/sh"
+       echo "# Created by GNU Automake missing as a replacement of"
+       echo "#  $ $@"
+       echo "exit 0"
+       chmod +x $file
+       exit 1
+    fi
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f y.tab.h ]; then
+       echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+        you modified a dependency of a manual page.  You may need the
+        \`Help2man' package in order for those modifications to take
+        effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+       file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+    fi
+    if [ -f "$file" ]; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo ".ab help2man is required to generate this page"
+       exit 1
+    fi
+    ;;
+
+  makeinfo)
+    if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+       # We have makeinfo, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  tar)
+    shift
+    if test -n "$run"; then
+      echo 1>&2 "ERROR: \`tar' requires --run"
+      exit 1
+    fi
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar ${1+"$@"} && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar ${1+"$@"} && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+       case "$firstarg" in
+       *o*)
+           firstarg=`echo "$firstarg" | sed s/o//`
+           tar "$firstarg" ${1+"$@"} && exit 0
+           ;;
+       esac
+       case "$firstarg" in
+       *h*)
+           firstarg=`echo "$firstarg" | sed s/h//`
+           tar "$firstarg" ${1+"$@"} && exit 0
+           ;;
+       esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..f20ccf3
--- /dev/null
@@ -0,0 +1,101 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 2002/12/13 20:15:29 paul Exp $
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
+
+# process command line arguments
+while test $# -gt 0 ; do
+   case "${1}" in
+     -h | --help | --h* )                      # -h for help
+       echo "${usage}" 1>&2; exit 0 ;;
+     -m )                                      # -m PERM arg
+       shift
+       test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; }
+       dirmode="${1}"
+       shift ;;
+     -- ) shift; break ;;                      # stop option processing
+     -* ) echo "${usage}" 1>&2; exit 1 ;;      # unknown option
+     * )  break ;;                             # first non-opt arg
+   esac
+done
+
+for file
+do
+  if test -d "$file"; then
+    shift
+  else
+    break
+  fi
+done
+
+case $# in
+0) exit 0 ;;
+esac
+
+case $dirmode in
+'')
+  if mkdir -p -- . 2>/dev/null; then
+    echo "mkdir -p -- $*"
+    exec mkdir -p -- "$@"
+  fi ;;
+*)
+  if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
+    echo "mkdir -m $dirmode -p -- $*"
+    exec mkdir -m "$dirmode" -p -- "$@"
+  fi ;;
+esac
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+       echo "mkdir $pathcomp"
+
+       mkdir "$pathcomp" || lasterr=$?
+
+       if test ! -d "$pathcomp"; then
+         errstatus=$lasterr
+       else
+         if test ! -z "$dirmode"; then
+            echo "chmod $dirmode $pathcomp"
+
+            lasterr=""
+            chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+            if test ! -z "$lasterr"; then
+              errstatus=$lasterr
+            fi
+         fi
+       fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 3
+# End:
+# mkinstalldirs ends here
diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore
new file mode 100644 (file)
index 0000000..cec4061
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile
+*.o
+*.patch
+ospf6d
+ospf6d.conf
+tags
+TAGS
+.deps
diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog
new file mode 100644 (file)
index 0000000..b7871c1
--- /dev/null
@@ -0,0 +1,809 @@
+2002-11-09  Vincent Jardin  <jardin@6wind.com>
+
+       * ospf6_interface.c: update link-local address on interface creation.
+
+2002-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination.
+       * ospf6_lsa.c: change not to issue flooding caused by expire event
+       when the received LSA is (already) MaxAge.
+       * ospf6_spf.c: fix a bug which is that ospf6d calculates
+       wrong nexthop when failed to find Link-LSA for the neighbor.
+       * ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c:
+       some clean up
+       * version: 0.9.6o
+
+2002-10-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_asbr.c: bug of failing ASE lsa refresh fixed.
+       * version: 0.9.6n
+
+2002-10-01  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_asbr.c: AS-External-LSA origination function
+       is re-written.
+       * ospf6_damp.[ch]: New feature that damps flaps is added.
+       * version: 0.9.6m
+
+2002-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation()
+       is deleted.
+       * version: 0.9.6l
+
+2002-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c: bug that ospf6d fails to refresh self-originated
+       LSA if he have not the LSA before has been fixed.
+       * ospf6_asbr.c: bug of failing removing ASE LSA when remove
+       message arrived from zebra has been fixed.
+       * version: 0.9.6k
+
+2002-07-13  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_zebra.c: bug reported [zebra 14642] fixed.
+       The bug was related to the synchronization between zebra
+       and ospf6d. Now synchronization will be correctly done.
+       * version: 0.9.6j
+
+2002-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router ().
+       * ospf6_dbex.c: because of retrans list structure changed
+       due to LSDB change, removal of old instance from retrans-list
+       is not necessary anymore. this caused crash but now fixed.
+       * version: 0.9.6i
+
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2002-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsdb.c: entirely rewritten. now ospf6d uses
+       radix tree by using lib/table.[ch] for LSDB lookup.
+       * ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed
+       due to rewriting of lsdb module.
+       * ospf6_neighbor.c: lack of check existence and find correct
+       instance of the LSA which is going to be removed from neighbor's
+       retransmission was filled.
+       * version: 0.9.6h
+
+2002-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_intra.c: bug fix for Intra-route deletion.
+       * ospf6_route.c: bug fix for path comparison.
+       * version: 0.9.6g
+
+2002-06-28  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.c: some logs trying to find the situation
+       when assert occur are added. route duration statistics
+       added.
+       * ospf6_zebra.c: trying to fix the problem reported by
+       [zebra 14318] but not yet sure.
+       * version: 0.9.6f
+
+2002-06-25  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_intra.c: new file for management of intra-prefix LSA.
+       * ospf6_abr.c: inter area route calculation code added.
+       * version: 0.9.6e
+
+2002-06-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_asbr.c: All AS-External route was removed when
+       one of the ASBR path was gone, but the route from other ASBR
+       path should stay remained. this bug is fixed.
+       * version: 0.9.6d
+
+2002-06-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.c: route table calculation bug fixed. [zebra 14105]
+       * ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up.
+       * version: 0.9.6c
+
+2002-04-27  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.c: [zebra 13514] bug fix.
+       thanks to Harald Koch.
+       * version: 0.9.6b
+
+2002-04-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dump.c: fix bug of log function
+       * ospf6_area.c: fix bug of intra route deletion
+       * version: 0.9.6a
+
+2002-04-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * merged with "current" version.
+       * version: 0.9.6
+
+2001-03-11  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsdb.c ospf6_spf.c: log message changed for debug.
+
+2001-02-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * version: 0.9.5i
+
+       * ospf6_asbr.c: Added code that finds alternative
+       AS-External route when remove AS-External route.
+       This is temporary fix ...
+
+       * ospf6_redistribute.c: remove redistributed routes
+       immediately when 'no redistribute ...'
+
+2001-02-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * version: 0.9.5h
+
+       * ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on
+       point-to-point links.
+
+       * ospf6_message.c: Bug of log messages of self-originated
+       Hello packet fixed.
+
+2001-02-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * version: 0.9.5g
+       * ospf6_asbr.c: fix for the bug that AS-External route
+       is not get removed.
+
+2001-02-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit
+       has been temporarily fixed
+
+2001-12-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_asbr.[ch]: The byte order bug in encoding/decoding
+       the bits/metric field in AS-External-LSA fixed.
+       Fixed to update E-bit in Router-LSA of itself.
+       Reported by Taisuke Sasaki ([zebra 11548]).
+
+       * README: updated.
+
+       * version: 0.9.5f
+
+2001-11-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_prefix.c: Intra-prefix-LSA bug fixed.
+       * ospf6_abr.[ch]: added (only just placeholder yet)
+
+2001-11-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.c: fix to overwrite a prefix when another
+       addition to the prefix is given. freeze function changed
+       not to remove routes by default.
+
+       * version: 0.9.5e
+
+2001-11-19  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * version: 0.9.5d
+
+       * ospf6_lsa.c ospf6_spf.c: SPF Calculations are now
+       scheduled by hook.
+
+       * ospf6_route.c: ospf6_route_add bug fix,
+       ospf6_route_remove_all corrected.
+
+2001-11-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_hook.[ch]: added.
+       * Almost half of the code has been rewritten.
+       especially, ospf6_route.[ch]. Hook call has been injected
+       much.
+       * ospf6_asbr.[ch]: added.
+
+2001-10-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c: ospf6d was wrong to omit reoriginating
+       of LSA when the self-originated LSA was received from others.
+       fixed.
+       * ospf6d.h: version: 0.9.5c
+
+2001-10-16  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsa.c: 'force-prefix' was not executed. fixed.
+       * ospf6d.h: version: 0.9.5b
+
+2001-10-13  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_interface.c: 'passive-interface' is now moved to
+       'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which
+       specifies the filter prefix for connected address prefix also
+       moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'.
+       The old obsoleted commands are still acceptable though. New command
+       'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d
+       to advertise rather prefix than stub local-address even on loopback
+       or pointopoint interfaces.
+
+       * ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'.
+       same for other message type. The older is still acceptable.
+
+       * ospf6_lsa.c: Changed AS-External generation to new one which uses
+       LSA hooks. Delete old garbage.
+
+2001-10-02  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6d.c: turn off and turn on sequence with
+       'no interface' 'interface' cmds was not work. fixed.
+
+       * ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub
+       did not care duplicate prefixes. fixed.
+
+2001-09-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_message.c: There was a bug that prevent LSDB
+       to syncronize. It was a DbDesc packet bug that Slave
+       sends two different DbDesc packet on the same sequence
+       number. This cause many LSAs are dropped when Exchanging
+       LSDB, because the latter DbDesc packet that have the same
+       sequence number will be ignored as duplicate packet.
+       This seems to be exist at least before 0.9.4 version.
+       Now this is the most stable candidate.
+
+       * ospf6d.h: version 0.9.5a
+
+2001-09-06  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_zebra.c ospf6_spf.c ospf6_lsa.c :
+       delete nexthop check to certify the nexthop is Link-local address.
+       Suppress Link-LSA origination on links other than Broadcast.
+       SPF's nexthop calculation first checks linklocal address
+       in Link-LSA, then checks source address of neighbor's packets.
+
+       * ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c:
+       intra-area-prefix-lsa origination func moved to new one.
+
+       * ospf6_interface.h ospf6d.[ch] ospf6_lsa.c: 
+       interface_area_cmd now changed to have 'passive'
+       and 'prefix-list' option.
+
+       * ospf6_prefix.c:
+       clean up.
+
+2001-09-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]:
+       clean up and new LSA origination functions added.
+
+       * ospf6_route.c ospf6_lsdb.c: make vty function more
+       clean/understandable.
+
+       * ospf6d.h: version 0.9.5
+
+2001-08-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of
+       ospf6_lsa_is_maxage.
+
+       * ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge.
+
+2001-08-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsdb.c: if There's no previous prefix
+       ospf6d was wrongly not calculate the prefix.
+       this reported by (v6 16029) is fixed.
+
+       * ospf6_neighbor.c: Instance of LSA Summary included
+       in DbDesc packet was wrongly freed. The bug cause
+       malformed DbDesc, ExChange <-> ExStart flapping,
+       and then crash.
+
+       * ospf6d.h: version 0.9.4
+
+2001-08-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.[ch]: Showing format is changed.
+       'show ipv6 route ospf6' -> 'show ipv6 ospf6 route'
+       'show ipv6 route ospf6 external' ->
+       'show ipv6 ospf6 route redistribute'
+
+       * ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c:
+       memory leak in LS list fixed.
+
+       * all: clean up
+
+       * ospf6d.h: version 0.9.3
+
+2001-08-20  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf6d.c (ospf6_timeval_sub_equal): Remove function.
+
+       * ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp().
+       (ospf6_timeval_add_equal): Function moved from ospf6d.c
+       
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-08-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsdb.c ospf6_neighbor.c:
+       LSDB function/structure and LS list function has been rewritten.
+       memory leak has been decreased.
+
+       * ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted.
+
+       * ospf6d.h: version 0.9.2
+
+2001-08-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c ospf6_lsdb.c:
+       Retransmition list had a critical bug that breaks LSDB
+       synchronization. When new LSA be added to retrans-list,
+       old must be removed, but it was not. So new LSA dropped,
+       and LSA Acknowledgement did not work. The bug was fixed.
+
+       * ospf6d.h: version 0.9.1
+
+2001-06-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_spf.c: crash bug fix in temporary treat code for
+       Router-LSA whose LS-ID != 0
+
+       * ospf6_dbex.c: RFC2328 13.(4) was wrongly coded.
+           (4) Else if the LSA's LS age is equal to MaxAge, and there is
+            currently *NO* instance of the LSA in the router's link state
+           ...
+
+       * ospf6_lsa.c: RFC2328 13.1 checksum tie breaker
+       had been neglected, and has just added now.
+
+       * ospf6d.h: version 0.9.0
+       ospf6d expected to work with hitachi gr2000 from these fixes.
+
+2001-06-12  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA.
+       DR was mis-include others prefixes advertised by their Link-LSA.
+
+       * ospf6_route.c: Fix bug in calculating intra area routes.
+       Not all prefixes in Intra-Area-Prefix-LSA was calculated.
+
+       * ospf6_spf.c:
+       Changed to quit when a error occured in calculating SPF tree.
+       Very messy hack for the bug reported by [zebra 8807]. This
+       is not tested yet.
+       Changed to quit SPF calculation when a nexthop calculation
+       errors.
+
+       * ospf6_zebra.c:
+       Support for interface address deletion.
+
+       * ospf6d.h:
+       version: 0.8.y
+
+2001-04-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6d.h
+       Due to previous change (DR Election algorithm changed),
+       backward compatibility will be lost from this version.
+       version: 0.8.x
+
+2001-04-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_message.c ospf6_ism.c:
+       Bug of router_id comparison
+
+2001-04-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had
+       some bug causing Loading state lasts long.
+       version: 0.8.v
+
+2001-04-08  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.c: BUG in AS-External route calculation fixed.
+       It was using OLD LSDB...
+       Version: 0.8.u-
+
+2001-04-08  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c,
+       ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c,
+       ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c,
+       ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c:
+       Delete old LSDB function.
+
+       * ospf6d.h:
+       Version: 0.8.u
+
+2001-04-05  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+       ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h,
+       ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c,
+       ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h:
+       Changed to use New LSDB.
+       Version: 0.8.t
+
+2001-04-02  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsa.c:
+       Interface stub check in Intra-Area-Prefix-LSA origination 
+       was wrong. - fixed.
+
+       * ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+       ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c,
+       ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c,
+       ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c:
+       New LSDB functions, but not changed to be used.
+
+       * ospf6d.h:
+       Version: 0.8.s
+
+2001-03-28  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c
+       ospf6_interface.c ospf6_interface.h ospf6_lsa.c
+       ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c
+       ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning.
+
+2001-03-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6d.h:
+       version: 0.8.r
+
+       * ospf6_neighbor.[ch], ospf6_lsa.[ch]:
+       just clean up and log clearify.
+
+       * ospf6_message.[ch]:
+       Packet receiving function and dumping OSPFv3 packet has been
+       changed simple and clean.
+
+       * ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch],
+         ospf6_neighbor.[ch], ospf6_nsm.[ch]:
+       LSList(i.e. summary list, request list, retrans list, etc) have
+       been rewritten based on new LSDB module. The main LSDB have not
+       yet shifted to this new module, but will shift eventually.
+       This change expected to resolve the problem that the ospf6d keeps
+       on sending redundant LSUpdate/LSAck.
+
+       * ospf6_interface.c: changed default MTU from 1500 to 1280.
+       It was possible that the ospf6d could not send packet (e.g.
+       LSUpdate in response to LSReq in my case) when the packet
+       size accidentally reached near 1500 (I was forget about IP
+       header :p). It is a bit illegal to set MTU 1280 constantly,
+       but I failed once with I/F MTU from kernel (through zebra),
+       and thinks that 1280 is more stable than kernel variable.
+       Comments will be appriciated.
+
+2001-03-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch],
+         ospf6_neighbor.c, ospf6_spf.c, ospf6d.c:
+       Fix for crash. ospf6d has ever been crashing when
+       'no interface' command executed, and when starting up with
+       the configuration which does not include 'router ospf6'.
+       these has been fixed.
+
+2001-02-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsa.c, ospf6_message.c:
+       LSA summary (exchanged while Adjacency bring up) may expire
+       (may reach MaxAge). Handling this has been added but
+       it's a little bit quick hack.
+
+       * ospf6_message.c:
+       Thread chain bug fixed. Read network thread chain has been cut
+       when receive packets on not-enabled interface. this was wrong
+       and fixed.
+
+2001-02-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_message.c:
+       I/F MTU check part on sending packet had some bug, and it's fixed.
+       Ospf6d has believed a value from zebra as I/F MTU, but from now
+       I/F MTU is set to constant 1500. This is workaround for ATM.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * just code clean up of almost all module.
+       * ospf6_dump.c, ospf6_lsa.c: file dependency.
+       * ospf6_mesg.[ch]: changed filename to ospf6_message.[ch]
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed.
+       version 0.8.k CRASHed for this.
+       * ospf6_lsa.c: bug of logging fixed.
+       version: 0.8.l
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_neighbor.c: fix typo when trying to delete
+       MaxAge AS-External LSA. MaxAge LSA remaining bug is expected
+       to be fixed.
+       version: 0.8.k
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_mesg.c: add I/F Mtu check for sending LS Update.
+
+       * ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h,
+       ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor
+       structure, from sockaddr_in6 to in6_addr. No protocol/processing
+       changed.
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of
+       Database Exchange.
+       version: 0.8.j
+
+       Because the LS Request list was checked only when attempt
+       to send (retransmit) LS Request packet, Loading state lasted
+       long (for RxmtInterval) unexpectedly. This was fixed; LS Request
+       packet will be send as soon as one received a LS Update packet.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to
+       /tmp/.ospf6d".
+
+2000-12-29  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dump.[ch]: simplified.
+
+2000-12-19  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_route.c: Fix bug of using unavailable route.
+       version: 0.8.d
+
+2000-11-30  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_spf.c: calculate statistics. version: 0.8.d
+
+2000-11-26  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed.
+       version: 0.8.c
+
+2000-11-26  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_dbex.c: Start debugging and cleaning.
+
+       * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c,
+       ospf6_proto.c, ospf6_top.c: add some function to clarify codes.
+
+2000-11-26  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_spf.c: Delete old garbage (which was enclosed by #if 0)
+
+       * ospf6_redistribute.c: "redistribute ospf6" was generated in
+       "router ospf6" in config file. It is a bug, and fixed.
+       wrong warning message was deleted.
+
+       * ospf6_main.c: If daemon mode, ospf6d was silent even if
+       the config file was wrong. It is a bug, and fixed.
+
+       * ospf6_route.c, ospf6_zebra.c: Zebra syncronization method
+       has been changed. delete garbages. allow nexthop of :: in case
+       of connected route.
+
+       * ospf6_dbex.c: Delete annoying log messages.
+
+       * ospf6_lsa.c: Changed string for LSA log.
+
+2000-11-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_spf.c: some careless bug fixed.
+
+       * ospf6_route.c: changed not to send garbage route
+          whose nexthop is not linklocal address.
+
+2000-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+        * ospf6_rtable.c: renamed to ospf6_route.c
+        whole functionality has been rewritten as new code.
+        new functions not yet installs routes; the old
+        functions still remains. cleaning log messages.
+
+       * ospf6_spf.c: whole functionality has been rewritten
+       as new code. new command "show ipv6 ospf6 spf node",
+       "show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table"
+       has been added. Memory leak was fixed. cleaning log messages.
+
+       * ospf6d version: 0.7.c
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile
+       warnings.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from
+       unsigned long to unsigned int.
+
+2000-04-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6d.h: Include some headers for avoid warning.
+
+       * ospf6_routemap.h: Add newfile.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP
+       rather than RFC2133.
+
+1999-10-21  Jun-ichiro itojun Hagino <itojun@itojun.org>
+
+       * ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion
+       from IPv4 Mapped Address to IPv4 address.
+
+1999-08-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by
+       #ifdef/#endif.
+
+1999-07-29  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ospf6_mesg.c: add new message process function.
+
+1999-07-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_main.c (sighup): Call of log_rotate() removed.
+
+1999-07-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       ospf6_dbex.{c,h}: variable "acknowledge" has been deleted.
+
+1999-07-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * *.{c,h}: lsa data structure has been drastically
+       changed.
+
+1999-07-16  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * *.{c,h}: bug of updating LSA's which is self
+       originated has been fixed.
+
+1999-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * *.{c,h} : log clean up.
+
+1999-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6d.c (ospf6_init): Change to use install_default.
+
+1999-07-03  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * ospf6_rtable.c (nexthop_*): added some function that handles
+       new nexthop structure.
+
+1999-07-01  Rick Payne <rickp@rossfell.co.uk>
+
+       * ospf6_zebra.c (ospf6_zebra_init): Install standard commands to
+       ZEBRA_NODE.
+
+1999-06-09  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * ospf6_rtable.h: added for new routing table of ospf6d
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+       * ospf6_main.c (signal_init): SIGTERM call sigint.
+       (sigint): Loggging more better message.
+
+1999-05-13  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       *ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex.
+
+1999-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID
+       is defined.
+       * ospf6_mesg.c (make_hello): Likewise.
+       * ospf6_lsa.c (lsa_flood): Likewise.
+
+1999-05-07  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * ospf6_spf.c, etc: Many bug fix.
+        intra-area-prefix-LSA treatment changed.
+        network byte order of neighbor ifid changed.
+
+1999-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_zebra.h (struct zebra): Add hitory entry to structure.
+
+1999-05-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_main.c (main): Add KAME check for binding vty socket.
+       (main): Delete old interface get routine garbage.
+
+       * ospf6d.c: Change all `show ip6' statement to `show ipv6'.
+       (show_ipv6_ospf6_requestlist): Add description.
+
+1999-05-04  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * ospf6_lsa.c, etc: Many bug fix, now two routers
+       on the same segment can become FULL neighbor state
+       each other.
+
+1999-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: Add file dependency.
+       (depend): Add target.
+
+1999-05-02  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * Clean up and fix have been almost done. This code
+       now testing stage of Intra area routing.
+
+       * Configuration Vty become more similar to Cisco.
+
+1999-04-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Trim training newline from zlog format arguemnt.
+       
+       * ospf6_dump.c (ospf6_err): Commented out ospf6_err and
+       ospf6_warn.  Same kind of function should be implemented as
+       zlog_err or zlog_warn or someting.
+
+       * ospf6d.c: Change OSPF_NODE to OSPF6_NODE.
+       Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG.
+       
+
+1999-04-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_mesg.c (make_hello): Add check of SIN6_LEN
+
+1999-04-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf6_neighbor.c: Change list_clear_all to list_delete_all_node.
+       Remove list_delete_all fuction and use lib/linklist.c's one.
+       
+1999-04-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * mcast_join(),mcast_leave()'s argument socket length is removed.
+
+1999-04-08    <kunihiro@zebra.org>
+
+       * ospf6_zebra.h (ospf_zebra_read): Fix typo.
+
+       * ospf6_interface.h: Tempolary add struct rt_addrinfo.
+
+1999-03-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Merge from ospfd-zebra-990303 codes.
+
+1999-02-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.in: add new file.
+
+       * Makefile.am: @INCLUDES@ is added for OS/library specific IPv6
+       directory search.
+
+       * Import files from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s ospfd.
+       Impterted files are:
+       Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c,
+       ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c,
+       ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c,
+       ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h,
+       ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h
diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am
new file mode 100644 (file)
index 0000000..e1b78cb
--- /dev/null
@@ -0,0 +1,48 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf6.a
+sbin_PROGRAMS = ospf6d
+
+libospf6_a_SOURCES = \
+       ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \
+       ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \
+       ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \
+       ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \
+       ospf6_routemap.c ospf6_proto.c \
+       ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \
+       ospf6_abr.c ospf6_intra.c ospf6_damp.c
+
+noinst_HEADERS = \
+       ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \
+       ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \
+       ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \
+       ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \
+       ospf6_top.h ospf6_nsm.h ospf6_routemap.h \
+        ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \
+       ospf6_abr.h ospf6_intra.h ospf6_damp.h
+
+ospf6d_SOURCES = \
+       ospf6_main.c $(libospf6_a_SOURCES)
+
+ospf6d_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospf6d.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
diff --git a/ospf6d/Makefile.in b/ospf6d/Makefile.in
new file mode 100644 (file)
index 0000000..fed57d9
--- /dev/null
@@ -0,0 +1,549 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf6.a
+sbin_PROGRAMS = ospf6d
+
+libospf6_a_SOURCES = \
+       ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \
+       ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \
+       ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \
+       ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \
+       ospf6_routemap.c ospf6_proto.c \
+       ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \
+       ospf6_abr.c ospf6_intra.c ospf6_damp.c
+
+
+noinst_HEADERS = \
+       ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \
+       ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \
+       ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \
+       ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \
+       ospf6_top.h ospf6_nsm.h ospf6_routemap.h \
+        ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \
+       ospf6_abr.h ospf6_intra.h ospf6_damp.h
+
+
+ospf6d_SOURCES = \
+       ospf6_main.c $(libospf6_a_SOURCES)
+
+
+ospf6d_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospf6d.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+subdir = ospf6d
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libospf6_a_AR = $(AR) cru
+libospf6_a_LIBADD =
+am_libospf6_a_OBJECTS = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \
+       ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \
+       ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \
+       ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \
+       ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
+       ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
+       ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
+       ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+       ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+       ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
+       ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS)
+sbin_PROGRAMS = ospf6d$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \
+       ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \
+       ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \
+       ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \
+       ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
+       ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
+       ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
+       ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+       ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+       ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
+       ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1)
+ospf6d_OBJECTS = $(am_ospf6d_OBJECTS)
+ospf6d_DEPENDENCIES = ../lib/libzebra.a
+ospf6d_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf6_abr.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_area.Po ./$(DEPDIR)/ospf6_asbr.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_bintree.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_damp.Po ./$(DEPDIR)/ospf6_dbex.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_dump.Po ./$(DEPDIR)/ospf6_hook.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_interface.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_intra.Po ./$(DEPDIR)/ospf6_ism.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_linklist.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_lsa.Po ./$(DEPDIR)/ospf6_lsdb.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_main.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_message.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_neighbor.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_network.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_nsm.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_prefix.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_proto.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_route.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_routemap.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_spf.Po ./$(DEPDIR)/ospf6_top.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf6_zebra.Po ./$(DEPDIR)/ospf6d.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = README $(noinst_HEADERS) ChangeLog Makefile.am \
+       Makefile.in
+SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  ospf6d/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES) 
+       -rm -f libospf6.a
+       $(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD)
+       $(RANLIB) libospf6.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sbindir)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+         rm -f $(DESTDIR)$(sbindir)/$$f; \
+       done
+
+clean-sbinPROGRAMS:
+       -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES) 
+       @rm -f ospf6d$(EXEEXT)
+       $(LINK) $(ospf6d_LDFLAGS) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_abr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_bintree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_damp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dbex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_hook.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_intra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_ism.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_linklist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_message.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_neighbor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_nsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_prefix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_top.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6d.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+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 =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-noinstLIBRARIES clean-sbinPROGRAMS ctags 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 pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ospf6d/README b/ospf6d/README
new file mode 100644 (file)
index 0000000..b3b4d16
--- /dev/null
@@ -0,0 +1,85 @@
+
+                 Zebra OSPF daemon for IPv6 network
+
+                            2001/12/20
+
+Zebra OSPF6d is OSPF version 3 daemon which is specified by
+"OSPF for IPv6" (RFC 2740).
+
+*** NOTE ***
+  Zebra ospf6d is in development yet. It may lack some functionalities,
+  and may have some bugs. Use the latest version from the anoncvs
+  repository (http://www.zebra.org/cvs.html) !
+
+This file README is like memo yet, so please feel free to ask
+<yasu@sfc.wide.ad.jp> by E-mail. Patches will be appriciated.
+
+ospf6d's vty port was default to 2606/tcp.
+Use commands below.
+
+VIEW NODE:
+  show ipv6 ospf6
+    To see Router-ID, uptime of ospf6d, some statistics.
+
+  show ipv6 ospf6 database ...
+    This command shows LSA database. You can specify
+    LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized.
+
+  show ipv6 ospf6 interface ...
+    To see the status of the OSPF interface, and the configuration
+    like interface costs.
+
+  show ipv6 ospf6 neighbor ...
+    Shows state of neighbors and choosed (Backup) DR on the I/F.
+
+  show ipv6 ospf6 route (X::X)
+    This command shows internal routing table of the ospf6d.
+    Routes not calculated by OSPFv3 (like connected routes)
+    are not shown. If Address is specified (X::X), shows the route
+    that the address matches.
+
+  show ipv6 ospf6 route redistribute (X::X)
+    Shows the routes advertised as AS-External routes by the router
+    itself. If Address is specified (X::X), shows the route
+    that the address matches.
+
+CONFIG NODE:
+  interface NAME
+    To enter INTERFACE NODE
+
+  router ospf6 ...
+    To enter OSPF6 NODE
+
+INTERFACE NODE:
+  ipv6 ospf6 cost COST
+    Sets the interface's output cost. default 1
+
+  ipv6 ospf6 hello-interval HELLOINTERVAL
+    Sets the interface's Hello Interval. default 10
+
+  ipv6 ospf6 dead-interval DEADINTERVAL
+    Sets the interface's Router Dead Interval. default 40
+
+  ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL
+    Sets the interface's Rxmt Interval. default 5
+
+  ipv6 ospf6 priority PRIORITY
+    Sets the interface's Router Priority. default 1
+
+  ipv6 ospf6 transmit-delay TRANSMITDELAY
+    Sets the interface's Inf-Trans-Delay. default 1
+
+OSPF6 NODE:
+  router-id A.B.C.D
+    Sets the router's Router-ID
+
+  interface NAME area AREA
+    Binds interface to specified Area, and start
+    sending OSPFv3 packets.
+
+Sample configuration is in ospf6d.conf.sample.
+
+--
+Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+Kunihiro Ishiguro <kunihiro@zebra.org>
+
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
new file mode 100644 (file)
index 0000000..864e0c2
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_dump.h"
+#include "ospf6_abr.h"
+
+static int abr_index;
+#define IS_OSPF6_DUMP_ABR (ospf6_dump_is_on (abr_index))
+
+#define ADD    0
+#define CHANGE 1
+#define REMOVE 2
+
+/* Inter-Area-Prefix-LSA Calculation */
+
+static struct ospf6_route_req *
+ospf6_abr_entry_lookup (struct ospf6_route_req *abr_entry,
+                        u_int32_t router_id, struct ospf6_area *area)
+{
+  struct prefix_ls abr_id;
+  char router_string[32];
+
+  inet_ntop (AF_INET, &router_id, router_string, sizeof (router_string));
+
+  //zlog_info ("ABR:   Finding router %s in area %s", router_string, area->str);
+
+  memset (&abr_id, 0, sizeof (abr_id));
+  abr_id.family = AF_UNSPEC;
+  abr_id.prefixlen = 64; /* xxx */
+  abr_id.id.s_addr = htonl (0);
+  abr_id.adv_router.s_addr = router_id;
+
+  ospf6_route_lookup (abr_entry, (struct prefix *) &abr_id,
+                      area->table_topology);
+
+  if (ospf6_route_end (abr_entry))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR:   Router %s not found in area %s",
+                   router_string, area->str);
+      return NULL;
+    }
+
+  if (abr_entry->path.area_id != area->area_id)
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: ABR area id mismatch");
+      return NULL;
+    }
+
+  if (! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: ABR entry's B bit off");
+      return NULL;
+    }
+
+  return abr_entry;
+}
+
+static int
+ospf6_abr_prefix_lsa_to_route (struct ospf6_lsa *lsa,
+                               struct ospf6_route_req *request)
+{
+  struct ospf6_inter_area_prefix_lsa *iep;
+  struct ospf6_route_req abr_entry;
+
+  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_PREFIX))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: LSA type mismatch");
+      return -1;
+    }
+
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: LSA MaxAge");
+      return -1;
+    }
+
+  if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router,
+                                (struct ospf6_area *) lsa->scope))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: ABR check failed");
+      return -1;
+    }
+
+  iep = OSPF6_LSA_HEADER_END (lsa->header);
+
+  memset (request, 0, sizeof (struct ospf6_route_req));
+  request->route.type = OSPF6_DEST_TYPE_NETWORK;
+  request->route.prefix.family = AF_INET6;
+  request->route.prefix.prefixlen = iep->prefix.prefix_length;
+  ospf6_prefix_in6_addr (&iep->prefix, &request->route.prefix.u.prefix6);
+
+  request->path.cost = abr_entry.path.cost +
+                      (ntohl (iep->metric) & ntohl (0x000fffff));
+  request->path.type = OSPF6_PATH_TYPE_INTER;
+  request->path.origin.type = lsa->header->type;
+  request->path.origin.id = lsa->header->id;
+  request->path.origin.adv_router = lsa->header->adv_router;
+  memcpy (&request->nexthop.address, &abr_entry.nexthop.address,
+          sizeof (request->nexthop.address));
+  request->nexthop.ifindex = abr_entry.nexthop.ifindex;
+
+  return 0;
+}
+
+void
+ospf6_abr_prefix_lsa_add (struct ospf6_lsa *lsa)
+{
+  struct ospf6_route_req request;
+  int ret;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Calculate %s", lsa->str);
+
+  ret = ospf6_abr_prefix_lsa_to_route (lsa, &request);
+  if (ret < 0)
+    return;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Inter Area Route add for %s", lsa->str);
+
+  ospf6_route_add (&request, ospf6->route_table);
+}
+
+void
+ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *lsa)
+{
+  struct ospf6_inter_area_prefix_lsa *iep;
+  struct prefix_ipv6 prefix6;
+  struct ospf6_route_req request;
+
+  iep = OSPF6_LSA_HEADER_END (lsa->header);
+
+  prefix6.family = AF_INET6;
+  prefix6.prefixlen = iep->prefix.prefix_length;
+  ospf6_prefix_in6_addr (&iep->prefix, &prefix6.prefix);
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Inter Area Route remove for %s", lsa->str);
+
+  for (ospf6_route_lookup (&request, (struct prefix *) &prefix6,
+                           ospf6->route_table);
+       ! ospf6_route_end (&request);
+       ospf6_route_next (&request))
+   {
+     if (memcmp (&prefix6, &request.route.prefix, sizeof (prefix6)))
+       break;
+     if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_PREFIX) ||
+         request.path.origin.adv_router != lsa->header->adv_router ||
+         request.path.origin.id != lsa->header->id)
+       continue;
+
+     ospf6_route_remove (&request, ospf6->route_table);
+   }
+}
+
+static int
+ospf6_abr_router_lsa_to_route (struct ospf6_lsa *lsa,
+                               struct ospf6_route_req *request)
+{
+  struct ospf6_inter_area_router_lsa *ier;
+  struct ospf6_route_req abr_entry;
+
+  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_ROUTER))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: LSA type mismatch");
+      return -1;
+    }
+
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: LSA MaxAge");
+      return -1;
+    }
+
+  if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router,
+                                (struct ospf6_area *) lsa->scope))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: Advertising router check failed");
+      return -1;
+    }
+
+  ier = OSPF6_LSA_HEADER_END (lsa->header);
+
+  memset (request, 0, sizeof (struct ospf6_route_req));
+  request->route.type = OSPF6_DEST_TYPE_ROUTER;
+  request->route.prefix.family = AF_UNSPEC;
+  request->route.prefix.prefixlen = 64; /* XXX */
+  ((struct prefix_ls *) &request->route.prefix)->adv_router.s_addr
+    = ier->router_id;
+
+  request->path.cost = abr_entry.path.cost +
+                      (ntohl (ier->metric & htonl (0x000fffff)));
+  request->path.type = OSPF6_PATH_TYPE_INTER;
+  request->path.origin.type = lsa->header->type;
+  request->path.origin.id = lsa->header->id;
+  request->path.origin.adv_router = lsa->header->adv_router;
+  SET_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E);
+  request->path.capability[0] = ier->options[0];
+  request->path.capability[1] = ier->options[1];
+  request->path.capability[2] = ier->options[2];
+
+  memcpy (&request->nexthop.address, &abr_entry.nexthop.address,
+          sizeof (request->nexthop.address));
+  request->nexthop.ifindex = abr_entry.nexthop.ifindex;
+
+  return 0;
+}
+
+void
+ospf6_abr_router_lsa_add (struct ospf6_lsa *lsa)
+{
+  struct ospf6_route_req request;
+  int ret;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Calculate %s", lsa->str);
+
+  ret = ospf6_abr_router_lsa_to_route (lsa, &request);
+  if (ret < 0)
+    return;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Inter Area Router add for %s", lsa->str);
+
+  ospf6_route_add (&request, ospf6->topology_table);
+}
+
+void
+ospf6_abr_router_lsa_remove (struct ospf6_lsa *lsa)
+{
+  struct ospf6_inter_area_router_lsa *ier;
+  struct prefix_ls prefix_ls;
+  struct ospf6_route_req request;
+
+  ier = OSPF6_LSA_HEADER_END (lsa->header);
+
+  memset (&prefix_ls, 0, sizeof (prefix_ls));
+  prefix_ls.family = AF_INET6;
+  prefix_ls.prefixlen = 64; /* XXX */
+  prefix_ls.adv_router.s_addr = ier->router_id;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Inter Area Route remove for %s", lsa->str);
+
+  for (ospf6_route_lookup (&request, (struct prefix *) &prefix_ls,
+                           ospf6->route_table);
+       ! ospf6_route_end (&request);
+       ospf6_route_next (&request))
+   {
+     if (memcmp (&prefix_ls, &request.route.prefix, sizeof (prefix_ls)))
+       break;
+     if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_ROUTER) ||
+         request.path.origin.adv_router != lsa->header->adv_router ||
+         request.path.origin.id != lsa->header->id)
+       continue;
+
+     ospf6_route_remove (&request, ospf6->route_table);
+   }
+}
+
+
+void
+ospf6_abr_abr_entry_add (struct ospf6_route_req *abr_entry)
+{
+  struct ospf6_lsdb_node node;
+  struct prefix_ls *abr_id;
+  struct ospf6_route_req request;
+  struct ospf6_area *area;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: New Area Border Router found");
+
+  area = ospf6_area_lookup (abr_entry->path.area_id, ospf6);
+  if (! area)
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: Can't find associated area");
+      return;
+    }
+
+  abr_id = (struct prefix_ls *) &abr_entry->route.prefix;
+  if (! ospf6_abr_entry_lookup (&request, abr_id->adv_router.s_addr, area))
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: back check failed");
+      return;
+    }
+
+  /* for each inter-prefix LSA this ABR originated */
+  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+                               abr_id->adv_router.s_addr, area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_abr_prefix_lsa_add (node.lsa);
+
+  /* for each inter-router LSA this ABR originated */
+  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER),
+                               abr_id->adv_router.s_addr, area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_abr_router_lsa_add (node.lsa);
+}
+
+void
+ospf6_abr_abr_entry_remove (struct ospf6_route_req *abr_entry)
+{
+  struct ospf6_lsdb_node node;
+  struct prefix_ls *abr_id;
+  struct ospf6_area *area;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("ABR: Area Border Router removed");
+
+  abr_id = (struct prefix_ls *) &abr_entry->route.prefix;
+
+  area = ospf6_area_lookup (abr_entry->path.area_id, ospf6);
+  if (! area)
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: Can't find associated area");
+      return;
+    }
+
+  /* for each inter-prefix LSA this ABR originated */
+  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+                               abr_id->adv_router.s_addr, area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_abr_prefix_lsa_remove (node.lsa);
+
+  /* for each inter-router LSA this ABR originated */
+  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER),
+                               abr_id->adv_router.s_addr, area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_abr_router_lsa_remove (node.lsa);
+}
+
+/* Inter-Area-Prefix-LSA Origination */
+
+static void
+ospf6_abr_prefix_lsa_update_add (struct ospf6_route_req *request,
+                                 struct ospf6_area *area)
+{
+  char buffer [MAXLSASIZE];
+  u_int16_t size;
+  struct ospf6_inter_area_prefix_lsa *iep;
+  char *p;
+
+  if (IS_OSPF6_DUMP_ABR)
+    zlog_info ("Update Inter-Prefix for %s: ID: %lu",
+               area->str, (u_long) ntohl (request->route_id));
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  size = sizeof (struct ospf6_inter_area_prefix_lsa);
+  iep = (struct ospf6_inter_area_prefix_lsa *) buffer;
+  p = (char *) (iep + 1);
+
+  /* prefixlen */
+  iep->prefix.prefix_length = request->route.prefix.prefixlen;
+
+  /* PrefixOptions */
+  iep->prefix.prefix_options = request->path.prefix_options;
+
+  /* set Prefix */
+  memcpy (p, &request->route.prefix.u.prefix6,
+          OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen));
+  ospf6_prefix_apply_mask (&iep->prefix);
+  size += OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen);
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+                       htonl (request->route_id), ospf6->router_id,
+                       (char *) iep, size, area);
+}
+
+static void
+ospf6_abr_prefix_lsa_update_remove (struct ospf6_route_req *request,
+                                    struct ospf6_area *area)
+{
+  struct ospf6_lsa *lsa;
+  lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+                                htonl (request->route_id),
+                                ospf6->router_id, area->lsdb);
+  if (lsa)
+    ospf6_lsa_premature_aging (lsa);
+}
+
+static void
+ospf6_abr_prefix_lsa_update (int type, struct ospf6_route_req *request)
+{
+  struct ospf6_route_req route, target;
+  listnode node;
+  struct ospf6_area *area;
+  struct ospf6_interface *o6i;
+
+  if (request->route.type != OSPF6_DEST_TYPE_NETWORK)
+    return;
+
+  /* assert this is best path; if not, return */
+  ospf6_route_lookup (&route, &request->route.prefix, request->table);
+  if (memcmp (&route.path, &request->path, sizeof (route.path)))
+    return;
+
+  if (target.path.cost >= LS_INFINITY ||
+      target.path.cost_e2 >= LS_INFINITY)
+    {
+      if (IS_OSPF6_DUMP_ABR)
+        zlog_info ("ABR: Exceeds LS Infinity, ignore");
+      return;
+    }
+
+  ospf6_route_lookup (&target, &request->route.prefix, request->table);
+  if (type == REMOVE)
+    {
+      ospf6_route_next (&route);
+      if (! memcmp (&route.route, &request->route, sizeof (route.route)))
+        {
+          type = ADD;
+          ospf6_route_next (&target);
+        }
+    }
+
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (target.path.area_id == area->area_id)
+        continue;
+
+      o6i = ospf6_interface_lookup_by_index (target.nexthop.ifindex);
+      if (o6i && o6i->area && o6i->area->area_id == area->area_id)
+        {
+          zlog_info ("ABR: Logical equivalent of split horizon, skip for %s",
+                     area->str);
+          continue;
+        }
+
+      if (area->area_id == ntohs (0) && /* Backbone */
+          target.path.type != OSPF6_PATH_TYPE_INTRA)
+        continue;
+
+      /* XXX, stub area check */
+
+      /* XXX, aggregate */
+        /* if either the area of the route or the area trying to
+           advertise is backbone, do not aggregate */
+
+      if (type == ADD)
+        ospf6_abr_prefix_lsa_update_add (&target, area);
+      else
+        ospf6_abr_prefix_lsa_update_remove (&target, area);
+    }
+}
+
+void
+ospf6_abr_route_add (struct ospf6_route_req *request)
+{
+  ospf6_abr_prefix_lsa_update (ADD, request);
+}
+
+void
+ospf6_abr_route_remove (struct ospf6_route_req *request)
+{
+  ospf6_abr_prefix_lsa_update (REMOVE, request);
+}
+
+int
+ospf6_abr_prefix_lsa_refresh (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_inter_area_prefix_lsa *ier;
+  struct prefix_ipv6 prefix6;
+  struct ospf6_route_req route;
+
+  ier = OSPF6_LSA_HEADER_END (lsa->header);
+  memset (&prefix6, 0, sizeof (prefix6));
+  prefix6.family = AF_INET6;
+  prefix6.prefixlen = ier->prefix.prefix_length;
+  ospf6_prefix_in6_addr (&ier->prefix, &prefix6.prefix);
+
+  ospf6_route_lookup (&route, (struct prefix *) &prefix6,
+                      ospf6->route_table);
+  assert (! ospf6_route_end (&route));
+
+  ospf6_abr_prefix_lsa_update (ADD, &route);
+  return 0;
+}
+
+int
+ospf6_abr_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  struct ospf6_inter_area_prefix_lsa *ier;
+  char prefix[128];
+
+  assert (lsa->header);
+  ier = OSPF6_LSA_HEADER_END (lsa->header);
+
+  ospf6_prefix_string (&ier->prefix, prefix, sizeof (prefix));
+
+  vty_out (vty, "     Metric: %d%s",
+           ntohl (ier->metric & htonl (0x000fffff)), VTY_NEWLINE);
+  vty_out (vty, "     Prefix: %s%s", prefix, VTY_NEWLINE);
+
+  return 0;
+}
+
+int
+ospf6_abr_prefix_lsa_hook_add (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  ospf6_abr_prefix_lsa_add (lsa);
+  return 0;
+}
+
+int
+ospf6_abr_prefix_lsa_hook_remove (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  ospf6_abr_prefix_lsa_remove (lsa);
+  return 0;
+}
+
+void
+ospf6_abr_database_hook_inter_prefix (struct ospf6_lsa *old,
+                                      struct ospf6_lsa *new)
+{
+  if (old)
+    ospf6_abr_prefix_lsa_hook_remove (old);
+  if (new && ! IS_LSA_MAXAGE (new))
+    ospf6_abr_prefix_lsa_hook_add (new);
+}
+
+void
+ospf6_abr_register_inter_prefix ()
+{
+  struct ospf6_lsa_slot slot;
+
+  memset (&slot, 0, sizeof (slot));
+  slot.type         = htons (OSPF6_LSA_TYPE_INTER_PREFIX);
+  slot.name         = "Inter-Prefix";
+  slot.func_show    = ospf6_abr_prefix_lsa_show;
+  slot.func_refresh = ospf6_abr_prefix_lsa_refresh;
+  ospf6_lsa_slot_register (&slot);
+
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_abr_database_hook_inter_prefix;
+}
+
+int
+ospf6_abr_router_lsa_hook_add (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  ospf6_abr_router_lsa_add (lsa);
+  return 0;
+}
+
+int
+ospf6_abr_router_lsa_hook_remove (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  ospf6_abr_router_lsa_remove (lsa);
+  return 0;
+}
+
+int
+ospf6_abr_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  return 0;
+}
+
+int
+ospf6_abr_router_lsa_refresh (void *data)
+{
+  return 0;
+}
+
+void
+ospf6_abr_database_hook_inter_router (struct ospf6_lsa *old,
+                                      struct ospf6_lsa *new)
+{
+  if (old)
+    ospf6_abr_router_lsa_hook_remove (old);
+  if (new && ! IS_LSA_MAXAGE (new))
+    ospf6_abr_router_lsa_hook_add (new);
+}
+
+void
+ospf6_abr_register_inter_router ()
+{
+  struct ospf6_lsa_slot slot;
+
+  memset (&slot, 0, sizeof (slot));
+  slot.type         = htons (OSPF6_LSA_TYPE_INTER_ROUTER);
+  slot.name         = "Inter-Router";
+  slot.func_show    = ospf6_abr_router_lsa_show;
+  slot.func_refresh = ospf6_abr_router_lsa_refresh;
+  ospf6_lsa_slot_register (&slot);
+
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_abr_database_hook_inter_router;
+}
+
+void
+ospf6_abr_inter_route_calculation (struct ospf6_area *area)
+{
+  struct ospf6_lsdb_node node;
+
+  /* for each inter-prefix LSA */
+  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
+                        area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_abr_prefix_lsa_add (node.lsa);
+}
+
+void
+ospf6_abr_init ()
+{
+  abr_index = ospf6_dump_install ("abr", "Area Border Router Function\n");
+
+  ospf6_abr_register_inter_prefix ();
+  ospf6_abr_register_inter_router ();
+}
+
+
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
new file mode 100644 (file)
index 0000000..510532e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_ABR_H
+#define OSPF6_ABR_H
+
+/* Inter-Area-Prefix-LSA */
+struct ospf6_inter_area_prefix_lsa
+{
+  u_int32_t metric;           /* 12bits reserved, 20bits metric */
+  struct ospf6_prefix prefix; /* followed by one address prefix */
+};
+
+/* Inter-Area-Router-LSA */
+struct ospf6_inter_area_router_lsa
+{
+  u_char reserved;
+  u_char options[3];      /* Optional Capability */
+  u_int32_t metric;       /* 12bits reserved, 20bits metric */
+  u_int32_t router_id;    /* Destination Router ID */
+};
+
+void ospf6_abr_prefix_lsa_add (struct ospf6_lsa *);
+void ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *);
+void ospf6_abr_prefix_lsa_change (struct ospf6_lsa *, struct ospf6_lsa *);
+
+void ospf6_abr_abr_entry_add (struct ospf6_route_req *);
+void ospf6_abr_abr_entry_remove (struct ospf6_route_req *);
+
+void ospf6_abr_route_add (struct ospf6_route_req *);
+void ospf6_abr_route_remove (struct ospf6_route_req *);
+
+void ospf6_abr_inter_route_calculation (struct ospf6_area *);
+
+void ospf6_abr_init ();
+
+#endif /* OSPF6_ABR_H */
+
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
new file mode 100644 (file)
index 0000000..51af508
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * OSPF6 Area Data Structure
+ * Copyright (C) 1999-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+static int area_index;
+#define IS_OSPF6_DUMP_AREA (ospf6_dump_is_on (area_index))
+
+static void
+ospf6_area_foreach_interface (struct ospf6_area *o6a, void *arg, int val,
+                              void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_interface *o6i;
+
+  for (node = listhead (o6a->if_list); node; nextnode (node))
+    {
+      o6i = (struct ospf6_interface *) getdata (node);
+      (*func) (arg, val, o6i);
+    }
+}
+
+static void
+ospf6_area_foreach_neighbor (struct ospf6_area *o6a, void *arg, int val,
+                             void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_interface *o6i;
+
+  for (node = listhead (o6a->if_list); node; nextnode (node))
+    {
+      o6i = (struct ospf6_interface *) getdata (node);
+      (*o6i->foreach_nei) (o6i, arg, val, func);
+    }
+}
+
+static int
+ospf6_area_maxage_remover (struct thread *t)
+{
+  int count;
+  struct ospf6_area *o6a = (struct ospf6_area *) THREAD_ARG (t);
+
+  o6a->maxage_remover = (struct thread *) NULL;
+
+  count = 0;
+  o6a->foreach_nei (o6a, &count, NBS_EXCHANGE, ospf6_count_state);
+  o6a->foreach_nei (o6a, &count, NBS_LOADING, ospf6_count_state);
+  if (count != 0)
+    return 0;
+
+  ospf6_lsdb_remove_maxage (o6a->lsdb);
+  return 0;
+}
+
+void
+ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj)
+{
+  struct ospf6_area *o6a = (struct ospf6_area *) obj;
+
+  if (o6a->maxage_remover != NULL)
+    return;
+
+  o6a->maxage_remover =
+    thread_add_event (master, ospf6_area_maxage_remover, o6a, 0);
+}
+
+int
+ospf6_area_is_stub (struct ospf6_area *o6a)
+{
+  if (OSPF6_OPT_ISSET (o6a->options, OSPF6_OPT_E))
+    return 0;
+  return 1;
+}
+
+int
+ospf6_area_is_transit (struct ospf6_area *o6a)
+{
+  return 0;
+}
+
+\f
+
+void
+ospf6_area_route_add (void *data)
+{
+  struct ospf6_route_req *route = data;
+  struct in6_addr local;
+
+  inet_pton (AF_INET6, "::1", &local);
+  if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_AREA)
+        zlog_info ("AREA: Self-originated route add, ignore");
+      return;
+    }
+
+  ospf6_route_add (route, ospf6->route_table);
+}
+
+void
+ospf6_area_route_remove (void *data)
+{
+  struct ospf6_route_req *route = data;
+  struct in6_addr local;
+
+  inet_pton (AF_INET6, "::1", &local);
+  if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_AREA)
+        zlog_info ("AREA: Self-originated route remove, ignore");
+      return;
+    }
+
+  ospf6_route_remove (route, ospf6->route_table);
+}
+
+/* Make new area structure */
+struct ospf6_area *
+ospf6_area_create (u_int32_t area_id)
+{
+  struct ospf6_area *o6a;
+  char namebuf[64];
+
+  /* allocate memory */
+  o6a = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
+
+  /* initialize */
+  inet_ntop (AF_INET, &area_id, o6a->str, sizeof (o6a->str));
+  o6a->area_id = area_id;
+  o6a->if_list = list_new ();
+
+  o6a->lsdb = ospf6_lsdb_create ();
+  o6a->spf_tree = ospf6_spftree_create ();
+
+  snprintf (namebuf, sizeof (namebuf), "Area %s's route table", o6a->str);
+  o6a->route_table = ospf6_route_table_create (namebuf);
+  o6a->route_table->hook_add = ospf6_area_route_add;
+  o6a->route_table->hook_change = ospf6_area_route_add;
+  o6a->route_table->hook_remove = ospf6_area_route_remove;
+
+  snprintf (namebuf, sizeof (namebuf), "Area %s's topology table", o6a->str);
+  o6a->table_topology = ospf6_route_table_create (namebuf);
+  o6a->table_topology->hook_add = ospf6_intra_topology_add;
+  o6a->table_topology->hook_change = ospf6_intra_topology_add;
+  o6a->table_topology->hook_remove = ospf6_intra_topology_remove;
+
+  /* xxx, set options */
+  OSPF6_OPT_SET (o6a->options, OSPF6_OPT_V6);
+  OSPF6_OPT_SET (o6a->options, OSPF6_OPT_E);
+  OSPF6_OPT_SET (o6a->options, OSPF6_OPT_R);
+
+  o6a->foreach_if = ospf6_area_foreach_interface;
+  o6a->foreach_nei = ospf6_area_foreach_neighbor;
+
+  return o6a;
+}
+
+void
+ospf6_area_bind_top (struct ospf6_area *o6a, struct ospf6 *o6)
+{
+  o6a->ospf6 = o6;
+  CALL_CHANGE_HOOK (&area_hook, o6a);
+  return;
+}
+
+void
+ospf6_area_delete (struct ospf6_area *o6a)
+{
+  listnode n;
+  struct ospf6_interface *o6i;
+
+  CALL_REMOVE_HOOK (&area_hook, o6a);
+
+  /* ospf6 interface list */
+  for (n = listhead (o6a->if_list); n; nextnode (n))
+    {
+      o6i = (struct ospf6_interface *) getdata (n);
+      /* ospf6_interface_delete (o6i); */
+    }
+  list_delete (o6a->if_list);
+
+  /* terminate LSDB */
+  ospf6_lsdb_remove_all (o6a->lsdb);
+
+  /* spf tree terminate */
+  /* xxx */
+
+  /* threads */
+  if (o6a->spf_calc)
+    thread_cancel (o6a->spf_calc);
+  o6a->spf_calc = (struct thread *) NULL;
+  if (o6a->route_calc)
+    thread_cancel (o6a->route_calc);
+  o6a->route_calc = (struct thread *) NULL;
+
+  /* new */
+  ospf6_route_table_delete (o6a->route_table);
+
+  ospf6_spftree_delete (o6a->spf_tree);
+  ospf6_route_table_delete (o6a->table_topology);
+
+  /* free area */
+  XFREE (MTYPE_OSPF6_AREA, o6a);
+}
+
+struct ospf6_area *
+ospf6_area_lookup (u_int32_t area_id, struct ospf6 *o6)
+{
+  struct ospf6_area *o6a;
+  listnode n;
+
+  for (n = listhead (o6->area_list); n; nextnode (n))
+    {
+      o6a = (struct ospf6_area *) getdata (n);
+      if (o6a->area_id == area_id)
+        return o6a;
+    }
+
+  return (struct ospf6_area *) NULL;
+}
+
+void
+ospf6_area_show (struct vty *vty, struct ospf6_area *o6a)
+{
+  listnode i;
+  struct ospf6_interface *o6i;
+
+  vty_out (vty, " Area %s%s", o6a->str, VTY_NEWLINE);
+  vty_out (vty, "     Number of Area scoped LSAs is %u%s",
+           o6a->lsdb->count, VTY_NEWLINE);
+
+  ospf6_spf_statistics_show (vty, o6a->spf_tree);
+
+  vty_out (vty, "     Interface attached to this area:");
+  for (i = listhead (o6a->if_list); i; nextnode (i))
+    {
+      o6i = (struct ospf6_interface *) getdata (i);
+      vty_out (vty, " %s", o6i->interface->name);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  for (i = listhead (o6a->if_list); i; nextnode (i))
+    {
+      o6i = (struct ospf6_interface *) getdata (i);
+      if (listcount (o6i->neighbor_list) != 0)
+        ospf6_interface_statistics_show (vty, o6i);
+    }
+}
+
+void
+ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a)
+{
+#if 0
+  listnode node;
+  struct ospf6_interface *o6i;
+
+  vty_out (vty, "  Statistics of Area %s%s", o6a->str, VTY_NEWLINE);
+#endif
+}
+
+DEFUN (show_ipv6_ospf6_area_route,
+       show_ipv6_ospf6_area_route_cmd,
+       "show ipv6 ospf6 area A.B.C.D route",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       ROUTE_STR
+       )
+{
+  struct ospf6_area *o6a;
+  u_int32_t area_id;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  inet_pton (AF_INET, argv[0], &area_id);
+  o6a = ospf6_area_lookup (area_id, ospf6);
+
+  if (! o6a)
+    return CMD_SUCCESS;
+
+  argc -= 1;
+  argv += 1;
+
+  return ospf6_route_table_show (vty, argc, argv, o6a->route_table);
+}
+
+ALIAS (show_ipv6_ospf6_area_route,
+       show_ipv6_ospf6_area_route_prefix_cmd,
+       "show ipv6 ospf6 area A.B.C.D route (X::X|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       ROUTE_STR
+       "Specify IPv6 address\n"
+       "Detailed information\n"
+       )
+
+void
+ospf6_area_init ()
+{
+  area_index = ospf6_dump_install ("area", "Area information\n");
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_prefix_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
new file mode 100644 (file)
index 0000000..0684464
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * OSPF6 Area Data Structure
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF_AREA_H
+#define OSPF_AREA_H
+
+/* This file defines area parameters and data structures. */
+
+#define OSPF6_AREA_RANGE_ADVERTISE     0
+#define OSPF6_AREA_RANGE_NOT_ADVERTISE 1
+
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+
+struct ospf6_area
+{
+  char            str[16];
+
+  struct ospf6   *ospf6;      /* back pointer */
+  u_int32_t       area_id;
+  u_char          options[3]; /* OSPF Option including ExternalCapability */
+
+  list            if_list; /* OSPF interface to this area */
+
+  struct ospf6_lsdb *lsdb;
+
+  struct thread  *spf_calc;
+  struct thread  *route_calc;
+  int             stat_spf_execed;
+  int             stat_route_execed;
+
+  struct route_table *table; /* new route table */
+
+  struct prefix_ipv6 area_range;
+  struct ospf6_spftree *spf_tree;
+
+  struct ospf6_route_table *route_table;
+  struct ospf6_route_table *table_topology;
+
+  void (*foreach_if)  (struct ospf6_area *, void *, int,
+                       void (*func) (void *, int, void *));
+  void (*foreach_nei) (struct ospf6_area *, void *, int,
+                       void (*func) (void *, int, void *));
+
+  struct thread *maxage_remover;
+
+  struct thread *thread_router_lsa;
+};
+
+
+/* prototypes */
+
+int
+ospf6_area_count_neighbor_in_state (u_char state, struct ospf6_area *o6a);
+
+void
+ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj);
+
+int ospf6_area_is_stub (struct ospf6_area *o6a);
+int ospf6_area_is_transit (struct ospf6_area *o6a);
+struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *);
+struct ospf6_area *ospf6_area_create (u_int32_t);
+void ospf6_area_delete (struct ospf6_area *);
+void ospf6_area_show (struct vty *, struct ospf6_area *);
+void
+ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a);
+
+void ospf6_area_init ();
+
+#endif /* OSPF_AREA_H */
+
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
new file mode 100644 (file)
index 0000000..00a2b66
--- /dev/null
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (C) 2001-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "ospf6_prefix.h"  /* xxx for ospf6_asbr.h */
+#include "ospf6_lsa.h"     /* xxx for ospf6_asbr.h */
+#include "ospf6_route.h"   /* xxx for ospf6_asbr.h, ospf6_zebra.h */
+#include "ospf6_zebra.h"
+#include "ospf6_asbr.h"
+#include "ospf6_damp.h"
+#include "ospf6_top.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_proto.h"
+
+extern struct thread_master *master;
+
+struct route_table *external_table;
+struct
+{
+  char *name;
+  struct route_map *map;
+} rmap [ZEBRA_ROUTE_MAX];
+
+static u_int32_t link_state_id = 0;
+
+char *
+zroute_name[] =
+{ 
+  "system", "kernel", "connected", "static",
+  "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
+};
+char *
+zroute_abname[] =
+{
+  "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
+};
+
+#define ZROUTE_NAME(x) \
+  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+   zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+
+#define ZROUTE_ABNAME(x) \
+  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+   zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+
+/* redistribute function */
+void
+ospf6_asbr_routemap_set (int type, char *mapname)
+{
+  if (rmap[type].name)
+    free (rmap[type].name);
+
+  rmap[type].name = strdup (mapname);
+  rmap[type].map = route_map_lookup_by_name (mapname);
+}
+
+void
+ospf6_asbr_routemap_unset (int type)
+{
+  if (rmap[type].name)
+    free (rmap[type].name);
+  rmap[type].name = NULL;
+  rmap[type].map = NULL;
+}
+
+void
+ospf6_asbr_routemap_update ()
+{
+  int i;
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (rmap[i].name)
+        rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+      else
+        rmap[i].map = NULL;
+    }
+}
+
+DEFUN (ospf6_redistribute,
+       ospf6_redistribute_cmd,
+       "redistribute (static|kernel|connected|ripng|bgp)",
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+{
+  int type = 0;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_unset (type);
+  ospf6_zebra_redistribute (type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_redistribute_routemap,
+       ospf6_redistribute_routemap_cmd,
+       "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+       "Redistribute\n"
+       "Static routes\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+       "Route map reference\n"
+       "Route map name\n"
+      )
+{
+  int type = 0;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_set (type, argv[1]);
+  ospf6_zebra_redistribute (type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_redistribute,
+       no_ospf6_redistribute_cmd,
+       "no redistribute (static|kernel|connected|ripng|bgp)",
+       NO_STR
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+{
+  int type = 0;
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info, *info_next = NULL;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_unset (type);
+
+  /* remove redistributed route */
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (! route)
+        continue;
+      for (info = route->info_head; info; info = info_next)
+        {
+          info_next = info->next;
+          if (info->type != type)
+            continue;
+          ospf6_asbr_route_remove (info->type, info->ifindex,
+                                   &route->prefix);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+
+int
+ospf6_redistribute_config_write (struct vty *vty)
+{
+  int i;
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (i == ZEBRA_ROUTE_OSPF6)
+        continue;
+
+      if (! ospf6_zebra_is_redistribute (i))
+        continue;
+
+      if (rmap[i].map)
+        vty_out (vty, " redistribute %s route-map %s%s",
+                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+      else
+        vty_out (vty, " redistribute %s%s",
+                 ZROUTE_NAME(i), VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+ospf6_redistribute_show_config (struct vty *vty)
+{
+  int i;
+
+  if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
+    return;
+
+  vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (i == ZEBRA_ROUTE_OSPF6)
+        continue;
+      if (! ospf6_zebra_is_redistribute (i))
+        continue;
+
+      if (rmap[i].map)
+        vty_out (vty, "    %s with route-map %s%s",
+                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+      else
+        vty_out (vty, "    %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
+    }
+}
+
+/* AS External LSA origination */
+int
+ospf6_asbr_external_lsa_originate (struct thread *thread)
+{
+  struct ospf6_external_info *info;
+  char buffer [MAXLSASIZE];
+  struct ospf6_lsa_as_external *e;
+  char *p;
+
+  info = THREAD_ARG (thread);
+
+  /* clear thread */
+  info->thread_originate = NULL;
+
+  if (info->is_removed)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char pbuf[64];
+          prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+          zlog_info ("ASBR: quit redistribution %s: state is down",
+                     pbuf);
+        }
+      return 0;
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  e = (struct ospf6_lsa_as_external *) buffer;
+  p = (char *) (e + 1);
+
+  if (info->metric_type == 2)
+    SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E);   /* type2 */
+  else
+    UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
+
+  /* forwarding address */
+  if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+    SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+  else
+    UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+
+  /* external route tag */
+  UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
+
+  /* set metric. note: related to E bit */
+  OSPF6_ASBR_METRIC_SET (e, info->metric);
+
+  /* prefixlen */
+  e->prefix.prefix_length = info->route->prefix.prefixlen;
+
+  /* PrefixOptions */
+  e->prefix.prefix_options = info->prefix_options;
+
+  /* don't use refer LS-type */
+  e->prefix.prefix_refer_lstype = htons (0);
+
+  /* set Prefix */
+  memcpy (p, &info->route->prefix.u.prefix6,
+          OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen));
+  ospf6_prefix_apply_mask (&e->prefix);
+  p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen);
+
+  /* Forwarding address */
+  if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
+    {
+      memcpy (p, &info->forwarding, sizeof (struct in6_addr));
+      p += sizeof (struct in6_addr);
+    }
+
+  /* External Route Tag */
+  if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
+    {
+      /* xxx */
+    }
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                       htonl (info->id), ospf6->router_id,
+                       (char *) buffer, p - buffer, ospf6);
+  return 0;
+}
+
+int
+ospf6_asbr_schedule_external (void *data)
+{
+  struct ospf6_external_info *info = data;
+  u_long elasped_time, time = 0;
+
+  if (info->thread_originate)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char pbuf[64];
+          prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+          zlog_info ("ASBR: schedule redistribution %s: another thread",
+                     pbuf);
+        }
+      return 0;
+    }
+
+  elasped_time =
+    ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id, ospf6);
+  if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+    time = OSPF6_MIN_LS_INTERVAL - elasped_time;
+  else
+    time = 0;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec",
+                 pbuf, (u_long) info->id, time);
+    }
+
+  if (time)
+    info->thread_originate =
+      thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time);
+  else
+    info->thread_originate =
+      thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0);
+
+  return 0;
+}
+
+int
+ospf6_asbr_external_lsa_flush (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  if (lsa)
+    ospf6_lsa_premature_aging (lsa);
+  return 0;
+}
+
+int
+ospf6_asbr_external_lsa_refresh (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_lsa_as_external *e;
+  struct prefix prefix;
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info;
+
+  if (IS_OSPF6_DUMP_ASBR)
+    zlog_info ("ASBR: refresh %s", lsa->str);
+
+  e = (struct ospf6_lsa_as_external *) (lsa->header + 1);
+  ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6);
+  prefix.prefixlen = e->prefix.prefix_length;
+  prefix.family = AF_INET6;
+  apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix);
+
+  node = route_node_lookup (external_table, &prefix);
+  if (! node || ! node->info)
+    {
+      char pname[64];
+
+      prefix2str (&prefix, pname, sizeof (pname));
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: could not find %s: premature age", pname);
+      ospf6_lsa_premature_aging (lsa);
+      return 0;
+    }
+
+  /* find external_info */
+  route = node->info;
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (lsa->header->id == htonl (info->id))
+        break;
+    }
+
+  if (info)
+    ospf6_asbr_schedule_external (info);
+  else
+    ospf6_lsa_premature_aging (lsa);
+
+  return 0;
+}
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+                      u_int nexthop_num, struct in6_addr *nexthop)
+{
+  int ret;
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info, tinfo;
+
+  if (! ospf6_zebra_is_redistribute (type))
+    return;
+
+  /* apply route-map */
+  memset (&tinfo, 0, sizeof (struct ospf6_external_info));
+  if (rmap[type].map)
+    {
+      ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
+      if (ret == RMAP_DENYMATCH)
+        {
+          if (IS_OSPF6_DUMP_ASBR)
+            zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
+          return;
+        }
+    }
+
+  node = route_node_get (external_table, prefix);
+  route = node->info;
+
+  if (! route)
+    {
+      route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                       sizeof (struct ospf6_external_route));
+      memset (route, 0, sizeof (struct ospf6_external_route));
+
+      memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+      node->info = route;
+      route->node = node;
+    }
+
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (info->type == type && info->ifindex == ifindex)
+        break;
+    }
+
+  if (! info)
+    {
+      info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                      sizeof (struct ospf6_external_info));
+      memset (info, 0, sizeof (struct ospf6_external_info));
+
+      info->route = route;
+      /* add tail */
+      info->prev = route->info_tail;
+      if (route->info_tail)
+        route->info_tail->next = info;
+      else
+        route->info_head = info;
+      route->info_tail = info;
+
+      info->id = link_state_id++;
+    }
+
+  /* copy result of route-map */
+  info->metric_type = tinfo.metric_type;
+  info->metric = tinfo.metric;
+  memcpy (&info->forwarding, &tinfo.forwarding,
+          sizeof (struct in6_addr));
+
+  info->type = type;
+  info->ifindex = ifindex;
+
+  if (nexthop_num && nexthop)
+    {
+      info->nexthop_num = nexthop_num;
+
+      if (info->nexthop)
+        XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+
+      info->nexthop = (struct in6_addr *)
+        XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                 nexthop_num * sizeof (struct in6_addr));
+      memcpy (info->nexthop, nexthop,
+              nexthop_num * sizeof (struct in6_addr));
+    }
+
+  info->is_removed = 0;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      struct timeval now;
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
+                 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+    }
+
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
+                       ospf6_asbr_schedule_external, info);
+#else /*HAVE_OSPF6_DAMP*/
+  ospf6_asbr_schedule_external (info);
+#endif /*HAVE_OSPF6_DAMP*/
+}
+
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
+{
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info;
+  struct ospf6_lsa *lsa;
+
+  node = route_node_get (external_table, prefix);
+  route = node->info;
+
+  if (! route)
+    return;
+
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (info->type == type && info->ifindex == ifindex)
+        break;
+    }
+
+  if (! info)
+    return;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      struct timeval now;
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
+                 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+    }
+
+  if (info->thread_originate)
+    thread_cancel (info->thread_originate);
+  info->thread_originate = NULL;
+
+  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id, ospf6);
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
+                         ospf6_asbr_external_lsa_flush, lsa);
+#else /*HAVE_OSPF6_DAMP*/
+  ospf6_asbr_external_lsa_flush (lsa);
+#endif /*HAVE_OSPF6_DAMP*/
+
+#if 1
+  info->is_removed = 1;
+#else
+  /* remove from route */
+  if (info->prev)
+    info->prev->next = info->next;
+  else
+    info->route->info_head = info->next;
+  if (info->next)
+    info->next->prev = info->prev;
+  else
+    info->route->info_tail = info->prev;
+
+  /* if no info, free route */
+  if (! info->route->info_head && ! info->route->info_tail)
+    {
+      info->route->node->info = NULL;
+      free (info->route);
+    }
+
+  if (info->nexthop)
+    free (info->nexthop);
+  free (info);
+#endif /*0*/
+}
+
+void
+ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa_as_external *external;
+  struct prefix_ls asbr_id;
+  struct ospf6_route_req asbr_entry;
+  struct ospf6_route_req request;
+
+  external = OSPF6_LSA_HEADER_END (lsa->header);
+
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: maxage external lsa: %s seq: %lx",
+                   lsa->str, (u_long)ntohl (lsa->header->seqnum));
+      ospf6_asbr_external_lsa_remove (lsa);
+      return;
+    }
+
+  if (IS_OSPF6_DUMP_ASBR)
+    zlog_info ("ASBR: new external lsa: %s seq: %lx",
+               lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+  if (lsa->header->adv_router == ospf6->router_id)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: my external LSA, ignore");
+      return;
+    }
+
+  if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: metric is infinity, ignore");
+      return;
+    }
+
+  memset (&asbr_id, 0, sizeof (asbr_id));
+  asbr_id.family = AF_UNSPEC;
+  asbr_id.prefixlen = 64; /* xxx */
+  asbr_id.adv_router.s_addr = lsa->header->adv_router;
+
+  ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
+                      ospf6->topology_table);
+
+  if (ospf6_route_end (&asbr_entry))
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char buf[64];
+          inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
+          zlog_info ("ASBR: router %s not found, ignore", buf);
+        }
+      return;
+    }
+
+  memset (&request, 0, sizeof (request));
+  request.route.type = OSPF6_DEST_TYPE_NETWORK;
+  request.route.prefix.family = AF_INET6;
+  request.route.prefix.prefixlen = external->prefix.prefix_length;
+  memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
+          OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
+
+  request.path.area_id = asbr_entry.path.area_id;
+  request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+  request.path.origin.id = lsa->header->id;
+  request.path.origin.adv_router = lsa->header->adv_router;
+  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
+    {
+      request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+      request.path.metric_type = 2;
+      request.path.cost = asbr_entry.path.cost;
+      request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
+    }
+  else
+    {
+      request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+      request.path.metric_type = 1;
+      request.path.cost = asbr_entry.path.cost
+                          + OSPF6_ASBR_METRIC (external);
+      request.path.cost_e2 = 0;
+    }
+  request.path.prefix_options = external->prefix.prefix_options;
+
+  while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
+         asbr_id.adv_router.s_addr &&
+         asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
+    {
+      memcpy (&request.nexthop, &asbr_entry.nexthop,
+              sizeof (struct ospf6_nexthop));
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char buf[64], nhop[64], ifname[IFNAMSIZ];
+          prefix2str (&request.route.prefix, buf, sizeof (buf));
+          inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+          if_indextoname (request.nexthop.ifindex, ifname);
+          zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname);
+        }
+      ospf6_route_add (&request, ospf6->route_table);
+      ospf6_route_next (&asbr_entry);
+    }
+}
+
+void
+ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa_as_external *external;
+  struct prefix dest;
+  char buf[64];
+  struct ospf6_route_req request;
+
+  if (IS_OSPF6_DUMP_ASBR)
+    zlog_info ("ASBR: withdraw external lsa: %s seq: %lx",
+               lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+  if (lsa->header->adv_router == ospf6->router_id)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: my external LSA, ignore");
+      return;
+    }
+
+  external = OSPF6_LSA_HEADER_END (lsa->header);
+  memset (&dest, 0, sizeof (dest));
+  dest.family = AF_INET6;
+  dest.prefixlen = external->prefix.prefix_length;
+  memcpy (&dest.u.prefix6, (char *)(external + 1),
+          OSPF6_PREFIX_SPACE (dest.prefixlen));
+
+  ospf6_route_lookup (&request, &dest, ospf6->route_table);
+  if (ospf6_route_end (&request))
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          prefix2str (&dest, buf, sizeof (buf));
+          zlog_info ("ASBR: %s not found", buf);
+        }
+      return;
+    }
+
+  while (request.path.origin.id != lsa->header->id ||
+         request.path.origin.adv_router != lsa->header->adv_router)
+    {
+      if (prefix_same (&request.route.prefix, &dest) != 1)
+        {
+          if (IS_OSPF6_DUMP_ASBR)
+            zlog_info ("ASBR:   Can't find the entry matches the origin");
+          return;
+        }
+      ospf6_route_next (&request);
+    }
+  assert (request.path.origin.id == lsa->header->id);
+  assert (request.path.origin.adv_router == request.path.origin.adv_router);
+
+  while (request.path.origin.id == lsa->header->id &&
+         request.path.origin.adv_router == lsa->header->adv_router &&
+         prefix_same (&request.route.prefix, &dest) == 1)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char nhop[64], ifname[IFNAMSIZ];
+          prefix2str (&dest, buf, sizeof (buf));
+          inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+          if_indextoname (request.nexthop.ifindex, ifname);
+          zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname);
+        }
+
+      ospf6_route_remove (&request, ospf6->route_table);
+      ospf6_route_next (&request);
+    }
+}
+
+void
+ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+  assert (old || new);
+
+  if (old == NULL)
+    ospf6_asbr_external_lsa_add (new);
+  else if (new == NULL)
+    ospf6_asbr_external_lsa_remove (old);
+  else
+    {
+      ospf6_route_table_freeze (ospf6->route_table);
+      ospf6_asbr_external_lsa_remove (old);
+      ospf6_asbr_external_lsa_add (new);
+      ospf6_route_table_thaw (ospf6->route_table);
+    }
+}
+
+void
+ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
+{
+  struct ospf6_lsdb_node node;
+
+  struct prefix_ls *inter_router;
+  u_int32_t id, adv_router;
+
+  inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+  id = inter_router->id.s_addr;
+  adv_router = inter_router->adv_router.s_addr;
+
+  if (IS_OSPF6_DUMP_ASBR)
+    {
+      char buf[64];
+      inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+      zlog_info ("ASBR: new router found: %s", buf);
+    }
+
+  if (ntohl (id) != 0 ||
+      ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+    {
+      zlog_warn ("ASBR: Inter topology table malformed");
+      return;
+    }
+
+  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                               adv_router, ospf6->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_asbr_external_lsa_add (node.lsa);
+}
+
+void
+ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
+{
+  struct prefix_ls *inter_router;
+  u_int32_t id, adv_router;
+  struct ospf6_route_req request;
+
+  inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+  id = inter_router->id.s_addr;
+  adv_router = inter_router->adv_router.s_addr;
+
+  if (IS_OSPF6_DUMP_ASBR)
+    {
+      char buf[64];
+      inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+      zlog_info ("ASBR: router disappearing: %s", buf);
+    }
+
+  if (ntohl (id) != 0 ||
+      ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+    {
+      zlog_warn ("ASBR: Inter topology table malformed");
+    }
+
+  for (ospf6_route_head (&request, ospf6->route_table);
+       ! ospf6_route_end (&request);
+       ospf6_route_next (&request))
+    {
+      if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
+          request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
+        continue;
+      if (request.path.area_id != topo_entry->path.area_id)
+        continue;
+      if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
+        continue;
+      if (memcmp (&topo_entry->nexthop, &request.nexthop,
+                  sizeof (struct ospf6_nexthop)))
+        continue;
+
+      ospf6_route_remove (&request, ospf6->route_table);
+    }
+}
+
+int
+ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa_as_external *external;
+  char buf[128], *ptr;
+  struct in6_addr in6;
+
+  assert (lsa->header);
+  external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
+  
+  /* bits */
+  snprintf (buf, sizeof (buf), "%s%s%s",
+            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
+             "E" : "-"),
+            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
+             "F" : "-"),
+            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
+             "T" : "-"));
+
+  vty_out (vty, "     Bits: %s%s", buf, VTY_NEWLINE);
+  vty_out (vty, "     Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
+           VTY_NEWLINE);
+
+  ospf6_prefix_options_str (external->prefix.prefix_options,
+                            buf, sizeof (buf));
+  vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
+
+  vty_out (vty, "     Referenced LSType: %d%s",
+           ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
+
+  ospf6_prefix_in6_addr (&external->prefix, &in6);
+  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+  vty_out (vty, "     Prefix: %s/%d%s",
+           buf, external->prefix.prefix_length, VTY_NEWLINE);
+
+  /* Forwarding-Address */
+  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
+    {
+      ptr = ((char *)(external + 1))
+            + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
+      inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
+      vty_out (vty, "     Forwarding-Address: %s%s", buf, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+  if (old)
+    ospf6_asbr_external_lsa_remove (old);
+  if (new && ! IS_LSA_MAXAGE (new))
+    ospf6_asbr_external_lsa_add (new);
+}
+
+void
+ospf6_asbr_register_as_external ()
+{
+  struct ospf6_lsa_slot slot;
+
+  memset (&slot, 0, sizeof (slot));
+  slot.type              = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+  slot.name              = "AS-External";
+  slot.func_show         = ospf6_asbr_external_show;
+  slot.func_refresh      = ospf6_asbr_external_lsa_refresh;
+  ospf6_lsa_slot_register (&slot);
+
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_asbr_database_hook;
+}
+
+void
+ospf6_asbr_external_info_show (struct vty *vty,
+                               struct ospf6_external_info *info)
+{
+  char prefix_buf[64], id_buf[16];
+  struct in_addr id;
+
+  if (info->is_removed)
+    return;
+
+  id.s_addr = ntohl (info->id);
+  inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf));
+  prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf));
+  vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s",
+           ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf,
+           info->nexthop_num, (u_long) info->metric, info->metric_type,
+           VTY_NEWLINE);
+}
+
+void
+ospf6_asbr_external_route_show (struct vty *vty,
+                                struct ospf6_external_route *route)
+{
+  struct ospf6_external_info *info;
+  for (info = route->info_head; info; info = info->next)
+    ospf6_asbr_external_info_show (vty, info);
+}
+
+DEFUN (show_ipv6_route_ospf6_external,
+       show_ipv6_route_ospf6_external_cmd,
+       "show ipv6 ospf6 route redistribute",
+       SHOW_STR
+       IP6_STR
+       ROUTE_STR
+       OSPF6_STR
+       "redistributing External information\n"
+       )
+{
+  struct route_node *node;
+  struct ospf6_external_route *route;
+
+  vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
+           " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
+           VTY_NEWLINE);
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (route)
+        ospf6_asbr_external_route_show (vty, route);
+    }
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_asbr_init ()
+{
+  external_table = route_table_init ();
+  link_state_id = 0;
+
+  ospf6_asbr_register_as_external ();
+
+  install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
+  install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
new file mode 100644 (file)
index 0000000..153ed21
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_ASBR_H
+#define OSPF6_ASBR_H
+
+#include "thread.h"
+
+struct ospf6_external_info
+{
+  int is_removed;
+  struct thread *thread_originate;
+
+  struct ospf6_external_route *route;
+
+  struct ospf6_external_info *prev;
+  struct ospf6_external_info *next;
+
+  /* external route type */
+  int type;
+
+  /* external route ifindex */
+  int ifindex;
+
+  /* LS-ID */
+  u_int32_t id;
+
+  /* nexthops */
+  u_int nexthop_num;
+  struct in6_addr *nexthop;
+
+  u_int8_t  prefix_options;
+
+  u_int8_t  metric_type;
+  u_int32_t metric;
+  struct in6_addr forwarding;
+  /* u_int32_t tag; */
+};
+
+struct ospf6_external_route
+{
+  struct route_node *node;
+
+  /* prefix */
+  struct prefix prefix;
+
+  /* external information */
+  struct ospf6_external_info *info_head;
+  struct ospf6_external_info *info_tail;
+};
+
+/* AS-External-LSA */
+struct ospf6_lsa_as_external
+{
+  u_int32_t bits_metric;
+
+  struct ospf6_prefix prefix;
+  /* followed by none or one forwarding address */
+  /* followed by none or one external route tag */
+  /* followed by none or one referenced LS-ID */
+};
+
+#define OSPF6_ASBR_BIT_T  ntohl (0x01000000)
+#define OSPF6_ASBR_BIT_F  ntohl (0x02000000)
+#define OSPF6_ASBR_BIT_E  ntohl (0x04000000)
+
+#define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff)))
+#define OSPF6_ASBR_METRIC_SET(E,C) \
+  { (E)->bits_metric &= htonl (0xff000000); \
+    (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); }
+
+void ospf6_asbr_routemap_update ();
+
+int ospf6_redistribute_config_write (struct vty *vty);
+void ospf6_redistribute_show_config (struct vty *vty);
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+                      u_int nexthop_num, struct in6_addr *nexthop);
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix);
+
+void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa);
+void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa);
+void ospf6_asbr_external_lsa_change (struct ospf6_lsa *old,
+                                     struct ospf6_lsa *new);
+
+void ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry);
+void ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry);
+
+void ospf6_asbr_init ();
+
+#endif /* OSPF6_ASBR_H */
+
diff --git a/ospf6d/ospf6_bintree.c b/ospf6d/ospf6_bintree.c
new file mode 100644 (file)
index 0000000..c1e9e55
--- /dev/null
@@ -0,0 +1,436 @@
+
+#include <zebra.h>
+#include "ospf6_bintree.h"
+
+static struct bintree_node *
+bintree_lookup_node_min (struct bintree_node *subroot)
+{
+  struct bintree_node *node;
+
+  if (subroot == NULL)
+    return NULL;
+
+  node = subroot;
+  while (node->bl_left)
+    node = node->bl_left;
+  return node;
+}
+
+static struct bintree_node *
+bintree_lookup_node_max (struct bintree_node *subroot)
+{
+  struct bintree_node *node;
+
+  assert (subroot != NULL);
+  node = subroot;
+  while (node->bl_right)
+    node = node->bl_right;
+  return node;
+}
+
+void *
+bintree_lookup (void *data, struct bintree *tree)
+{
+  int cmp;
+  struct bintree_node *node;
+
+  node = tree->root;
+
+  while (node)
+    {
+      if (tree->cmp)
+        cmp = (*tree->cmp) (node->data, data);
+      else
+        cmp = (node->data - data);
+
+      if (cmp == 0)
+        break;
+
+      if (cmp > 0)
+        node = node->bl_left;
+      else /* if (cmp < 0) */
+        node = node->bl_right;
+    }
+
+  if (node)
+    return node->data;
+
+  return NULL;
+}
+
+void *
+bintree_lookup_min (struct bintree *tree)
+{
+  struct bintree_node *node;
+  node = bintree_lookup_node_min (tree->root);
+  if (node == NULL)
+    return NULL;
+  return node->data;
+}
+
+void *
+bintree_lookup_max (struct bintree *tree)
+{
+  struct bintree_node *node;
+  node = bintree_lookup_node_max (tree->root);
+  if (node == NULL)
+    return NULL;
+  return node->data;
+}
+
+int
+bintree_add (void *data, struct bintree *tree)
+{
+  int cmp = 0;
+  struct bintree_node *node, *parent;
+
+  node = tree->root;
+  parent = NULL;
+
+  while (node)
+    {
+      if (tree->cmp)
+        cmp = (*tree->cmp) (node->data, data);
+      else
+        cmp = (node->data - data);
+
+      if (cmp == 0)
+        break;
+
+      parent = node;
+      if (cmp > 0)
+        node = node->bl_left;
+      else /* if (cmp < 0) */
+        node = node->bl_right;
+    }
+
+  if (node)
+    return -1;
+
+  node = malloc (sizeof (struct bintree_node));
+  memset (node, 0, sizeof (struct bintree_node));
+  node->tree = tree;
+  node->data = data;
+
+  if (parent)
+    {
+      node->parent = parent;
+
+      assert (cmp != 0);
+      if (cmp > 0)
+        {
+          node->parent_link = BL_LEFT;
+          parent->bl_left = node;
+        }
+      else /* if (cmp < 0) */
+        {
+          node->parent_link = BL_RIGHT;
+          parent->bl_right = node;
+        }
+    }
+  else
+    tree->root = node;
+
+  tree->count++;
+  return 0;
+}
+
+static void
+bintree_remove_nochild (struct bintree_node *node)
+{
+  assert (node->bl_left == NULL && node->bl_right == NULL);
+
+  if (node->parent == NULL)
+    node->tree->root = NULL;
+  else
+    node->parent->link[node->parent_link] = NULL;
+}
+
+static void
+bintree_remove_onechild (struct bintree_node *node)
+{
+  assert ((node->bl_left == NULL && node->bl_right != NULL) ||
+          (node->bl_left != NULL && node->bl_right == NULL));
+
+  if (node->bl_left)
+    {
+      if (node->parent == NULL)
+        {
+          node->tree->root = node->bl_left;
+          node->bl_left->parent = NULL;
+        }
+      else
+        {
+          node->parent->link[node->parent_link] = node->bl_left;
+          node->bl_left->parent = node->parent;
+          node->bl_left->parent_link = node->parent_link;
+        }
+    }
+  else if (node->bl_right)
+    {
+      if (node->parent == NULL)
+        {
+          node->tree->root = node->bl_right;
+          node->bl_right->parent = NULL;
+        }
+      else
+        {
+          node->parent->link[node->parent_link] = node->bl_right;
+          node->bl_right->parent = node->parent;
+          node->bl_right->parent_link = node->parent_link;
+        }
+    }
+  else
+    assert (0);
+}
+
+int
+bintree_remove (void *data, struct bintree *tree)
+{
+  int cmp;
+  struct bintree_node *node;
+
+  node = tree->root;
+
+  while (node)
+    {
+      if (tree->cmp)
+        cmp = (*tree->cmp) (node->data, data);
+      else
+        cmp = (node->data - data);
+
+      if (cmp == 0)
+        break;
+
+      if (cmp > 0)
+        node = node->bl_left;
+      else /* if (cmp < 0) */
+        node = node->bl_right;
+    }
+
+  if (node == NULL)
+    return -1;
+
+  if (node->bl_left == NULL && node->bl_right == NULL)
+    {
+      bintree_remove_nochild (node);
+      free (node);
+      tree->count--;
+      return 0;
+    }
+
+  if ((node->bl_left == NULL && node->bl_right != NULL) ||
+      (node->bl_left != NULL && node->bl_right == NULL))
+    {
+      bintree_remove_onechild (node);
+      free (node);
+      tree->count--;
+      return 0;
+    }
+
+  if (node->bl_left != NULL && node->bl_right != NULL)
+    {
+      struct bintree_node *successor;
+
+      /* find successor of the removing node */
+      successor = bintree_lookup_node_min (node->bl_right);
+
+      /* remove successor from tree */
+      if (successor->bl_right)
+        bintree_remove_onechild (successor);
+      else
+        bintree_remove_nochild (successor);
+
+      /* swap removing node with successor */
+      successor->parent = node->parent;
+      successor->parent_link = node->parent_link;
+      successor->bl_left = node->bl_left;
+      successor->bl_right = node->bl_right;
+
+      /* if the successor was the node->bl_right itself,
+         bintree_remove_**child may touch node->bl_right,
+         so only the successor->bl_right may be NULL
+         by above assignment */
+      successor->bl_left->parent = successor;
+      if (successor->bl_right)
+        successor->bl_right->parent = successor;
+
+      if (successor->parent == NULL)
+        tree->root = successor;
+      else
+        successor->parent->link[successor->parent_link] = successor;
+
+      free (node);
+      tree->count--;
+      return 0;
+    }
+
+  /* not reached */
+  return -1;
+}
+
+/* in-order traversal */
+
+void
+bintree_head (struct bintree *tree, struct bintree_node *node)
+{
+  struct bintree_node *head;
+
+  head = bintree_lookup_node_min (tree->root);
+  if (head == NULL)
+    {
+      node->parent = NULL;
+      node->bl_left = NULL;
+      node->bl_right = NULL;
+      node->data = NULL;
+      return;
+    }
+
+  node->tree = head->tree;
+  node->parent = head->parent;
+  node->parent_link = head->parent_link;
+  node->bl_left = head->bl_left;
+  node->bl_right = head->bl_right;
+  node->data = head->data;
+}
+
+int
+bintree_end (struct bintree_node *node)
+{
+  if (node->parent || node->bl_left || node->bl_right || node->data)
+    return 0;
+  return 1;
+}
+
+#define GOTO_PROCED_SUBTREE_TOP(node) \
+  while (node->parent && node->parent->bl_right && \
+         node->parent->bl_right->data == node->data) \
+    { \
+      node->data = node->parent->data; \
+      node->bl_left = node->parent->bl_left; \
+      node->bl_right = node->parent->bl_right; \
+      node->parent_link = node->parent->parent_link; \
+      node->parent = node->parent->parent; \
+    }
+
+void
+bintree_next (struct bintree_node *node)
+{
+  struct bintree_node *next = NULL;
+
+  /* if node have just been removed, current point should have just been
+     replaced with its successor. that certainly  will not be processed
+     yet, so process it */
+  if (node->parent == NULL)
+    {
+      if (node->tree->root == NULL)
+        {
+          assert (node->tree->count == 0);
+          node->parent = NULL;
+          node->bl_left = NULL;
+          node->bl_right = NULL;
+          node->data = NULL;
+          return;
+        }
+      else if (node->tree->root->data != node->data)
+        next = node->tree->root;
+    }
+  else if (node->parent->link[node->parent_link] == NULL)
+    {
+      if (node->parent_link == BL_LEFT)
+        next = node->parent;
+      else
+        {
+          GOTO_PROCED_SUBTREE_TOP (node);
+          next = node->parent;
+        }
+    }
+  else if (node->parent->link[node->parent_link]->data != node->data)
+    next = node->parent->link[node->parent_link];
+
+  if (next == NULL)
+    {
+      if (node->bl_right)
+        next = bintree_lookup_node_min (node->bl_right);
+      else
+        {
+          GOTO_PROCED_SUBTREE_TOP (node);
+          next = node->parent;
+        }
+    }
+
+  if (next)
+    {
+      node->tree = next->tree;
+      node->parent = next->parent;
+      node->parent_link = next->parent_link;
+      node->bl_left = next->bl_left;
+      node->bl_right = next->bl_right;
+      node->data = next->data;
+    }
+  else
+    {
+      node->parent = NULL;
+      node->bl_left = NULL;
+      node->bl_right = NULL;
+      node->data = NULL;
+    }
+}
+
+struct bintree *
+bintree_create ()
+{
+  struct bintree *tree;
+
+  tree = malloc (sizeof (struct bintree));
+  memset (tree, 0, sizeof (struct bintree));
+
+  return tree;
+}
+
+void
+bintree_delete (struct bintree *tree)
+{
+  struct bintree_node node;
+
+  for (bintree_head (tree, &node); ! bintree_end (&node);
+       bintree_next (&node))
+    bintree_remove (node.data, tree);
+
+  assert (tree->count == 0);
+  free (tree);
+}
+
+int indent_num = 0;
+
+void
+bintree_print_sub (void (*print) (int, void *), struct bintree_node *subroot)
+{
+  if (subroot == NULL)
+    return;
+
+  if (subroot->bl_right)
+    {
+      indent_num++;
+      bintree_print_sub (print, subroot->bl_right);
+      indent_num--;
+    }
+
+  (*print) (indent_num, subroot->data);
+
+  if (subroot->bl_left)
+    {
+      indent_num++;
+      bintree_print_sub (print, subroot->bl_left);
+      indent_num--;
+    }
+}
+
+void
+bintree_print (void (*print) (int, void *), struct bintree *tree)
+{
+  indent_num = 0;
+  bintree_print_sub (print, tree->root);
+}
+
+
diff --git a/ospf6d/ospf6_bintree.h b/ospf6d/ospf6_bintree.h
new file mode 100644 (file)
index 0000000..fad8bbd
--- /dev/null
@@ -0,0 +1,47 @@
+
+#ifndef _BINTREE_H_
+#define _BINTREE_H_
+
+struct bintree_node
+{
+  struct bintree *tree;
+
+  struct bintree_node *parent;
+  int parent_link;
+
+#define BL_LEFT  0
+#define BL_RIGHT 1
+#define BL_MAX   2
+  struct bintree_node *link[BL_MAX];
+#define bl_left  link[BL_LEFT]
+#define bl_right link[BL_RIGHT]
+
+  void *data;
+};
+
+struct bintree
+{
+  int count;
+  struct bintree_node *root;
+
+  int  (*cmp)   (void *, void *);
+};
+
+void *bintree_lookup (void *data, struct bintree *tree);
+void *bintree_lookup_min (struct bintree *tree);
+void *bintree_lookup_max (struct bintree *tree);
+
+int   bintree_add (void *data, struct bintree *tree);
+int   bintree_remove (void *data, struct bintree *tree);
+
+void bintree_head (struct bintree *tree, struct bintree_node *node);
+int  bintree_end (struct bintree_node *node);
+void bintree_next (struct bintree_node *node);
+
+struct bintree *bintree_create ();
+void bintree_delete (struct bintree *);
+
+void bintree_print (void (*print) (int, void *), struct bintree *);
+
+#endif /*_BINTREE_H_*/
+
diff --git a/ospf6d/ospf6_damp.c b/ospf6d/ospf6_damp.c
new file mode 100644 (file)
index 0000000..4e807a7
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002 
+ * 
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; 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 <math.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "thread.h"
+#include "table.h"
+#include "command.h"
+#include "vty.h"
+
+extern struct thread_master *master;
+
+#include "ospf6_damp.h"
+
+#ifdef HAVE_OSPF6_DAMP
+
+#define DELTA_REUSE         10 /* Time granularity for reuse lists */
+#define DELTA_T              5 /* Time granularity for decay arrays */
+#define DEFAULT_HALF_LIFE   60 /* (sec)     1 min */
+
+#define DEFAULT_PENALTY   1000
+#define DEFAULT_REUSE      750
+#define DEFAULT_SUPPRESS  2000
+
+#define REUSE_LIST_SIZE    256
+#define REUSE_ARRAY_SIZE  1024
+
+/* Global variable to access damping configuration */
+struct ospf6_damp_config damp_config;
+struct ospf6_damp_config *dc = &damp_config;
+u_int reuse_array_offset = 0;
+struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX];
+struct thread *ospf6_reuse_thread = NULL;
+
+int ospf6_damp_debug = 0;
+#define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug)
+
+static struct ospf6_damp_info *
+ospf6_damp_lookup (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+
+  node = route_node_lookup (damp_info_table[type], name);
+  if (node && node->info)
+    return (struct ospf6_damp_info *) node->info;
+  return NULL;
+}
+
+static struct ospf6_damp_info *
+ospf6_damp_create (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+
+  di = ospf6_damp_lookup (type, name);
+  if (di)
+    return di;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (name, namebuf, sizeof (namebuf));
+      zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf);
+    }
+
+  di = (struct ospf6_damp_info *)
+    malloc (sizeof (struct ospf6_damp_info));
+  memset (di, 0, sizeof (struct ospf6_damp_info));
+  di->type = type;
+  prefix_copy (&di->name, name);
+
+  node = route_node_get (damp_info_table[type], name);
+  node->info = di;
+
+  return di;
+}
+
+static void
+ospf6_damp_delete (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+
+  node = route_node_lookup (damp_info_table[type], name);
+  if (! node || ! node->info)
+    return;
+
+  di = node->info;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      zlog_info ("DAMP: delete: type: %d, name: %s",
+                 di->type, namebuf);
+    }
+
+  node->info = NULL;
+  free (di);
+}
+
+/* compute and fill the configuration parameter */
+void
+ospf6_damp_init_config (u_int half_life, u_int reuse,
+                        u_int suppress, u_int t_hold)
+{
+  int i;
+  double max_ratio, max_ratio1, max_ratio2;
+
+  dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE;
+  dc->reuse     = reuse     ? reuse     : DEFAULT_REUSE;
+  dc->suppress  = suppress  ? suppress  : DEFAULT_SUPPRESS;
+  dc->t_hold    = t_hold    ? t_hold    : 4 * dc->half_life;
+
+  /* Initialize system-wide params */
+  dc->delta_t = DELTA_T;
+  dc->delta_reuse = DELTA_REUSE;
+  dc->default_penalty = DEFAULT_PENALTY;
+  dc->reuse_index_array_size = REUSE_ARRAY_SIZE;
+
+  /* ceiling is the maximum penalty a route may attain */
+  /* ceiling = reuse * 2^(T-hold/half-life) */
+  dc->ceiling = (int)
+    (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life)));
+
+  /* Decay-array computations */
+  /* decay_array_size = decay memory/time granularity */
+  dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t);
+  dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size));
+
+  /* Each i-th element is per tick delay raised to the i-th power */
+  dc->decay_array[0] = 1.0;
+  dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5));
+  for (i = 2; i < dc->decay_array_size; i++)
+    dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1];
+
+  /* Reuse-list computations (reuse queue head array ?) */
+  dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1;
+  if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE)
+    dc->reuse_list_size = REUSE_LIST_SIZE;
+  dc->reuse_list_array = (struct ospf6_damp_info **)
+    malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+  memset (dc->reuse_list_array, 0x00,
+          dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+
+  /* Reuse-array computations */
+  dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size);
+
+  /*
+   * This is the maximum ratio between the current value of the penalty and
+   * the reuse value which can be indexed by the reuse array. It will be 
+   * limited by the ceiling or by the amount of time that the reuse list 
+   * covers 
+   */
+  max_ratio1 = (double) dc->ceiling / dc->reuse;
+  max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0);
+  max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ?
+               max_ratio2 : max_ratio1);
+
+  /*
+   * reuse array is just an estimator and we need something
+   * to use the full array 
+   */
+  dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1);
+
+  for (i = 0; i < dc->reuse_index_array_size; i++)
+    {
+      dc->reuse_index_array[i] = (int)
+        (((double) dc->half_life / dc->delta_reuse) *
+         log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor))))
+         / log10 (0.5));
+    }
+
+  dc->enabled = ON;
+}
+
+static double
+ospf6_damp_decay (time_t tdiff)
+{
+  int index = tdiff / dc->delta_t;
+
+  if (index >= dc->decay_array_size)
+    return 0;
+
+  return dc->decay_array[index];
+}
+
+static int
+ospf6_damp_reuse_index (int penalty)
+{
+  int index;
+
+  index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor);
+
+  if (index >= dc->reuse_index_array_size)
+    index = dc->reuse_index_array_size - 1;
+
+  return (dc->reuse_index_array[index] - dc->reuse_index_array[0]);
+}
+
+static int
+ospf6_reuse_list_lookup (struct ospf6_damp_info *di)
+{
+  struct ospf6_damp_info *info;
+
+  for (info = dc->reuse_list_array[di->index]; info; info = info->next)
+    {
+      if (info == di)
+        return 1;
+    }
+  return 0;
+}
+
+static void
+ospf6_reuse_list_remove (struct ospf6_damp_info *di)
+{
+  if (di->prev)
+    di->prev->next = di->next;
+  else
+    dc->reuse_list_array[di->index] = di->next;
+  if (di->next)
+    di->next->prev = di->prev;
+
+  di->index = -1;
+  di->prev = NULL;
+  di->next = NULL;
+}
+
+static void
+ospf6_reuse_list_add (struct ospf6_damp_info *di)
+{
+  /* set the index of reuse-array */
+  di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty)))
+              % dc->reuse_list_size;
+
+  /* insert to the head of the reuse list */
+  di->next = dc->reuse_list_array[di->index];
+  if (di->next)
+    di->next->prev = di;
+  di->prev = NULL;
+  dc->reuse_list_array[di->index] = di;
+}
+
+/* When we quit damping for a target, we should execute proper event
+   which have been postponed during damping */
+static void
+ospf6_damp_stop (struct ospf6_damp_info *di)
+{
+  time_t t_now;
+  char namebuf[64];
+  struct timeval now;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      t_now = time (NULL);
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+                 now.tv_sec, now.tv_usec,
+                 t_now, di->type, namebuf);
+    }
+
+  /* set flag indicates that we're damping this target */
+  di->damping = OFF;
+
+  /* if the target's current status differ from that it should be,
+     execute the proper event to repair his status */
+  if (di->target_status != di->event_type)
+    {
+      (*(di->event)) (di->target);
+      di->target_status = di->event_type;
+
+      di->event = NULL;
+      di->event_type = event_none;
+    }
+}
+
+/* ospf6_reuse_timer is called every DELTA_REUSE seconds.
+   Each route in the current reuse-list is evaluated
+   and is used or requeued */
+int
+ospf6_damp_reuse_timer (struct thread *t)
+{
+  struct ospf6_damp_info *di, *next;
+  time_t t_now, t_diff;
+  char namebuf[64];
+  struct timeval now;
+
+  /* Restart the reuse timer */
+  ospf6_reuse_thread =
+    thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+  t_now = time (NULL);
+
+  /* get the damp info list head */
+  di = dc->reuse_list_array[reuse_array_offset];
+  dc->reuse_list_array[reuse_array_offset] = NULL;
+
+  /* rotate the circular reuse list head array */
+  reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size;
+
+  /* for each damp info */
+  while (di)
+    {
+      next = di->next;
+      di->next = NULL;
+
+      /* Update penalty */
+      t_diff = t_now - di->t_updated;
+      di->t_updated = t_now;
+      di->penalty = (int)
+        ((double) di->penalty * ospf6_damp_decay (t_diff));
+      /* configration of ceiling may be just changed */
+      if (di->penalty > dc->ceiling)
+        di->penalty = dc->ceiling;
+
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+                     now.tv_sec, now.tv_usec,
+                     di->type, namebuf, di->penalty);
+        }
+
+      /* If the penalty becomes under reuse,
+         call real event that we have been postponed. */
+      if (di->penalty < dc->reuse && di->damping == ON)
+        ospf6_damp_stop (di);
+
+      /* If the penalty becomes less than the half of the
+         reuse value, this damp info will be freed from reuse-list,
+         by assuming that it is considered to be stable enough already,
+         and there's no need to maintain flapping history for this. */
+      if (di->penalty <= dc->reuse / 2)
+        {
+          ospf6_damp_delete (di->type, &di->name);
+          di = next;
+          continue;
+        }
+
+      /* re-insert to the reuse-list */
+      ospf6_reuse_list_add (di);
+
+      di = next;
+    }
+
+  return 0;
+}
+
+static void
+ospf6_damp_event (damp_event_t event_type,
+                  u_short type, struct prefix *name,
+                  int (*event) (void *), void *target)
+{
+  time_t t_now, t_diff;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+  struct timeval now;
+
+  if (dc->enabled == OFF)
+    {
+      (*event) (target);
+      return;
+    }
+
+  di = ospf6_damp_lookup (type, name);
+  if (! di)
+    di = ospf6_damp_create (type, name);
+
+  t_now = time (NULL);
+
+  di->event = event;
+  di->target = target;
+  di->event_type = event_type;
+
+  if (! ospf6_reuse_list_lookup (di))
+    di->t_start = t_now;
+  else
+    {
+      ospf6_reuse_list_remove (di);
+
+      t_diff = t_now - di->t_updated;
+      di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff));
+    }
+
+  /* penalty only on down event */
+  if (event_type == event_down)
+    {
+      di->flap++;
+      di->penalty += dc->default_penalty;
+    }
+
+  /* limit penalty up to ceiling */
+  if (di->penalty > dc->ceiling)
+    di->penalty = dc->ceiling;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+                 now.tv_sec, now.tv_usec,
+                 di->type, namebuf, di->penalty);
+    }
+
+  /* if penalty < reuse, stop damping here */
+  if (di->penalty < dc->reuse && di->damping == ON)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, di->type, namebuf);
+        }
+      di->damping = OFF;
+    }
+
+  /* if event == up and if penalty >= suppress , start damping here */
+  if (di->event_type == event_up && di->penalty >= dc->suppress &&
+      di->damping == OFF)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, type, namebuf);
+        }
+      di->damping = ON;
+    }
+
+  /* execute event if we're not damping */
+  if (di->damping == OFF)
+    {
+      (*(di->event)) (di->target);
+      di->target_status = di->event_type;
+    }
+
+  /* if the penalty goes beyond suppress value, start damping */
+  if (di->penalty >= dc->suppress && di->damping == OFF)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, type, namebuf);
+        }
+      di->damping = ON;
+    }
+
+  /* update last-updated-time field */
+  di->t_updated = t_now;
+
+  /* Insert it into the reuse list */
+  ospf6_reuse_list_add (di);
+}
+
+void
+ospf6_damp_event_up (u_short type, struct prefix *name,
+                     int (*event) (void *), void *target)
+{
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  if (IS_OSPF6_DEBUG_DAMP)
+    zlog_info ("DAMP: Up   Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+  ospf6_damp_event (event_up, type, name, event, target);
+}
+
+void
+ospf6_damp_event_down (u_short type, struct prefix *name,
+                       int (*event) (void *), void *target)
+{
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  if (IS_OSPF6_DEBUG_DAMP)
+    zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+  ospf6_damp_event (event_down, type, name, event, target);
+}
+
+int
+ospf6_damp_debug_thread (struct thread *thread)
+{
+  int i;
+  struct ospf6_damp_info *di;
+  char buf[256];
+  time_t t_now;
+  struct timeval now;
+
+  for (i = 0; i < dc->reuse_list_size; i++)
+    {
+      for (di = dc->reuse_list_array[i]; di; di = di->next)
+        {
+          t_now = time (NULL);
+          gettimeofday (&now, NULL);
+          prefix2str (&di->name, buf, sizeof (buf));
+          zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u",
+                     now.tv_sec, now.tv_usec,
+                     (di->damping == ON ? 'D' : 'A'), buf,
+                     (u_int) (di->penalty *
+                              ospf6_damp_decay (t_now - di->t_updated)));
+        }
+    }
+  thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1);
+  return 0;
+}
+
+DEFUN (show_ipv6_ospf6_route_flapping,
+       show_ipv6_ospf6_route_flapping_cmd,
+       "show ipv6 ospf6 route flapping",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR)
+{
+  int i;
+  struct ospf6_damp_info *di;
+  char buf[256];
+  time_t t_now;
+
+  t_now = time (NULL);
+  vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE);
+
+  for (i = 0; i < dc->reuse_list_size; i++)
+    {
+      for (di = dc->reuse_list_array[i]; di; di = di->next)
+        {
+          prefix2str (&di->name, buf, sizeof (buf));
+          vty_out (vty, "%c %-32s %7u%s",
+                   (di->damping == ON ? 'D' : ' '), buf,
+                   (u_int) (di->penalty *
+                            ospf6_damp_decay (t_now - di->t_updated)),
+                   VTY_NEWLINE);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (flap_damping_route,
+       flap_damping_route_cmd,
+       "flap-damping route <0-4294967295> <0-4294967295> "
+                          "<0-4294967295> <0-4294967295>",
+       "enable flap dampening\n"
+       "enable route flap dampening\n"
+       "half-life in second\n"
+       "reuse value\n"
+       "suppress value\n"
+       "t-hold in second (maximum time that the target can be damped)\n"
+      )
+{
+  u_int half_life, reuse, suppress, t_hold;
+
+  if (argc)
+    {
+      half_life = (u_int) strtoul (argv[0], NULL, 10);
+      reuse     = (u_int) strtoul (argv[1], NULL, 10);
+      suppress  = (u_int) strtoul (argv[2], NULL, 10);
+      t_hold    = (u_int) strtoul (argv[3], NULL, 10);
+    }
+  else
+    {
+      half_life = (u_int) DEFAULT_HALF_LIFE;
+      reuse     = (u_int) DEFAULT_REUSE;
+      suppress  = (u_int) DEFAULT_SUPPRESS;
+      t_hold    = (u_int) DEFAULT_HALF_LIFE * 4;
+    }
+
+  if (reuse && suppress && reuse >= suppress)
+    {
+      vty_out (vty, "reuse value exceeded suppress value, failed%s\n",
+               VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (half_life && t_hold && half_life >= t_hold)
+    {
+      vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  ospf6_damp_init_config (half_life, reuse, suppress, t_hold);
+
+  if (ospf6_reuse_thread == NULL)
+    ospf6_reuse_thread =
+      thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_damp_config,
+       show_ipv6_ospf6_camp_config_cmd,
+       "show ipv6 ospf6 damp config",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+       "shows dampening configuration\n"
+      )
+{
+  int i;
+
+  vty_out (vty, "%10s %10s %10s %10s%s",
+           "Half life", "Suppress", "Reuse", "T-hold",
+           VTY_NEWLINE);
+  vty_out (vty, "%10u %10u %10u %10u%s",
+           dc->half_life, dc->suppress, dc->reuse, dc->t_hold,
+           VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE);
+  vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE);
+  vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE);
+  vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE);
+  vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE);
+
+  vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE);
+  for (i = 0; i < dc->decay_array_size; i++)
+    {
+      if (i % 10 == 0)
+        vty_out (vty, "  ");
+      vty_out (vty, " %f", dc->decay_array[i]);
+      if (i % 10 == 0)
+        vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "ReuseIndexArray(%d) =%s",
+           dc->reuse_index_array_size, VTY_NEWLINE);
+  for (i = 0; i < dc->reuse_index_array_size; i++)
+    {
+      if (i % 10 == 0)
+        vty_out (vty, "  ");
+      vty_out (vty, " %d", dc->reuse_index_array[i]);
+      if (i % 10 == 0)
+        vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_config_write (struct vty *vty)
+{
+  if (dc->enabled == ON)
+    {
+      vty_out (vty, " flap-damping route %u %u %u %u%s",
+               dc->half_life, dc->reuse, dc->suppress, dc->t_hold,
+               VTY_NEWLINE);
+    }
+}
+
+DEFUN (debug_ospf6_damp,
+       debug_ospf6_damp_cmd,
+       "debug ospf6 damp",
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  ospf6_damp_debug = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_damp,
+       no_debug_ospf6_damp_cmd,
+       "no debug ospf6 damp",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  ospf6_damp_debug = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_debug_ospf6_damp,
+       show_debug_ospf6_damp_cmd,
+       "show debugging ospf6 damp",
+       SHOW_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  vty_out (vty, "debugging ospf6 damp is ");
+  if (IS_OSPF6_DEBUG_DAMP)
+    vty_out (vty, "enabled.");
+  else
+    vty_out (vty, "disabled.");
+  vty_out (vty, "%s", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_init ()
+{
+  int i;
+  for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++)
+    damp_info_table[i] = route_table_init ();
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd);
+  install_element (OSPF6_NODE, &flap_damping_route_cmd);
+
+  install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_damp_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd);
+
+  thread_add_event (master, ospf6_damp_debug_thread, NULL, 0);
+}
+
+#endif /* HAVE_OSPF6_DAMP */
+
+
diff --git a/ospf6d/ospf6_damp.h b/ospf6d/ospf6_damp.h
new file mode 100644 (file)
index 0000000..19bdbc7
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002 
+ * 
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/*
+ * Flap Damping (target e.g. link/route)
+ */
+
+#define HAVE_OSPF6_DAMP
+
+typedef enum
+{
+  OFF,
+  ON,
+} onoff_t;
+
+typedef enum
+{
+  event_none,
+  event_up,
+  event_down,
+} damp_event_t;
+
+/* Structure maintained per target basis */
+struct ospf6_damp_info
+{
+  /* identifier to decide which target */
+  u_short type;
+  struct prefix name;
+
+  /* do we damping this info */
+  onoff_t damping;
+
+  u_int penalty;
+  u_int flap;
+  time_t t_start;   /* First flap (down event) time */
+  time_t t_updated; /* Last time the penalty was updated */
+
+  /* index and double-link for reuse list */
+  int                    index;
+  struct ospf6_damp_info *next;
+  struct ospf6_damp_info *prev;
+
+  /* the last event that we are avoiding */
+  int (*event) (void *target);
+  void *target;
+  damp_event_t event_type;
+  damp_event_t target_status;
+};
+
+#define OSPF6_DAMP_TYPE_ROUTE      0
+#define OSPF6_DAMP_TYPE_MAX        1
+
+/* Global Configuration Parameters */
+struct ospf6_damp_config
+{
+  /* is damping enabled ? */
+  onoff_t enabled;
+
+  /* configurable parameters */
+  u_int half_life;
+  u_int suppress;
+  u_int reuse;
+  u_int t_hold;                 /* Maximum hold down time */
+
+  /* Non configurable parameters */
+  u_int   delta_t;
+  u_int   delta_reuse;
+  u_int   default_penalty;
+  u_int   ceiling;              /* Max value a penalty can attain */
+  double  scale_factor;
+
+  int     decay_array_size;     /* Calculated using config parameters */
+  double *decay_array;          /* Storage for decay values */
+
+  int  reuse_index_array_size;  /* Size of reuse index array */
+  int *reuse_index_array;
+
+  int  reuse_list_size;         /* Number of reuse lists */
+  struct ospf6_damp_info **reuse_list_array;
+};
+
+int ospf6_damp_reuse_timer (struct thread *);
+void ospf6_damp_event_up   (u_short type, struct prefix *name,
+                           int (*exec_up)   (void *), void *target);
+void ospf6_damp_event_down (u_short type, struct prefix *name,
+                           int (*exec_down) (void *), void *target);
+
+void ospf6_damp_config_write (struct vty *);
+void ospf6_damp_init ();
+
diff --git a/ospf6d/ospf6_dbex.c b/ospf6d/ospf6_dbex.c
new file mode 100644 (file)
index 0000000..b10d9ae
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+/* check validity and put lsa in reqestlist if needed. */
+/* returns -1 if SeqNumMismatch required. */
+int
+ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
+                                    struct ospf6_neighbor *from)
+{
+  struct ospf6_lsa *received = NULL;
+  struct ospf6_lsa *have = NULL;
+
+  received = ospf6_lsa_summary_create
+    ((struct ospf6_lsa_header__ *) lsa_header);
+
+  /* case when received is AS-External though neighbor belongs stub area */
+  if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
+      ospf6_area_is_stub (from->ospf6_interface->area))
+    {
+      zlog_err ("DbDesc %s receive from %s", from->str, received->str);
+      zlog_err ("    E-bit mismatch: %s", received->str);
+      ospf6_lsa_delete (received);
+      return -1;
+    }
+
+  /* if already have newer database copy, check next LSA */
+  have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
+                            lsa_header->advrtr,
+                            ospf6_lsa_get_scope (lsa_header->type,
+                                                 from->ospf6_interface));
+  if (! have)
+    {
+      /* if we don't have database copy, add request */
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Have no database copy, Request");
+      ospf6_neighbor_request_add (received, from);
+    }
+  else if (have)
+    {
+      /* if database copy is less recent, add request */
+      if (ospf6_lsa_check_recent (received, have) < 0)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("Database copy less recent, Request");
+          ospf6_neighbor_request_add (received, from);
+        }
+    }
+
+  return 0;
+}
+
+/* Direct acknowledgement */
+static void
+ospf6_dbex_acknowledge_direct (struct ospf6_lsa *lsa,
+                               struct ospf6_neighbor *o6n)
+{
+  struct iovec directack[MAXIOVLIST];
+  assert (lsa);
+
+  if (IS_OSPF6_DUMP_DBEX)
+    zlog_info ("DBEX: [%s:%s] direct ack %s ",
+               o6n->str, o6n->ospf6_interface->interface->name,
+               lsa->str);
+
+  /* clear pointers to fragments of packet for direct acknowledgement */
+  iov_clear (directack, MAXIOVLIST);
+
+  /* set pointer of LSA to send */
+  OSPF6_MESSAGE_ATTACH (directack, lsa->header,
+                        sizeof (struct ospf6_lsa_header));
+
+  /* age update and add InfTransDelay */
+  ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+
+  /* send unicast packet to neighbor's ipaddress */
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, directack, &o6n->hisaddr,
+                      o6n->ospf6_interface->if_id);
+}
+
+/* Delayed  acknowledgement */
+void
+ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
+                                struct ospf6_interface *o6i)
+{
+  assert (o6i);
+
+  if (IS_OSPF6_DUMP_DBEX)
+    zlog_info ("DBEX: [%s] delayed ack %s", o6i->interface->name, lsa->str);
+
+  /* attach delayed acknowledge list */
+  ospf6_lsa_age_current (lsa);
+  ospf6_interface_delayed_ack_add (lsa, o6i);
+
+  /* if not yet, schedule delayed acknowledge RxmtInterval later.
+     timers should be *less than* RxmtInterval
+     or needless retrans will ensue */
+  if (o6i->thread_send_lsack_delayed == NULL)
+    o6i->thread_send_lsack_delayed
+      = thread_add_timer (master, ospf6_send_lsack_delayed,
+                          o6i, o6i->rxmt_interval - 1);
+
+  return;
+}
+
+/* RFC2328 section 13 (4):
+   if MaxAge LSA and if we have no instance, and no neighbor
+   is in states Exchange or Loading */
+/* returns 1 if match this case, else returns 0 */
+static int
+ospf6_dbex_is_maxage_to_be_dropped (struct ospf6_lsa *received,
+                                    struct ospf6_neighbor *from)
+{
+  int count;
+
+  if (! IS_LSA_MAXAGE (received))
+    return 0;
+
+  if (ospf6_lsdb_lookup (received->header->type, received->header->id,
+                         received->header->adv_router,
+                         ospf6_lsa_get_scope (received->header->type,
+                                              from->ospf6_interface)))
+    return 0;
+
+  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (received->header->type)))
+    {
+      count = 0;
+      (*from->ospf6_interface->foreach_nei)
+        (from->ospf6_interface, &count, NBS_EXCHANGE, ospf6_count_state);
+      (*from->ospf6_interface->foreach_nei)
+        (from->ospf6_interface, &count, NBS_LOADING, ospf6_count_state);
+      if (count)
+        return 0;
+    }
+  else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (received->header->type)))
+    {
+      count = 0;
+      (*from->ospf6_interface->area->foreach_nei)
+         (from->ospf6_interface->area, &count, NBS_EXCHANGE, ospf6_count_state);
+      (*from->ospf6_interface->area->foreach_nei)
+         (from->ospf6_interface->area, &count, NBS_LOADING, ospf6_count_state);
+      if (count)
+        return 0;
+    }
+  else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (received->header->type)))
+    {
+      count = 0;
+      (*from->ospf6_interface->area->ospf6->foreach_nei)
+         (from->ospf6_interface->area->ospf6, &count, NBS_EXCHANGE,
+          ospf6_count_state);
+      (*from->ospf6_interface->area->ospf6->foreach_nei)
+         (from->ospf6_interface->area->ospf6, &count, NBS_LOADING,
+          ospf6_count_state);
+      if (count)
+        return 0;
+    }
+
+  return 1;
+}
+
+static void
+ospf6_dbex_remove_retrans (void *arg, int val, void *obj)
+{
+  struct ospf6_lsa *rem;
+  struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
+  struct ospf6_lsa *lsa = (struct ospf6_lsa *) arg;
+
+  rem = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+                                lsa->header->adv_router, nei->retrans_list);
+  if (rem)
+    {
+      ospf6_neighbor_retrans_remove (rem, nei);
+      ospf6_maxage_remover ();
+    }
+}
+
+void
+ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa)
+{
+  struct ospf6_interface *o6i;
+  struct ospf6_area *o6a;
+
+  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa->header->type)))
+    {
+      o6i = lsa->scope;
+      (*o6i->foreach_nei) (o6i, lsa, 0, ospf6_dbex_remove_retrans);
+    }
+  else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa->header->type)))
+    {
+      o6a = lsa->scope;
+      (*o6a->foreach_nei) (o6a, lsa, 0, ospf6_dbex_remove_retrans);
+    }
+  else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa->header->type)))
+    {
+      (*ospf6->foreach_nei) (ospf6, lsa, 0, ospf6_dbex_remove_retrans);
+    }
+}
+
+/* RFC2328 section 13 */
+void
+ospf6_dbex_receive_lsa (struct ospf6_lsa_header *lsa_header,
+                        struct ospf6_neighbor *from)
+{
+  struct ospf6_lsa *received, *have, *rem;
+  struct timeval now;
+  int ismore_recent, acktype;
+  unsigned short cksum;
+  struct ospf6_lsa_slot *slot;
+
+  received = have = (struct ospf6_lsa *)NULL;
+  ismore_recent = -1;
+  recent_reason = "no instance";
+
+  zlog_info ("Receive LSA (header -> %p)", lsa_header);
+
+  /* make lsa structure for received lsa */
+  received = ospf6_lsa_create (lsa_header);
+
+  /* set LSA scope */
+  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
+    received->scope = from->ospf6_interface;
+  else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa_header->type)))
+    received->scope = from->ospf6_interface->area;
+  else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa_header->type)))
+    received->scope = from->ospf6_interface->area->ospf6;
+
+  /* (1) LSA Checksum */
+  cksum = ntohs (lsa_header->checksum);
+  if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
+    {
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: received %s from %s%%%s"
+                   ": wrong checksum, drop",
+                   received->str, from->str,
+                   from->ospf6_interface->interface->name);
+      ospf6_lsa_delete (received);
+      return;
+    }
+
+  /* (3) Ebit Missmatch: AS-External-LSA */
+  if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
+      ospf6_area_is_stub (from->ospf6_interface->area))
+    {
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: received %s from %s%%%s"
+                   ": E-bit mismatch, drop",
+                   received->str, from->str,
+                   from->ospf6_interface->interface->name);
+      ospf6_lsa_delete (received);
+      return;
+    }
+
+  /* (4) if MaxAge LSA and if we have no instance, and no neighbor
+         is in states Exchange or Loading */
+  if (ospf6_dbex_is_maxage_to_be_dropped (received, from))
+    {
+      /* log */
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: received %s from %s%%%s"
+                   ": MaxAge, no instance, no neighbor exchange, drop",
+                   received->str, from->str,
+                   from->ospf6_interface->interface->name);
+
+      /* a) Acknowledge back to neighbor (13.5) */
+        /* Direct Acknowledgement */
+      ospf6_dbex_acknowledge_direct (received, from);
+
+      /* b) Discard */
+      ospf6_lsa_delete (received);
+      return;
+    }
+
+  /* (5) */
+  /* lookup the same database copy in lsdb */
+  have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
+                            lsa_header->advrtr,
+                            ospf6_lsa_get_scope (lsa_header->type,
+                                                 from->ospf6_interface));
+  if (have)
+    {
+      ismore_recent = ospf6_lsa_check_recent (received, have);
+      if (ntohl (received->header->seqnum) == ntohl (have->header->seqnum))
+        SET_FLAG (received->flag, OSPF6_LSA_FLAG_DUPLICATE);
+    }
+
+  /* if no database copy or received is more recent */
+  if (!have || ismore_recent < 0)
+    {
+      /* in case we have no database copy */
+      ismore_recent = -1;
+
+      /* (a) MinLSArrival check */
+      gettimeofday (&now, (struct timezone *)NULL);
+      if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL)
+        {
+          //if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d "
+                       "within MinLSArrival, drop: %ld.%06ld",
+                       from->str, received->str,
+                       ntohl (received->header->seqnum),
+                       ntohs (received->header->age),
+                       now.tv_sec, now.tv_usec);
+
+          /* this will do free this lsa */
+          ospf6_lsa_delete (received);
+          return;   /* examin next lsa */
+        }
+
+      //if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d: "
+                   "%ld.%06ld",
+                   from->str, received->str,
+                   ntohl (received->header->seqnum),
+                   ntohs (received->header->age),
+                   now.tv_sec, now.tv_usec);
+
+      /* (b) immediately flood */
+      ospf6_dbex_flood (received, from);
+
+#if 0
+      /* Because New LSDB do not permit two LSA having the same identifier
+         exist in a LSDB list, above ospf6_dbex_flood() will remove
+         the old instance automatically. thus bellow is not needed. */
+      /* (c) remove database copy from all neighbor's retranslist */
+      if (have)
+        ospf6_dbex_remove_from_all_retrans_list (have);
+#endif
+
+      /* (d), installing lsdb, which may cause routing
+              table calculation (replacing database copy) */
+      ospf6_lsdb_install (received);
+
+      /* (e) possibly acknowledge */
+      acktype = ack_type (received, ismore_recent, from);
+      if (acktype == DIRECT_ACK)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Direct Ack to %s", from->str);
+          ospf6_dbex_acknowledge_direct (received, from);
+        }
+      else if (acktype == DELAYED_ACK)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Delayed Ack to %s", from->str);
+          ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
+        }
+      else
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: No Ack to %s", from->str);
+        }
+
+      /* (f) */
+      /* Self Originated LSA, section 13.4 */
+      if (received->lsa_hdr->lsh_advrtr == ospf6->router_id
+          && (! have || ismore_recent < 0))
+        {
+          /* we're going to make new lsa or to flush this LSA. */
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Self-originated LSA %s from %s:%s",
+                       received->str, from->str,
+                       from->ospf6_interface->interface->name);
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: %s: Make new one/Flush", received->str);
+
+          SET_FLAG (received->flag, OSPF6_LSA_FLAG_REFRESH);
+          slot = ospf6_lsa_slot_get (received->header->type);
+          if (slot && slot->func_refresh)
+            {
+              (*slot->func_refresh) (received);
+              return;
+            }
+
+          zlog_warn ("Can't Refresh LSA: Unknown type: %#x, Flush",
+                     ntohs (received->header->type));
+          ospf6_lsa_premature_aging (received);
+          return;
+        }
+    }
+  else if (ospf6_lsdb_lookup_lsdb (received->header->type,
+                                   received->header->id,
+                                   received->header->adv_router,
+                                   from->request_list))
+    /* (6) if there is instance on sending neighbor's request list */
+    {
+      /* if no database copy, should go above state (5) */
+      assert (have);
+
+      zlog_warn ("DBEX: [%s:%s] received LSA %s is not newer,"
+                 " and is on his requestlist: Generate BadLSReq",
+                 from->str, from->ospf6_interface->interface->name,
+                 received->str);
+
+      /* BadLSReq */
+      thread_add_event (master, bad_lsreq, from, 0);
+
+      ospf6_lsa_delete (received);
+    }
+  else if (ismore_recent == 0) /* (7) if neither is more recent */
+    {
+      /* (a) if on retranslist, Treat this LSA as an Ack: Implied Ack */
+      rem = ospf6_lsdb_lookup_lsdb (received->header->type,
+                                    received->header->id,
+                                    received->header->adv_router,
+                                    from->retrans_list);
+      if (rem)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Implied Ack from %s, (remove retrans)",
+                       from->str);
+          SET_FLAG (received->flag, OSPF6_LSA_FLAG_IMPLIEDACK);
+          ospf6_neighbor_retrans_remove (rem, from);
+        }
+
+      /* (b) possibly acknowledge */
+      acktype = ack_type (received, ismore_recent, from);
+      if (acktype == DIRECT_ACK)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Direct Ack to %s", from->str);
+          ospf6_dbex_acknowledge_direct (received, from);
+        }
+      else if (acktype == DELAYED_ACK)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Delayed Ack to %s", from->str);
+          ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
+        }
+      else
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: No Ack to %s", from->str);
+        }
+      ospf6_lsa_delete (received);
+    }
+  else /* (8) previous database copy is more recent */
+    {
+      /* If Seqnumber Wrapping, simply discard
+         Otherwise, Send database copy of this LSA to this neighbor */
+      if (! IS_LSA_MAXAGE (received) ||
+          received->lsa_hdr->lsh_seqnum != MAX_SEQUENCE_NUMBER)
+        {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: database is more recent: send back to %s",
+                       from->str);
+          ospf6_send_lsupdate_direct (have, from);
+        }
+      ospf6_lsa_delete (received);
+    }
+}
+
+/* RFC2328: Table 19: Sending link state acknowledgements. */
+int 
+ack_type (struct ospf6_lsa *newp, int ismore_recent,
+          struct ospf6_neighbor *from)
+{
+  struct ospf6_interface *ospf6_interface;
+  struct ospf6_lsa *have;
+  int count;
+
+  assert (from && from->ospf6_interface);
+  ospf6_interface = from->ospf6_interface;
+
+  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
+    return NO_ACK;
+
+  if (ismore_recent < 0)
+    {
+      if (ospf6_interface->state != IFS_BDR)
+        return DELAYED_ACK;
+
+      if (ospf6_interface->dr == from->router_id)
+        return DELAYED_ACK;
+      return NO_ACK;
+    }
+
+  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+      CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+    {
+      if (ospf6_interface->state != IFS_BDR)
+        return NO_ACK;
+
+      if (ospf6_interface->dr == from->router_id)
+        return DELAYED_ACK;
+
+      return NO_ACK;
+    }
+
+  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+      ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+    return DIRECT_ACK;
+
+  have = ospf6_lsdb_lookup (newp->header->type, newp->header->id,
+                            newp->header->adv_router,
+                            ospf6_lsa_get_scope (newp->header->type,
+                                                 from->ospf6_interface));
+
+  count = 0;
+  ospf6->foreach_nei (ospf6, &count, NBS_EXCHANGE, ospf6_count_state);
+  ospf6->foreach_nei (ospf6, &count, NBS_LOADING, ospf6_count_state);
+
+  if (IS_LSA_MAXAGE (newp) && have == NULL && count == 0)
+    return DIRECT_ACK;
+  return NO_ACK;
+}
+
+static void
+ospf6_dbex_flood_linklocal (struct ospf6_lsa *lsa, struct ospf6_interface *o6i,
+                            struct ospf6_neighbor *from)
+{
+  struct ospf6_neighbor *o6n = (struct ospf6_neighbor *) NULL;
+  int ismore_recent, addretrans = 0;
+  listnode n;
+  struct ospf6_lsa *req;
+
+  /* (1) for each neighbor */
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+
+      /* (a) */
+      if (o6n->state < NBS_EXCHANGE)
+        continue;  /* examin next neighbor */
+
+      /* (b) */
+      if (o6n->state == NBS_EXCHANGE
+          || o6n->state == NBS_LOADING)
+        {
+          req = ospf6_lsdb_lookup_lsdb (lsa->header->type,
+                                        lsa->header->id,
+                                        lsa->header->adv_router,
+                                        o6n->request_list);
+          if (req)
+            {
+              ismore_recent = ospf6_lsa_check_recent (lsa, req);
+              if (ismore_recent > 0)
+                {
+                  continue; /* examin next neighbor */
+                }
+              else if (ismore_recent == 0)
+                {
+                  ospf6_neighbor_request_remove (req, o6n);
+                  continue; /* examin next neighbor */
+                }
+              else /* ismore_recent < 0 (the new LSA is more recent) */
+                {
+                  ospf6_neighbor_request_remove (req, o6n);
+                }
+            }
+        }
+
+      /* (c) */
+      if (from && from->router_id == o6n->router_id)
+        continue; /* examin next neighbor */
+
+      /* (d) add retranslist */
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: schedule flooding [%s:%s]: %s",
+                   o6n->str, o6n->ospf6_interface->interface->name,
+                   lsa->str);
+      ospf6_neighbor_retrans_add (lsa, o6n);
+      addretrans++;
+      if (o6n->send_update == (struct thread *) NULL)
+        o6n->send_update =
+          thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
+                            o6n->ospf6_interface->rxmt_interval);
+    }
+
+  /* (2) */
+  if (addretrans == 0)
+    return; /* examin next interface */
+
+  if (from && from->ospf6_interface == o6i)
+    {
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: flood back %s to %s",
+                   lsa->str, o6i->interface->name);
+      /* note occurence of floodback */
+      SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_FLOODBACK);
+    }
+
+  /* (3) */
+  if (from && from->ospf6_interface == o6i)
+    {
+      /* if from DR or BDR, don't need to flood this interface */
+      if (from->router_id == from->ospf6_interface->dr ||
+          from->router_id == from->ospf6_interface->bdr)
+        return; /* examin next interface */
+    }
+
+  /* (4) if I'm BDR, DR will flood this interface */
+  if (from && from->ospf6_interface == o6i
+      && o6i->state == IFS_BDR)
+    return; /* examin next interface */
+
+  if (IS_OSPF6_DUMP_DBEX)
+    zlog_info ("Flood to interface %s", o6i->interface->name);
+
+  /* (5) send LinkState Update */
+  ospf6_send_lsupdate_flood (lsa, o6i);
+
+  return;
+}
+
+/* RFC2328 section 13.3 */
+static void
+ospf6_dbex_flood_area (struct ospf6_lsa *lsa, struct ospf6_area *area,
+                       struct ospf6_neighbor *from)
+{
+  listnode n;
+  struct ospf6_interface *ospf6_interface;
+
+  assert (lsa && lsa->lsa_hdr && area);
+
+  /* for each eligible ospf_ifs */
+  for (n = listhead (area->if_list); n; nextnode (n))
+    {
+      ospf6_interface = (struct ospf6_interface *) getdata (n);
+      ospf6_dbex_flood_linklocal (lsa, ospf6_interface, from);
+    }
+}
+
+static void
+ospf6_dbex_flood_as (struct ospf6_lsa *lsa, struct ospf6 *ospf6,
+                     struct ospf6_neighbor *from)
+{
+  listnode n;
+  struct ospf6_area *o6a;
+
+  assert (lsa && lsa->lsa_hdr && ospf6);
+
+  /* for each attached area */
+  for (n = listhead (ospf6->area_list); n; nextnode (n))
+    {
+      o6a = (struct ospf6_area *) getdata (n);
+      ospf6_dbex_flood_area (lsa, o6a, from);
+    }
+}
+
+/* flood ospf6_lsa within appropriate scope */
+void
+ospf6_dbex_flood (struct ospf6_lsa *lsa, struct ospf6_neighbor *from)
+{
+  struct ospf6_area *o6a;
+  struct ospf6_interface *o6i;
+  struct ospf6 *o6;
+  struct ospf6_lsa_header *lsa_header;
+
+  lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
+
+  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa_header->type)))
+    {
+      o6i = (struct ospf6_interface *) lsa->scope;
+      assert (o6i);
+
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Flood Linklocal: %s", o6i->interface->name);
+      ospf6_dbex_flood_linklocal (lsa, o6i, from);
+    }
+  else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa_header->type)))
+    {
+      o6a = (struct ospf6_area *) lsa->scope;
+      assert (o6a);
+
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Flood Area: %s", o6a->str);
+      ospf6_dbex_flood_area (lsa, o6a, from);
+    }
+  else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa_header->type)))
+    {
+      o6 = (struct ospf6 *) lsa->scope;
+      assert (o6);
+
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Flood AS");
+      ospf6_dbex_flood_as (lsa, o6, from);
+    }
+  else
+    {
+      zlog_warn ("Can't Flood %s: scope unknown", lsa->str);
+    }
+}
+
+
diff --git a/ospf6d/ospf6_dbex.h b/ospf6d/ospf6_dbex.h
new file mode 100644 (file)
index 0000000..fbb7dc5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_DBEX_H
+#define OSPF6_DBEX_H
+
+/* for ack_type() */
+#define NO_ACK       0
+#define DELAYED_ACK  1
+#define DIRECT_ACK   2
+
+/* Function Prototypes */
+void
+ospf6_add_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *);
+void
+ospf6_remove_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *);
+void ospf6_lsa_delayed_ack_remove_all (struct ospf6_lsa *lsa);
+
+void ospf6_dbex_prepare_summary (struct ospf6_neighbor *);
+
+int
+ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
+                                    struct ospf6_neighbor *from);
+
+void
+ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
+                                struct ospf6_interface *o6i);
+
+void
+ospf6_dbex_receive_lsa (struct ospf6_lsa_header *,
+                        struct ospf6_neighbor *);
+
+int ack_type (struct ospf6_lsa *, int, struct ospf6_neighbor *);
+
+void ospf6_dbex_flood (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa);
+
+#endif /* OSPF6_DBEX_H */
+
diff --git a/ospf6d/ospf6_dump.c b/ospf6d/ospf6_dump.c
new file mode 100644 (file)
index 0000000..e950ec8
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Logging function
+ * Copyright (C) 1999-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* Include other stuffs */
+#include "log.h"
+#include "command.h"
+#include "ospf6_dump.h"
+
+#define CMD_SHOW    0
+#define CMD_ENABLE  1
+#define CMD_DISABLE 2
+#define CMD_MAX     3
+
+struct ospf6_dump
+{
+  struct cmd_element cmd[CMD_MAX];
+  char *name;
+  int config;
+};
+
+#define DUMP_MAX 512
+struct ospf6_dump *ospf6_dump[DUMP_MAX];
+unsigned int dump_size = 0;
+
+static int
+ospf6_dump_index (struct cmd_element *cmd, int command)
+{
+  int i;
+
+  for (i = 0; i < DUMP_MAX; i++)
+    {
+      if (cmd != &ospf6_dump[i]->cmd[command])
+        continue;
+      break;
+    }
+
+  if (i == DUMP_MAX)
+    return -1;
+  return i;
+}
+
+int
+ospf6_dump_is_on (int index)
+{
+  if (ospf6_dump[index] == NULL)
+    return 0;
+
+  return ospf6_dump[index]->config;
+}
+
+int
+ospf6_dump_show (struct cmd_element *cmd,
+                 struct vty *vty, int argc, char **argv)
+{
+  int index;
+
+  index = ospf6_dump_index (cmd, CMD_SHOW);
+  assert (index != -1);
+
+  vty_out (vty, "  %-16s: %s%s", ospf6_dump[index]->name,
+           (ospf6_dump[index]->config ? "on" : "off"),
+           VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_enable (struct cmd_element *cmd,
+                   struct vty *vty, int argc, char **argv)
+{
+  int index;
+
+  index = ospf6_dump_index (cmd, CMD_ENABLE);
+  assert (index != -1);
+
+  ospf6_dump[index]->config = 1;
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_disable (struct cmd_element *cmd,
+                    struct vty *vty, int argc, char **argv)
+{
+  int index;
+
+  index = ospf6_dump_index (cmd, CMD_DISABLE);
+  assert (index != -1);
+
+  ospf6_dump[index]->config = 0;
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_dump_install (char *name, char *help)
+{
+  struct cmd_element *cmd;
+  char string[256];
+  char helpstring[256];
+
+  if (dump_size + 1 >= DUMP_MAX)
+    return -1;
+
+  ospf6_dump[dump_size] = malloc (sizeof (struct ospf6_dump));
+  if (ospf6_dump[dump_size] == NULL)
+    return -1;
+  memset (ospf6_dump[dump_size], 0, sizeof (struct ospf6_dump));
+
+  ospf6_dump[dump_size]->name = strdup (name);
+
+  cmd = &ospf6_dump[dump_size]->cmd[CMD_SHOW];
+  snprintf (string, sizeof (string), "show debugging ospf6 %s", name);
+  snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
+            SHOW_STR, DEBUG_STR, OSPF6_STR, help);
+  memset (cmd, 0, sizeof (struct cmd_element));
+  cmd->string = strdup (string);
+  cmd->func = ospf6_dump_show;
+  cmd->doc = strdup (helpstring);
+  install_element (VIEW_NODE, cmd);
+  install_element (ENABLE_NODE, cmd);
+
+  cmd = &ospf6_dump[dump_size]->cmd[CMD_ENABLE];
+  snprintf (string, sizeof (string), "debug ospf6 %s", name);
+  snprintf (helpstring, sizeof (helpstring), "%s%s%s",
+            DEBUG_STR, OSPF6_STR, help);
+  memset (cmd, 0, sizeof (struct cmd_element));
+  cmd->string = strdup (string);
+  cmd->func = ospf6_dump_enable;
+  cmd->doc = strdup (helpstring);
+  install_element (CONFIG_NODE, cmd);
+
+  cmd = &ospf6_dump[dump_size]->cmd[CMD_DISABLE];
+  snprintf (string, sizeof (string), "no debug ospf6 %s", name);
+  snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
+            NO_STR, DEBUG_STR, OSPF6_STR, help);
+  memset (cmd, 0, sizeof (struct cmd_element));
+  cmd->string = strdup (string);
+  cmd->func = ospf6_dump_disable;
+  cmd->doc = strdup (helpstring);
+  install_element (CONFIG_NODE, cmd);
+
+  return dump_size++;
+}
+
+DEFUN(show_debug_ospf6,
+      show_debug_ospf6_cmd,
+      "show debugging ospf6",
+      SHOW_STR
+      DEBUG_STR
+      OSPF6_STR)
+{
+  int i;
+
+  vty_out (vty, "OSPF6 debugging status:%s", VTY_NEWLINE);
+
+  for (i = 0; i < DUMP_MAX; i++)
+    {
+      if (ospf6_dump[i] == NULL)
+        continue;
+      ospf6_dump_show (&ospf6_dump[i]->cmd[CMD_SHOW], vty, 0, NULL);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ospf6_all,
+       debug_ospf6_all_cmd,
+       "debug ospf6 all",
+       DEBUG_STR
+       OSPF6_STR
+       "Turn on ALL OSPFv3 debugging\n")
+{
+  int i;
+
+  for (i = 0; i < DUMP_MAX; i++)
+    {
+      if (ospf6_dump[i] == NULL)
+        continue;
+      ospf6_dump_enable (&ospf6_dump[i]->cmd[CMD_ENABLE], vty, 0, NULL);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_all,
+       no_debug_ospf6_all_cmd,
+       "no debug ospf6 all",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Turn off ALL OSPFv3 debugging\n")
+{
+  int i;
+
+  for (i = 0; i < DUMP_MAX; i++)
+    {
+      if (ospf6_dump[i] == NULL)
+        continue;
+      ospf6_dump_disable (&ospf6_dump[i]->cmd[CMD_DISABLE], vty, 0, NULL);
+    }
+
+  return CMD_SUCCESS;
+}
+
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  ""
+};
+
+int
+ospf6_dump_config_write (struct vty *vty)
+{
+  int i;
+
+  for (i = 0; i < dump_size; i++)
+    {
+      if (ospf6_dump[i] == NULL)
+        continue;
+
+      if (ospf6_dump[i]->config == 0)
+        continue;
+
+      vty_out (vty, "debug ospf6 %s%s", ospf6_dump[i]->name, VTY_NEWLINE);
+    }
+
+  vty_out (vty, "!%s", VTY_NEWLINE);
+  return 0;
+}
+
+char dump_index[OSPF6_DUMP_MAX];
+
+void
+ospf6_dump_init ()
+{
+  memset (ospf6_dump, 0, sizeof (ospf6_dump));
+
+  install_node (&debug_node, ospf6_dump_config_write);
+
+  install_element (VIEW_NODE,   &show_debug_ospf6_cmd);
+  install_element (ENABLE_NODE, &show_debug_ospf6_cmd);
+
+  install_element (CONFIG_NODE, &debug_ospf6_all_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd);
+
+  /* bellow is for backward compatibility
+     should be moved to each modules */
+
+#define MESSAGE_STR "OSPFv3 Messages\n"
+
+  dump_index[OSPF6_DUMP_HELLO] =
+    ospf6_dump_install ("message hello",
+                        MESSAGE_STR "Hello\n");
+  dump_index[OSPF6_DUMP_DBDESC] =
+    ospf6_dump_install ("message dbdesc",
+                        MESSAGE_STR "Database Description\n");
+  dump_index[OSPF6_DUMP_LSREQ] =
+    ospf6_dump_install ("message lsreq",
+                        MESSAGE_STR "Link State Request\n");
+  dump_index[OSPF6_DUMP_LSUPDATE] =
+    ospf6_dump_install ("message lsupdate",
+                        MESSAGE_STR "Link State Update\n");
+  dump_index[OSPF6_DUMP_LSACK] =
+    ospf6_dump_install ("message lsack",
+                        MESSAGE_STR "Link State Acknowledge\n");
+  dump_index[OSPF6_DUMP_NEIGHBOR] =
+    ospf6_dump_install ("neighbor", "Neighbors\n");
+  dump_index[OSPF6_DUMP_INTERFACE] =
+    ospf6_dump_install ("interface", "Interfaces\n");
+  dump_index[OSPF6_DUMP_LSA] =
+    ospf6_dump_install ("lsa", "Link State Advertisement\n");
+  dump_index[OSPF6_DUMP_ZEBRA] =
+    ospf6_dump_install ("zebra", "Communication with zebra\n");
+  dump_index[OSPF6_DUMP_CONFIG] =
+    ospf6_dump_install ("config", "Configuration Changes\n");
+  dump_index[OSPF6_DUMP_DBEX] =
+    ospf6_dump_install ("dbex", "Database Exchange/Flooding\n");
+  dump_index[OSPF6_DUMP_SPF] =
+    ospf6_dump_install ("spf", "SPF Calculation\n");
+  dump_index[OSPF6_DUMP_ROUTE] =
+    ospf6_dump_install ("route", "Route Calculation\n");
+  dump_index[OSPF6_DUMP_LSDB] =
+    ospf6_dump_install ("lsdb", "Link State Database\n");
+  dump_index[OSPF6_DUMP_REDISTRIBUTE] =
+    ospf6_dump_install ("redistribute",
+                        "Route Exchange with other protocols\n");
+  dump_index[OSPF6_DUMP_HOOK] =
+    ospf6_dump_install ("hook", "Hooks\n");
+  dump_index[OSPF6_DUMP_ASBR] =
+    ospf6_dump_install ("asbr", "AS Boundary Router function\n");
+  dump_index[OSPF6_DUMP_PREFIX] =
+    ospf6_dump_install ("prefix", "Prefix\n");
+}
+
+
diff --git a/ospf6d/ospf6_dump.h b/ospf6d/ospf6_dump.h
new file mode 100644 (file)
index 0000000..18a6e46
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Logging function
+ * Copyright (C) 1999-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_DUMP_H
+#define OSPF6_DUMP_H
+
+enum ospf6_dump_type
+{
+  OSPF6_DUMP_HELLO,
+  OSPF6_DUMP_DBDESC,
+  OSPF6_DUMP_LSREQ,
+  OSPF6_DUMP_LSUPDATE,
+  OSPF6_DUMP_LSACK,
+  OSPF6_DUMP_NEIGHBOR,
+  OSPF6_DUMP_INTERFACE,
+  OSPF6_DUMP_AREA,
+  OSPF6_DUMP_LSA,
+  OSPF6_DUMP_ZEBRA,
+  OSPF6_DUMP_CONFIG,
+  OSPF6_DUMP_DBEX,
+  OSPF6_DUMP_SPF,
+  OSPF6_DUMP_ROUTE,
+  OSPF6_DUMP_LSDB,
+  OSPF6_DUMP_REDISTRIBUTE,
+  OSPF6_DUMP_HOOK,
+  OSPF6_DUMP_ASBR,
+  OSPF6_DUMP_PREFIX,
+  OSPF6_DUMP_ABR,
+  OSPF6_DUMP_MAX
+};
+
+#define IS_OSPF6_DUMP_HELLO \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HELLO]))
+#define IS_OSPF6_DUMP_DBDESC \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBDESC]))
+#define IS_OSPF6_DUMP_LSREQ \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSREQ]))
+#define IS_OSPF6_DUMP_LSUPDATE \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSUPDATE]))
+#define IS_OSPF6_DUMP_LSACK \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSACK]))
+#define IS_OSPF6_DUMP_NEIGHBOR \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_NEIGHBOR]))
+#define IS_OSPF6_DUMP_INTERFACE \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_INTERFACE]))
+#define IS_OSPF6_DUMP_LSA \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSA]))
+#define IS_OSPF6_DUMP_ZEBRA \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ZEBRA]))
+#define IS_OSPF6_DUMP_CONFIG \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_CONFIG]))
+#define IS_OSPF6_DUMP_DBEX \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBEX]))
+#define IS_OSPF6_DUMP_SPF \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_SPF]))
+#define IS_OSPF6_DUMP_ROUTE \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ROUTE]))
+#define IS_OSPF6_DUMP_LSDB \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSDB]))
+#define IS_OSPF6_DUMP_REDISTRIBUTE \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_REDISTRIBUTE]))
+#define IS_OSPF6_DUMP_HOOK \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HOOK]))
+#define IS_OSPF6_DUMP_ASBR \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ASBR]))
+#define IS_OSPF6_DUMP_PREFIX \
+  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_PREFIX]))
+
+extern char dump_index[OSPF6_DUMP_MAX];
+
+void ospf6_dump_init ();
+int ospf6_dump_is_on (int index);
+int ospf6_dump_install (char *name, char *help);
+
+#endif /* OSPF6_DUMP_H */
+
diff --git a/ospf6d/ospf6_hook.c b/ospf6d/ospf6_hook.c
new file mode 100644 (file)
index 0000000..fc9e185
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+#include "ospf6_hook.h"
+
+struct ospf6_hook_master neighbor_hook;
+struct ospf6_hook_master interface_hook;
+struct ospf6_hook_master area_hook;
+struct ospf6_hook_master top_hook;
+struct ospf6_hook_master database_hook;
+struct ospf6_hook_master intra_topology_hook;
+struct ospf6_hook_master inter_topology_hook;
+struct ospf6_hook_master route_hook;
+struct ospf6_hook_master redistribute_hook;
+
+static struct ospf6_hook *
+ospf6_hook_create ()
+{
+  struct ospf6_hook *new;
+  new = XMALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_hook));
+  if (new == NULL)
+    return NULL;
+  memset (new, 0, sizeof (struct ospf6_hook));
+  return new;
+}
+
+static void
+ospf6_hook_delete (struct ospf6_hook *hook)
+{
+  XFREE (MTYPE_OSPF6_OTHER, hook);
+}
+
+static int
+ospf6_hook_issame (struct ospf6_hook *hook1, struct ospf6_hook *hook2)
+{
+  if (hook1->name && hook2->name &&
+      strcmp (hook1->name, hook2->name) != 0)
+    return 0;
+  if (hook1->hook_add != hook2->hook_add)
+    return 0;
+  if (hook1->hook_change != hook2->hook_change)
+    return 0;
+  if (hook1->hook_remove != hook2->hook_remove)
+    return 0;
+  return 1;
+}
+
+void
+ospf6_hook_register (struct ospf6_hook *hook,
+                     struct ospf6_hook_master *master)
+{
+  struct ospf6_hook *new;
+
+  new = ospf6_hook_create ();
+
+  if (hook->name)
+    new->name = strdup (hook->name);
+  new->hook_add = hook->hook_add;
+  new->hook_change = hook->hook_change;
+  new->hook_remove = hook->hook_remove;
+
+  new->prev = master->tail;
+  if (master->tail)
+    master->tail->next = new;
+
+  master->tail = new;
+  if (! master->head)
+    master->head = new;
+
+  master->count++;
+
+  if (IS_OSPF6_DUMP_HOOK)
+    {
+      zlog_info ("HOOK: Register hook%s%s%s%s",
+                 (hook->name ? " " : ""),
+                 (hook->name ? hook->name : ""),
+                 (master->name ? " to " : ""),
+                 (master->name ? master->name : ""));
+    }
+}
+
+void
+ospf6_hook_unregister (struct ospf6_hook *req,
+                       struct ospf6_hook_master *master)
+{
+  struct ospf6_hook *hook;
+
+  for (hook = master->head; hook; hook = hook->next)
+    {
+      if (ospf6_hook_issame (hook, req))
+        break;
+    }
+  if (! hook)
+    return;
+
+  if (hook->prev)
+    hook->prev->next = hook->next;
+  if (hook->next)
+    hook->next->prev = hook->prev;
+  if (master->head == hook)
+    master->head = hook->next;
+  if (master->tail == hook)
+    master->tail = hook->prev;
+
+  master->count--;
+
+  if (IS_OSPF6_DUMP_HOOK)
+    {
+      zlog_info ("HOOK: Unregister hook%s%s%s%s",
+                 (hook->name ? " " : ""),
+                 (hook->name ? hook->name : ""),
+                 (master->name ? " to " : ""),
+                 (master->name ? master->name : ""));
+    }
+
+  if (hook->name)
+    free (hook->name);
+  ospf6_hook_delete (hook);
+}
+
+void
+ospf6_hook_unregister_all (struct ospf6_hook_master *master)
+{
+  struct ospf6_hook *hook, *next;
+
+  for (hook = master->head; hook; hook = next)
+    {
+      next = hook->next;
+      ospf6_hook_delete (hook);
+    }
+
+  master->head = NULL;
+  master->tail = NULL;
+  master->count = 0;
+}
+
+
+void
+ospf6_hook_init ()
+{
+  neighbor_hook.name       =      "Neighbor Hooklist";
+  interface_hook.name      =     "Interface Hooklist";
+  area_hook.name           =          "Area Hooklist";
+  top_hook.name            =           "Top Hooklist";
+  database_hook.name       =      "Database Hooklist";
+  intra_topology_hook.name = "IntraTopology Hooklist";
+  inter_topology_hook.name = "InterTopology Hooklist";
+  route_hook.name          =         "Route Hooklist";
+}
+
+
diff --git a/ospf6d/ospf6_hook.h b/ospf6d/ospf6_hook.h
new file mode 100644 (file)
index 0000000..fa882a5
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_HOOK_H
+#define OSPF6_HOOK_H
+
+#include "ospf6_dump.h"
+
+struct ospf6_hook
+{
+  struct ospf6_hook *prev;
+  struct ospf6_hook *next;
+
+  char *name;
+  int (*hook_add) (void *);
+  int (*hook_change) (void *);
+  int (*hook_remove) (void *);
+};
+
+struct ospf6_hook_master
+{
+  char *name;
+  struct ospf6_hook *head;
+  struct ospf6_hook *tail;
+  int count;
+};
+
+#define CALL_HOOKS(master,hookname,hookstr,data) \
+  {\
+    struct ospf6_hook *hook;\
+    for (hook = (master)->head; hook; hook = hook->next)\
+      {\
+        if (hook->hookname)\
+          {\
+            if (IS_OSPF6_DUMP_HOOK)\
+              zlog_info ("HOOK: Call %s hook: %s", (hookstr), hook->name);\
+            (*(hook->hookname)) (data);\
+          }\
+      }\
+  }
+#define CALL_ADD_HOOK(master,data) \
+  { CALL_HOOKS ((master), hook_add, "ADD", (data)) }
+#define CALL_CHANGE_HOOK(master,data) \
+  { CALL_HOOKS ((master), hook_change, "CHANGE", (data)) }
+#define CALL_REMOVE_HOOK(master,data) \
+  { CALL_HOOKS ((master), hook_remove, "REMOVE", (data)) }
+
+#define IS_HOOK_SET(hook) \
+  ((hook)->hook_add || (hook)->hook_change || (hook)->hook_remove)
+
+extern struct ospf6_hook_master neighbor_hook;
+extern struct ospf6_hook_master interface_hook;
+extern struct ospf6_hook_master area_hook;
+extern struct ospf6_hook_master top_hook;
+extern struct ospf6_hook_master database_hook;
+extern struct ospf6_hook_master intra_topology_hook;
+extern struct ospf6_hook_master inter_topology_hook;
+extern struct ospf6_hook_master route_hook;
+extern struct ospf6_hook_master redistribute_hook;
+
+void ospf6_hook_register (struct ospf6_hook *,
+                          struct ospf6_hook_master *);
+void ospf6_hook_unregister (struct ospf6_hook *,
+                            struct ospf6_hook_master *);
+void ospf6_hook_unregister_all (struct ospf6_hook_master *);
+void ospf6_hook_init ();
+
+#endif /*OSPF6_HOOK_H*/
+
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
new file mode 100644 (file)
index 0000000..d394f21
--- /dev/null
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+#include "if.h"
+#include "log.h"
+#include "command.h"
+
+#include "ospf6_lsdb.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+
+char *ospf6_interface_state_string[] =
+{
+  "None", "Down", "Loopback", "Waiting", "PointToPoint",
+  "DROther", "BDR", "DR", NULL
+};
+
+static void
+ospf6_interface_foreach_neighbor (struct ospf6_interface *o6i,
+                                  void *arg, int val,
+                                  void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_neighbor *nei;
+
+  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+    {
+      nei = (struct ospf6_neighbor *) getdata (node);
+      (*func) (arg, val, nei);
+    }
+}
+
+static int
+ospf6_interface_maxage_remover (struct thread *t)
+{
+  int count;
+  struct ospf6_interface *o6i = (struct ospf6_interface *) THREAD_ARG (t);
+
+  o6i->maxage_remover = (struct thread *) NULL;
+
+  count = 0;
+  o6i->foreach_nei (o6i, &count, NBS_EXCHANGE, ospf6_count_state);
+  o6i->foreach_nei (o6i, &count, NBS_LOADING, ospf6_count_state);
+  if (count != 0)
+    return 0;
+
+  ospf6_lsdb_remove_maxage (o6i->lsdb);
+  return 0;
+}
+
+void
+ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj)
+{
+  struct ospf6_interface *o6i = (struct ospf6_interface *) obj;
+
+  if (o6i->maxage_remover != NULL)
+    return;
+
+  o6i->maxage_remover =
+    thread_add_event (master, ospf6_interface_maxage_remover, o6i, 0);
+}
+
+/* Create new ospf6 interface structure */
+struct ospf6_interface *
+ospf6_interface_create (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *)
+    XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface));
+
+  if (o6i)
+    memset (o6i, 0, sizeof (struct ospf6_interface));
+  else
+    {
+      zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex);
+      return (struct ospf6_interface *) NULL;
+    }
+
+  o6i->instance_id = 0;
+  o6i->if_id = ifp->ifindex;
+  o6i->lladdr = (struct in6_addr *) NULL;
+  o6i->area = (struct ospf6_area *) NULL;
+  o6i->state = IFS_DOWN;
+  o6i->flag = 0;
+  o6i->neighbor_list = list_new ();
+
+  o6i->ack_list = ospf6_lsdb_create ();
+  o6i->lsdb = ospf6_lsdb_create ();
+
+  o6i->transdelay = 1;
+  o6i->priority = 1;
+  o6i->hello_interval = 10;
+  o6i->dead_interval = 40;
+  o6i->rxmt_interval = 5;
+  o6i->cost = 1;
+  o6i->ifmtu = 1280;
+
+  o6i->foreach_nei = ospf6_interface_foreach_neighbor;
+
+  /* link both */
+  o6i->interface = ifp;
+  ifp->info = o6i;
+
+  CALL_ADD_HOOK (&interface_hook, o6i);
+
+  /* Get the interface's link-local if any */
+  ospf6_interface_address_update(ifp);
+
+  return o6i;
+}
+
+void
+ospf6_interface_delete (struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+
+  CALL_REMOVE_HOOK (&interface_hook, o6i);
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      ospf6_neighbor_delete (o6n);
+    }
+  list_delete (o6i->neighbor_list);
+
+  if (o6i->thread_send_hello)
+    {
+      thread_cancel (o6i->thread_send_hello);
+      o6i->thread_send_hello = NULL;
+    }
+  if (o6i->thread_send_lsack_delayed)
+    {
+      thread_cancel (o6i->thread_send_lsack_delayed);
+      o6i->thread_send_lsack_delayed = NULL;
+    }
+
+  ospf6_lsdb_delete (o6i->ack_list);
+  ospf6_lsdb_remove_all (o6i->lsdb);
+  ospf6_lsdb_delete (o6i->lsdb);
+
+  /* cut link */
+  o6i->interface->info = NULL;
+
+  /* plist_name */
+  if (o6i->plist_name)
+    XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+
+  XFREE (MTYPE_OSPF6_IF, o6i);
+}
+
+static struct in6_addr *
+ospf6_interface_update_linklocal_address (struct interface *ifp)
+{
+  listnode n;
+  struct connected *c;
+  struct in6_addr *l = (struct in6_addr *) NULL;
+
+  /* for each connected address */
+  for (n = listhead (ifp->connected); n; nextnode (n))
+    {
+      c = (struct connected *) getdata (n);
+
+      /* if family not AF_INET6, ignore */
+      if (c->address->family != AF_INET6)
+        continue;
+
+      /* linklocal scope check */
+      if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6))
+        l = &c->address->u.prefix6;
+    }
+  return l;
+}
+
+void
+ospf6_interface_if_add (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (!o6i)
+    return;
+
+  o6i->if_id = ifp->ifindex;
+
+  ospf6_interface_address_update (ifp);
+
+  /* interface start */
+  if (o6i->area)
+    thread_add_event (master, interface_up, o6i, 0);
+}
+
+void
+ospf6_interface_if_del (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (!o6i)
+    return;
+
+  /* interface stop */
+  if (o6i->area)
+    thread_execute (master, interface_down, o6i, 0);
+
+  listnode_delete (o6i->area->if_list, o6i);
+  o6i->area = (struct ospf6_area *) NULL;
+
+  /* cut link */
+  o6i->interface = NULL;
+  ifp->info = NULL;
+
+  ospf6_interface_delete (o6i);
+}
+
+void
+ospf6_interface_state_update (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    return;
+  if (! o6i->area)
+    return;
+
+  if (if_is_up (ifp))
+    thread_add_event (master, interface_up, o6i, 0);
+  else
+    thread_add_event (master, interface_down, o6i, 0);
+
+  return;
+}
+
+void
+ospf6_interface_address_update (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    return;
+
+  /* reset linklocal pointer */
+  o6i->lladdr = ospf6_interface_update_linklocal_address (ifp);
+
+  /* if area is null, can't make link-lsa */
+  if (! o6i->area)
+    return;
+
+  /* create new Link-LSA */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+}
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_index (int ifindex)
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = if_lookup_by_index (ifindex);
+
+  if (! ifp)
+    return (struct ospf6_interface *) NULL;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  return o6i;
+}
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_name (char *ifname)
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = if_lookup_by_name (ifname);
+
+  if (! ifp)
+    return (struct ospf6_interface *) NULL;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  return o6i;
+}
+
+int
+ospf6_interface_count_neighbor_in_state (u_char state,
+                                         struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+  int count = 0;
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      if (o6n->state == state)
+        count++;
+    }
+  return count;
+}
+
+int
+ospf6_interface_count_full_neighbor (struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+  int count = 0;
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      if (o6n->state == NBS_FULL)
+        count++;
+    }
+  return count;
+}
+
+int
+ospf6_interface_is_enabled (unsigned int ifindex)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = ospf6_interface_lookup_by_index (ifindex);
+  if (! o6i)
+    return 0;
+
+  if (! o6i->area)
+    return 0;
+
+  if (o6i->state <= IFS_DOWN)
+    return 0;
+
+  return 1;
+}
+
+void
+ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
+                                 struct ospf6_interface *o6i)
+{
+  struct ospf6_lsa *summary;
+  summary = ospf6_lsa_summary_create (lsa->header);
+  ospf6_lsdb_add (summary, o6i->ack_list);
+}
+
+void
+ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
+                                    struct ospf6_interface *o6i)
+{
+  struct ospf6_lsa *summary;
+  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+                                    lsa->header->adv_router, o6i->ack_list);
+  ospf6_lsdb_remove (summary, o6i->ack_list);
+}
+
+/* show specified interface structure */
+int
+ospf6_interface_show (struct vty *vty, struct interface *iface)
+{
+  struct ospf6_interface *ospf6_interface;
+  struct connected *c;
+  struct prefix *p;
+  listnode i;
+  char strbuf[64], dr[32], bdr[32];
+  char *updown[3] = {"down", "up", NULL};
+  char *type;
+
+  /* check physical interface type */
+  if (if_is_loopback (iface))
+    type = "LOOPBACK";
+  else if (if_is_broadcast (iface))
+    type = "BROADCAST";
+  else if (if_is_pointopoint (iface))
+    type = "POINTOPOINT";
+  else
+    type = "UNKNOWN";
+
+  vty_out (vty, "%s is %s, type %s%s",
+           iface->name, updown[if_is_up (iface)], type,
+          VTY_NEWLINE);
+  vty_out (vty, "  Interface ID: %d%s", iface->ifindex, VTY_NEWLINE);
+
+  if (iface->info == NULL)
+    {
+      vty_out (vty, "   OSPF not enabled on this interface%s", VTY_NEWLINE);
+      return 0;
+    }
+  else
+    ospf6_interface = (struct ospf6_interface *) iface->info;
+
+  vty_out (vty, "  Internet Address:%s", VTY_NEWLINE);
+  for (i = listhead (iface->connected); i; nextnode (i))
+    {
+      c = (struct connected *)getdata (i);
+      p = c->address;
+      prefix2str (p, strbuf, sizeof (strbuf));
+      switch (p->family)
+        {
+        case AF_INET:
+          vty_out (vty, "   inet : %s%s", strbuf,
+                  VTY_NEWLINE);
+          break;
+        case AF_INET6:
+          vty_out (vty, "   inet6: %s%s", strbuf,
+                  VTY_NEWLINE);
+          break;
+        default:
+          vty_out (vty, "   ???  : %s%s", strbuf,
+                  VTY_NEWLINE);
+          break;
+        }
+    }
+
+  if (ospf6_interface->area)
+    {
+      inet_ntop (AF_INET, &ospf6_interface->area->ospf6->router_id,
+                 strbuf, sizeof (strbuf));
+      vty_out (vty, "  Instance ID %d, Router ID %s%s",
+              ospf6_interface->instance_id, strbuf,
+              VTY_NEWLINE);
+      inet_ntop (AF_INET, &ospf6_interface->area->area_id,
+                 strbuf, sizeof (strbuf));
+      vty_out (vty, "  Area ID %s, Cost %hu%s", strbuf,
+              ospf6_interface->cost, VTY_NEWLINE);
+    }
+  else
+    vty_out (vty, "  Not Attached to Area%s", VTY_NEWLINE);
+
+  vty_out (vty, "  State %s, Transmit Delay %d sec, Priority %d%s",
+           ospf6_interface_state_string[ospf6_interface->state],
+           ospf6_interface->transdelay,
+           ospf6_interface->priority,
+          VTY_NEWLINE);
+  vty_out (vty, "  Timer intervals configured:%s", VTY_NEWLINE);
+  vty_out (vty, "   Hello %d, Dead %d, Retransmit %d%s",
+           ospf6_interface->hello_interval,
+           ospf6_interface->dead_interval,
+           ospf6_interface->rxmt_interval,
+          VTY_NEWLINE);
+
+  inet_ntop (AF_INET, &ospf6_interface->dr, dr, sizeof (dr));
+  inet_ntop (AF_INET, &ospf6_interface->bdr, bdr, sizeof (bdr));
+  vty_out (vty, "  DR:%s BDR:%s%s", dr, bdr, VTY_NEWLINE);
+
+  vty_out (vty, "  Number of I/F scoped LSAs is %u%s",
+                ospf6_interface->lsdb->count, VTY_NEWLINE);
+  vty_out (vty, "  %-16s %5d times, %-16s %5d times%s",
+                "DRElection", ospf6_interface->ospf6_stat_dr_election,
+                "DelayedLSAck", ospf6_interface->ospf6_stat_delayed_lsack,
+                VTY_NEWLINE);
+
+  return 0;
+}
+
+void
+ospf6_interface_statistics_show (struct vty *vty, struct ospf6_interface *o6i)
+{
+  struct timeval now, uptime;
+  u_long recv_total, send_total;
+  u_long bps_total_avg, bps_tx_avg, bps_rx_avg;
+  int i;
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  ospf6_timeval_sub (&now, &ospf6->starttime, &uptime);
+
+  recv_total = send_total = 0;
+  for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++)
+    {
+      recv_total += o6i->message_stat[i].recv_octet;
+      send_total += o6i->message_stat[i].send_octet;
+    }
+  bps_total_avg = (recv_total + send_total) * 8 / uptime.tv_sec;
+  bps_tx_avg = send_total * 8 / uptime.tv_sec;
+  bps_rx_avg = recv_total * 8 / uptime.tv_sec;
+
+  vty_out (vty, "     Statistics of interface %s%s",
+           o6i->interface->name, VTY_NEWLINE);
+  vty_out (vty, "         Number of Neighbor: %d%s",
+           listcount (o6i->neighbor_list), VTY_NEWLINE);
+
+  vty_out (vty, "         %-8s %6s %6s %8s %8s%s",
+           "Type", "tx", "rx", "tx-byte", "rx-byte", VTY_NEWLINE);
+  for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++)
+    {
+      vty_out (vty, "         %-8s %6d %6d %8d %8d%s",
+               ospf6_message_type_string[i],
+               o6i->message_stat[i].send,
+               o6i->message_stat[i].recv,
+               o6i->message_stat[i].send_octet,
+               o6i->message_stat[i].recv_octet,
+               VTY_NEWLINE);
+    }
+
+  vty_out (vty, "         Average Link bandwidth: %ldbps"
+                " (Tx: %ldbps Rx: %ldbps)%s",
+           bps_total_avg, bps_tx_avg, bps_rx_avg, VTY_NEWLINE);
+}
+
+/* show interface */
+DEFUN (show_ipv6_ospf6_interface,
+       show_ipv6_ospf6_interface_ifname_cmd,
+       "show ipv6 ospf6 interface IFNAME",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       IFNAME_STR
+       )
+{
+  struct interface *ifp;
+  listnode i;
+
+  if (argc)
+    {
+      ifp = if_lookup_by_name (argv[0]);
+      if (!ifp)
+        {
+          vty_out (vty, "No such Interface: %s%s", argv[0],
+                  VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      ospf6_interface_show (vty, ifp);
+    }
+  else
+    {
+      for (i = listhead (iflist); i; nextnode (i))
+        {
+          ifp = (struct interface *)getdata (i);
+          ospf6_interface_show (vty, ifp);
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_interface,
+       show_ipv6_ospf6_interface_cmd,
+       "show ipv6 ospf6 interface",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       )
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_cost,
+       ipv6_ospf6_cost_cmd,
+       "ipv6 ospf6 cost COST",
+       IP6_STR
+       OSPF6_STR
+       "Interface cost\n"
+       "<1-65535> Cost\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = (struct interface *)vty->index;
+  assert (ifp);
+
+  o6i = (struct ospf6_interface *)ifp->info;
+  if (!o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  if (o6i->cost == strtol (argv[0], NULL, 10))
+    return CMD_SUCCESS;
+
+  o6i->cost = strtol (argv[0], NULL, 10);
+
+  /* execute LSA hooks */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_hellointerval,
+       ipv6_ospf6_hellointerval_cmd,
+       "ipv6 ospf6 hello-interval HELLO_INTERVAL",
+       IP6_STR
+       OSPF6_STR
+       "Time between HELLO packets\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  ospf6_interface = (struct ospf6_interface *) ifp->info;
+  if (!ospf6_interface)
+    ospf6_interface = ospf6_interface_create (ifp);
+  assert (ospf6_interface);
+
+  ospf6_interface->hello_interval = strtol (argv[0], NULL, 10);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_deadinterval,
+       ipv6_ospf6_deadinterval_cmd,
+       "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL",
+       IP6_STR
+       OSPF6_STR
+       "Interval after which a neighbor is declared dead\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  ospf6_interface = (struct ospf6_interface *) ifp->info;
+  if (!ospf6_interface)
+    ospf6_interface = ospf6_interface_create (ifp);
+  assert (ospf6_interface);
+
+  ospf6_interface->dead_interval = strtol (argv[0], NULL, 10);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_transmitdelay,
+       ipv6_ospf6_transmitdelay_cmd,
+       "ipv6 ospf6 transmit-delay TRANSMITDELAY",
+       IP6_STR
+       OSPF6_STR
+       "Link state transmit delay\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  ospf6_interface = (struct ospf6_interface *) ifp->info;
+  if (!ospf6_interface)
+    ospf6_interface = ospf6_interface_create (ifp);
+  assert (ospf6_interface);
+
+  ospf6_interface->transdelay = strtol (argv[0], NULL, 10);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_retransmitinterval,
+       ipv6_ospf6_retransmitinterval_cmd,
+       "ipv6 ospf6 retransmit-interval RXMTINTERVAL",
+       IP6_STR
+       OSPF6_STR
+       "Time between retransmitting lost link state advertisements\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  ospf6_interface = (struct ospf6_interface *) ifp->info;
+  if (!ospf6_interface)
+    ospf6_interface = ospf6_interface_create (ifp);
+  assert (ospf6_interface);
+
+  ospf6_interface->rxmt_interval = strtol (argv[0], NULL, 10);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_priority,
+       ipv6_ospf6_priority_cmd,
+       "ipv6 ospf6 priority PRIORITY",
+       IP6_STR
+       OSPF6_STR
+       "Router priority\n"
+       "<0-255> Priority\n"
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  ospf6_interface = (struct ospf6_interface *) ifp->info;
+  if (!ospf6_interface)
+    ospf6_interface = ospf6_interface_create (ifp);
+  assert (ospf6_interface);
+
+  ospf6_interface->priority = strtol (argv[0], NULL, 10);
+
+  if (ospf6_interface->area)
+    ifs_change (dr_election (ospf6_interface), "Priority reconfigured",
+                ospf6_interface);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_instance,
+       ipv6_ospf6_instance_cmd,
+       "ipv6 ospf6 instance-id INSTANCE",
+       IP6_STR
+       OSPF6_STR
+       "Instance ID\n"
+       "<0-255> Instance ID\n"
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  struct interface *ifp;
+
+  ifp = (struct interface *)vty->index;
+  assert (ifp);
+
+  ospf6_interface = (struct ospf6_interface *)ifp->info;
+  if (!ospf6_interface)
+    ospf6_interface = ospf6_interface_create (ifp);
+  assert (ospf6_interface);
+
+  ospf6_interface->instance_id = strtol (argv[0], NULL, 10);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_passive,
+       ipv6_ospf6_passive_cmd,
+       "ipv6 ospf6 passive",
+       IP6_STR
+       OSPF6_STR
+       "passive interface: No Adjacency will be formed on this I/F\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+  listnode node;
+  struct ospf6_neighbor *o6n;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+  if (o6i->thread_send_hello)
+    {
+      thread_cancel (o6i->thread_send_hello);
+      o6i->thread_send_hello = (struct thread *) NULL;
+    }
+
+  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+    {
+      o6n = getdata (node);
+      if (o6n->inactivity_timer)
+        thread_cancel (o6n->inactivity_timer);
+      thread_execute (master, inactivity_timer, o6n, 0);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_passive,
+       no_ipv6_ospf6_passive_cmd,
+       "no ipv6 ospf6 passive",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "passive interface: No Adjacency will be formed on this I/F\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+  if (o6i->thread_send_hello == NULL)
+    thread_add_event (master, ospf6_send_hello, o6i, 0);
+
+  return CMD_SUCCESS;
+}
+
+
+DEFUN (ipv6_ospf6_advertise_force_prefix,
+       ipv6_ospf6_advertise_force_prefix_cmd,
+       "ipv6 ospf6 advertise force-prefix",
+       IP6_STR
+       OSPF6_STR
+       "Advertising options\n"
+       "Force advertising prefix, applicable if Loopback or P-to-P\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  if (! if_is_loopback (ifp) && ! if_is_pointopoint (ifp))
+    {
+      vty_out (vty, "Interface not Loopback nor PointToPoint%s",
+               VTY_NEWLINE);
+      return CMD_ERR_NOTHING_TODO;
+    }
+
+  SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX);
+
+  /* execute LSA hooks */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_advertise_force_prefix,
+       no_ipv6_ospf6_advertise_force_prefix_cmd,
+       "no ipv6 ospf6 advertise force-prefix",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "Advertising options\n"
+       "Force to advertise prefix, applicable if Loopback or P-to-P\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX);
+
+  /* execute LSA hooks */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_advertise_prefix_list,
+       ipv6_ospf6_advertise_prefix_list_cmd,
+       "ipv6 ospf6 advertise prefix-list WORD",
+       IP6_STR
+       OSPF6_STR
+       "Advertising options\n"
+       "Filter prefix using prefix-list\n"
+       "Prefix list name\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  if (o6i->plist_name)
+    XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+  o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]);
+
+  /* execute LSA hooks */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_advertise_prefix_list,
+       no_ipv6_ospf6_advertise_prefix_list_cmd,
+       "no ipv6 ospf6 advertise prefix-list",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "Advertising options\n"
+       "Filter prefix using prefix-list\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+  assert (o6i);
+
+  if (o6i->plist_name)
+    {
+      XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+      o6i->plist_name = NULL;
+    }
+
+  /* execute LSA hooks */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_interface_config_write (struct vty *vty)
+{
+  listnode i;
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  for (i = listhead (iflist); i; nextnode (i))
+    {
+      ifp = (struct interface *) getdata (i);
+      o6i = (struct ospf6_interface *) ifp->info;
+      if (! o6i)
+        continue;
+
+      vty_out (vty, "interface %s%s",
+               o6i->interface->name, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 cost %d%s",
+               o6i->cost, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 hello-interval %d%s",
+               o6i->hello_interval, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 dead-interval %d%s",
+               o6i->dead_interval, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s",
+               o6i->rxmt_interval, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 priority %d%s",
+               o6i->priority, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 transmit-delay %d%s",
+               o6i->transdelay, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 instance-id %d%s",
+               o6i->instance_id, VTY_NEWLINE);
+
+      if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX))
+        vty_out (vty, " ipv6 ospf6 advertise force-prefix%s", VTY_NEWLINE);
+      if (o6i->plist_name)
+        vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s",
+                 o6i->plist_name, VTY_NEWLINE);
+
+      if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+        vty_out (vty, " ipv6 ospf6 passive%s", VTY_NEWLINE);
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+};
+
+void
+ospf6_interface_init ()
+{
+  /* Install interface node. */
+  install_node (&interface_node, ospf6_interface_config_write);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+
+  install_default (INTERFACE_NODE);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_force_prefix_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_force_prefix_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
new file mode 100644 (file)
index 0000000..a96ef25
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_INTERFACE_H
+#define OSPF6_INTERFACE_H
+
+#include "ospf6_message.h"
+
+/* This file defines interface data structure. */
+
+struct ospf6_interface
+{
+  /* IF info from zebra */
+  struct interface *interface;
+
+  /* back pointer */
+  struct ospf6_area *area;
+
+  /* list of ospf6 neighbor */
+  list neighbor_list;
+
+  /* linklocal address of this I/F */
+  struct in6_addr *lladdr;
+
+  /* Interface ID; same as ifindex */
+  u_int32_t if_id;
+
+  /* ospf6 instance id */
+  u_char instance_id;
+
+  /* I/F transmission delay */
+  u_int32_t transdelay;
+
+  /* Router Priority */
+  u_char priority;
+
+  /* Timers */
+  u_int16_t hello_interval;
+  u_int16_t dead_interval;
+  u_int32_t rxmt_interval;
+
+  /* Cost */
+  u_int32_t cost;
+
+  /* I/F MTU */
+  u_int32_t ifmtu;
+
+  /* Interface State */
+  u_char state;
+
+  /* OSPF6 Interface flag */
+  char flag;
+
+  /* Decision of DR Election */
+  u_int32_t dr;
+  u_int32_t bdr;
+  u_int32_t prevdr;
+  u_int32_t prevbdr;
+
+  /* Ongoing Tasks */
+  struct thread *thread_send_hello;
+  struct thread *thread_send_lsack_delayed;
+
+  /* LSAs to Delayed Acknowledge */
+  struct ospf6_lsdb *ack_list;
+
+  /* Linklocal LSA Database: includes Link-LSA */
+  struct ospf6_lsdb *lsdb;
+
+  /* statistics */
+  u_int ospf6_stat_dr_election;
+  u_int ospf6_stat_delayed_lsack;
+
+  struct ospf6_message_stat message_stat[OSPF6_MESSAGE_TYPE_MAX];
+
+  void (*foreach_nei) (struct ospf6_interface *, void *, int,
+                       void (*func) (void *, int, void *));
+
+  struct thread *maxage_remover;
+
+  /* route-map to filter connected prefix */
+  char *plist_name;
+};
+
+extern char *ospf6_interface_state_string[];
+
+#define OSPF6_INTERFACE_FLAG_PASSIVE      0x01
+#define OSPF6_INTERFACE_FLAG_FORCE_PREFIX 0x02
+
+\f
+/* Function Prototypes */
+
+void
+ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj);
+
+struct ospf6_interface *
+ospf6_interface_create (struct interface *);
+void
+ospf6_interface_delete (struct ospf6_interface *);
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_index (int);
+struct ospf6_interface *
+ospf6_interface_lookup_by_name (char *);
+
+void ospf6_interface_if_add (struct interface *);
+void ospf6_interface_if_del (struct interface *);
+void ospf6_interface_state_update (struct interface *);
+void ospf6_interface_address_update (struct interface *);
+
+void ospf6_interface_init ();
+
+#if 0
+int
+ospf6_interface_count_neighbor_in_state (u_char state,
+                                         struct ospf6_interface *o6i);
+int
+ospf6_interface_count_full_neighbor (struct ospf6_interface *);
+#endif
+
+int ospf6_interface_is_enabled (u_int32_t ifindex);
+
+void
+ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
+                                 struct ospf6_interface *o6i);
+void
+ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
+                                    struct ospf6_interface *o6i);
+
+void
+ospf6_interface_statistics_show (struct vty *vty,
+                                 struct ospf6_interface *o6i);
+
+#endif /* OSPF6_INTERFACE_H */
+
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
new file mode 100644 (file)
index 0000000..b9c9ebd
--- /dev/null
@@ -0,0 +1,896 @@
+/*
+ * Copyright (C) 2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+static int intra_index;
+#define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index))
+
+#define ADD    0
+#define REMOVE 1
+
+static void
+ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa,
+                             struct ospf6_route_req *topo_entry)
+{
+  struct ospf6_intra_area_prefix_lsa *intra_prefix;
+  char *start, *end;
+  struct ospf6_prefix *ospf6_prefix;
+  struct ospf6_route_req request;
+  struct ospf6_area *area;
+
+  if (IS_OSPF6_DUMP_INTRA)
+    {
+      char buf[64];
+      struct prefix_ls *p_ls;
+      p_ls = (struct prefix_ls *) &topo_entry->route.prefix;
+      inet_ntop (AF_INET, &p_ls->adv_router, buf, sizeof (buf));
+      zlog_info ("INTRA: Calculate [%s] %s and %s",
+                 (type == ADD ? "add" : "remove"), lsa->str, buf);
+    }
+
+  intra_prefix = OSPF6_LSA_HEADER_END (lsa->header);
+
+  area = lsa->scope;
+  assert (area);
+
+  start = (char *) (intra_prefix + 1);
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+  for (ospf6_prefix = (struct ospf6_prefix *) start;
+       (char *) ospf6_prefix < end;
+       ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix))
+    {
+      memset (&request, 0, sizeof (request));
+
+      request.route.type = OSPF6_DEST_TYPE_NETWORK;
+      request.route.prefix.family = AF_INET6;
+      request.route.prefix.prefixlen = ospf6_prefix->prefix_length;
+      ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6);
+
+      request.path.type = OSPF6_PATH_TYPE_INTRA;
+      request.path.area_id = area->area_id;
+      request.path.origin.type = lsa->header->type;
+      request.path.origin.id = lsa->header->id;
+      request.path.origin.adv_router = lsa->header->adv_router;
+      request.path.cost = topo_entry->path.cost +
+                          ntohs (ospf6_prefix->prefix_metric);
+      request.path.capability[0] = topo_entry->path.capability[0];
+      request.path.capability[1] = topo_entry->path.capability[1];
+      request.path.capability[2] = topo_entry->path.capability[2];
+
+      memcpy (&request.nexthop.address, &topo_entry->nexthop.address,
+              sizeof (request.nexthop.address));
+      request.nexthop.ifindex = topo_entry->nexthop.ifindex;
+
+      if (type == ADD)
+        ospf6_route_add (&request, area->route_table);
+      else if (type == REMOVE)
+        ospf6_route_remove (&request, area->route_table);
+      else
+        assert (0);
+    }
+}
+
+int
+ospf6_intra_prefix_database_hook_remove (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_area *area;
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct prefix_ls prefix_ls;
+  struct ospf6_route_req topo_entry;
+
+  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
+    return 0;
+
+  area = (struct ospf6_area *) lsa->scope;
+  assert (area);
+
+  if (IS_OSPF6_DUMP_INTRA)
+    zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str);
+
+  iap = OSPF6_LSA_HEADER_END (lsa->header);
+  memset (&prefix_ls, 0, sizeof (prefix_ls));
+  prefix_ls.prefixlen = 64;
+  prefix_ls.adv_router.s_addr = iap->refer_advrtr;
+  prefix_ls.id.s_addr = iap->refer_lsid;
+
+  if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+      iap->refer_lsid != htonl (0))
+    {
+      zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
+                 (u_long) ntohl (iap->refer_lsid), lsa->str);
+      prefix_ls.id.s_addr = htonl (0);
+    }
+
+  ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
+                      area->table_topology);
+
+  while (iap->refer_lstype == topo_entry.path.origin.type &&
+         iap->refer_lsid == topo_entry.path.origin.id &&
+         iap->refer_advrtr == topo_entry.path.origin.adv_router)
+    {
+      ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry);
+      ospf6_route_next (&topo_entry);
+    }
+  return 0;
+}
+
+int
+ospf6_intra_prefix_database_hook_add (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_area *area;
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct prefix_ls prefix_ls;
+  struct ospf6_route_req topo_entry;
+
+  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
+    return 0;
+
+  area = (struct ospf6_area *) lsa->scope;
+  assert (area);
+
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      ospf6_intra_prefix_database_hook_remove (lsa);
+      return 0;
+    }
+
+  if (IS_OSPF6_DUMP_INTRA)
+    zlog_info ("INTRA: area %s add: %s", area->str, lsa->str);
+
+  iap = OSPF6_LSA_HEADER_END (lsa->header);
+
+  memset (&prefix_ls, 0, sizeof (struct prefix_ls));
+  prefix_ls.prefixlen = 64;
+  prefix_ls.adv_router.s_addr = iap->refer_advrtr;
+  prefix_ls.id.s_addr = iap->refer_lsid;
+
+  if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+      iap->refer_lsid != htonl (0))
+    {
+      zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
+                 (u_long) ntohl (iap->refer_lsid), lsa->str);
+      prefix_ls.id.s_addr = htonl (0);
+    }
+
+  ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
+                      area->table_topology);
+
+  while (iap->refer_lstype == topo_entry.path.origin.type &&
+         iap->refer_lsid == topo_entry.path.origin.id &&
+         iap->refer_advrtr == topo_entry.path.origin.adv_router)
+    {
+      ospf6_intra_route_calculate (ADD, lsa, &topo_entry);
+      ospf6_route_next (&topo_entry);
+    }
+  return 0;
+}
+
+void
+ospf6_intra_topology_add (void *data)
+{
+  struct ospf6_route_req *topo_entry = data;
+  struct ospf6_area *area;
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct ospf6_lsdb_node node;
+
+  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
+  if (! area)
+    return;
+
+  if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
+      (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
+       CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
+    ospf6_route_add (topo_entry, ospf6->topology_table);
+
+  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                        area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      if (IS_LSA_MAXAGE (node.lsa))
+        continue;
+
+      iap = OSPF6_LSA_HEADER_END (node.lsa->header);
+
+      if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+          iap->refer_lsid != htonl (0))
+        {
+          zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
+                     (u_long) ntohl (iap->refer_lsid), node.lsa->str);
+        }
+
+      if (iap->refer_lstype != topo_entry->path.origin.type ||
+          iap->refer_lsid != topo_entry->path.origin.id ||
+          iap->refer_advrtr != topo_entry->path.origin.adv_router)
+        continue;
+
+      ospf6_intra_route_calculate (ADD, node.lsa, topo_entry);
+    }
+}
+
+void
+ospf6_intra_topology_remove (void *data)
+{
+  struct ospf6_route_req *topo_entry = data;
+  struct ospf6_area *area;
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct ospf6_lsdb_node node;
+
+  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
+  if (! area)
+    return;
+
+  if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
+      (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
+       CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
+    ospf6_route_remove (topo_entry, ospf6->topology_table);
+
+  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                        area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      if (IS_LSA_MAXAGE (node.lsa))
+        continue;
+
+      iap = OSPF6_LSA_HEADER_END (node.lsa->header);
+
+      if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
+          iap->refer_lsid != htonl (0))
+        zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
+                   (u_long) ntohl (iap->refer_lsid), node.lsa->str);
+
+      if (iap->refer_lstype != topo_entry->path.origin.type ||
+          iap->refer_lsid != topo_entry->path.origin.id ||
+          iap->refer_advrtr != topo_entry->path.origin.adv_router)
+        continue;
+
+      ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry);
+    }
+}
+
+\f
+/*****************************************/
+/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
+/*****************************************/
+
+#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
+  if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_PREFIX)\
+        zlog_info ("  Filter out Linklocal: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
+  if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_PREFIX)\
+        zlog_info ("  Filter out Unspecified: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
+  if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_PREFIX)\
+        zlog_info ("  Filter out Loopback: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
+  if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_PREFIX)\
+        zlog_info ("  Filter out V4Compat: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
+  if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_PREFIX)\
+        zlog_info ("  Filter out V4Mapped: %s", buf);\
+      continue;\
+    }
+
+
+int
+ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  struct ospf6_intra_area_prefix_lsa *iap_lsa;
+  struct ospf6_prefix *prefix;
+  unsigned short prefixnum;
+  char buf[128], type[32], id[32], adv_router[32];
+  struct in6_addr in6;
+  char *start, *end, *current;
+
+  assert (lsa->header);
+  iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1);
+
+  prefixnum = ntohs (iap_lsa->prefix_number);
+  ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type));
+  inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id));
+  inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router,
+             sizeof (adv_router));
+
+  vty_out (vty, "     Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
+  vty_out (vty, "     Referenced LS Type: %s%s", type, VTY_NEWLINE);
+  vty_out (vty, "     Referenced LS ID: %s%s", id, VTY_NEWLINE);
+  vty_out (vty, "     Referenced Advertising Router: %s%s", adv_router,
+           VTY_NEWLINE);
+
+  start = (char *) lsa->header + sizeof (struct ospf6_lsa_header)
+          + sizeof (struct ospf6_intra_area_prefix_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+
+  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
+    {
+      prefix = (struct ospf6_prefix *) current;
+      if (current + OSPF6_PREFIX_SIZE (prefix) > end)
+        {
+          vty_out (vty, "    Trailing %d byte garbage ... Malformed%s",
+                   end - current, VTY_NEWLINE);
+          return -1;
+        }
+
+      ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
+      vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
+
+      ospf6_prefix_in6_addr (prefix, &in6);
+      inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+      vty_out (vty, "     Prefix: %s/%d%s",
+               buf, prefix->prefix_length, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+ospf6_lsa_intra_prefix_update_transit (char *ifname)
+{
+  char buffer [MAXLSASIZE];
+  u_int16_t size;
+  struct ospf6_lsa *old;
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+  struct ospf6_neighbor *o6n;
+
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct ospf6_lsdb_node n;
+  listnode node;
+  char *start, *end, *current;
+  struct ospf6_prefix *prefix, *dup, *src, *dst;
+  struct ospf6_link_lsa *link;
+  char buf[128];
+  int count, prefix_num;
+
+  list adv_list;
+
+  ifp = if_lookup_by_name (ifname);
+  if (! ifp)
+    {
+      zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s",
+                  ifname);
+      return;
+    }
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i || ! o6i->area)
+    {
+      zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s",
+                  ifname);
+      return;
+    }
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                           htonl (o6i->if_id), ospf6->router_id,
+                           o6i->area);
+
+  /* Don't originate Network-LSA if not DR */
+  if (o6i->state != IFS_DR)
+    {
+      if (old)
+        {
+          if (IS_OSPF6_DUMP_PREFIX)
+            zlog_info ("Update Intra-Prefix (Transit): %s not DR",
+                       o6i->interface->name);
+          ospf6_lsa_premature_aging (old);
+        }
+      return;
+    }
+
+  /* If none of neighbor is adjacent to us */
+  count = 0;
+  o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+  if (count == 0)
+    {
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("Update Intra-Prefix (Transit): %s is Stub",
+                   o6i->interface->name);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  if (IS_OSPF6_DUMP_PREFIX)
+    zlog_info ("Update Intra-Prefix (Transit): Interface %s",
+               o6i->interface->name);
+
+  adv_list = list_new ();
+
+  /* foreach Link-LSA associated with this Link */
+  for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb);
+       ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n))
+    {
+      if (IS_LSA_MAXAGE (n.lsa))
+        continue;
+
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("Update Intra-Prefix (Transit): Checking %s",
+                    n.lsa->str);
+
+      /* Check status of the advertising router */
+      if (n.lsa->header->adv_router != o6i->area->ospf6->router_id)
+        {
+          o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i);
+          if (! o6n)
+            {
+              if (IS_OSPF6_DUMP_PREFIX)
+                zlog_info ("Update Intra-Prefix (Transit): neighbor not found");
+              continue;
+            }
+
+          if (o6n->state != NBS_FULL)
+            {
+              if (IS_OSPF6_DUMP_PREFIX)
+                zlog_info ("Update Intra-Prefix (Transit): %s not FULL",
+                           o6n->str);
+              continue;
+            }
+        }
+
+      /* For each Prefix in this Link-LSA */
+      link = (struct ospf6_link_lsa *) (n.lsa->header + 1);
+      prefix_num = ntohl (link->llsa_prefix_num);
+
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("  Prefix #%d", prefix_num);
+
+      start = (char *) (link + 1);
+      end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length);
+      prefix = (struct ospf6_prefix *) start;
+      for (current = start; current < end;
+           current += OSPF6_PREFIX_SIZE (prefix))
+        {
+          prefix = (struct ospf6_prefix *) current;
+          ospf6_prefix_string (prefix, buf, sizeof (buf));
+
+          /* Check duplicate prefix */
+          dup = ospf6_prefix_lookup (adv_list, prefix);
+          if (dup)
+            {
+              if (IS_OSPF6_DUMP_PREFIX)
+                zlog_info ("  Duplicate %s", buf);
+              dup->prefix_options |= prefix->prefix_options;
+              continue;
+            }
+
+          if (prefix_num <= 0)
+            {
+              zlog_warn ("  Wong prefix number ...");
+              break;
+            }
+
+          if (IS_OSPF6_DUMP_PREFIX)
+            zlog_info ("  Prefix %s", buf);
+
+          /* copy prefix to advertise list */
+          ospf6_prefix_add (adv_list, prefix);
+
+          prefix_num --;
+        }
+    }
+
+  /* if no prefix to advertise, return */
+  if (listcount (adv_list) == 0)
+    {
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("  No Prefix to advertise");
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  size = sizeof (struct ospf6_intra_area_prefix_lsa);
+  iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
+
+  /* Set Referenced LSA field */
+  iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK);
+  iap->refer_lsid = htonl (o6i->if_id);
+  iap->refer_advrtr = o6i->area->ospf6->router_id;
+
+  dst = (struct ospf6_prefix *) (iap + 1);
+  for (node = listhead (adv_list); node; nextnode (node))
+    {
+      src = (struct ospf6_prefix *) getdata (node);
+
+      memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
+
+      size += OSPF6_PREFIX_SIZE (dst);
+      dst = OSPF6_NEXT_PREFIX (dst);
+    }
+  iap->prefix_number = htons (listcount (adv_list));
+
+  while ((node = listhead (adv_list)) != NULL)
+    {
+      prefix = getdata (node);
+      ospf6_prefix_delete (prefix);
+      listnode_delete (adv_list, prefix);
+    }
+  list_delete (adv_list);
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                       htonl (o6i->if_id), ospf6->router_id,
+                       buffer, size, o6i->area);
+}
+
+void
+ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id)
+{
+  char buffer [MAXLSASIZE];
+  u_int16_t size;
+  struct ospf6_lsa *old;
+  struct ospf6_area *o6a;
+  int count;
+
+  struct ospf6_intra_area_prefix_lsa *iap;
+  listnode i,j;
+  struct ospf6_interface *o6i = NULL;
+  struct ospf6_prefix *prefix, *dst, *src;
+  struct connected *c;
+  char buf[128];
+
+  list adv_list;
+  listnode node;
+  char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)];
+
+  o6a = ospf6_area_lookup (area_id, ospf6);
+  if (! o6a)
+    {
+      char tmp[16];
+      inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp));
+      zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp);
+      return;
+    }
+  else if (IS_OSPF6_DUMP_PREFIX)
+    {
+      zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str);
+    }
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                           htonl (0), ospf6->router_id,
+                           o6a); /* xxx, ls-id */
+
+  adv_list = list_new ();
+
+  /* Examin for each interface */
+  for (i = listhead (o6a->if_list); i; nextnode (i))
+    {
+      o6i = (struct ospf6_interface *) getdata (i);
+
+      if (o6i->state == IFS_DOWN)
+        {
+          if (IS_OSPF6_DUMP_PREFIX)
+            zlog_info ("    Interface %s: down", o6i->interface->name);
+          continue;
+        }
+
+      count = 0;
+      o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+      if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP &&
+          count != 0)
+        {
+          /* This interface's prefix will be included in DR's */
+          if (IS_OSPF6_DUMP_PREFIX)
+            zlog_info ("    Interface %s: not stub", o6i->interface->name);
+          continue;
+        }
+
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("    Interface %s:", o6i->interface->name);
+
+      /* copy foreach address prefix */
+      for (j = listhead (o6i->interface->connected); j; nextnode (j))
+        {
+          c = (struct connected *) getdata (j);
+
+          /* filter prefix not IPv6 */
+          if (c->address->family != AF_INET6)
+            continue;
+
+          /* for log */
+          prefix2str (c->address, buf, sizeof (buf));
+
+          CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
+          CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
+          CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
+          CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
+          CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
+
+          /* filter prefix specified by configuration */
+          if (o6i->plist_name)
+            {
+              struct prefix_list *plist;
+              enum prefix_list_type result = PREFIX_PERMIT;
+
+              plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
+              if (plist)
+                result = prefix_list_apply (plist, c->address);
+              else
+                zlog_warn ("Update Intra-Prefix (Stub): "
+                           "Prefix list \"%s\" not found",
+                           o6i->plist_name);
+
+              if (result == PREFIX_DENY)
+                {
+                  if (IS_OSPF6_DUMP_PREFIX)
+                    zlog_info ("    %s: Filtered by %s",
+                               buf, o6i->plist_name);
+                  continue;
+                }
+            }
+
+          /* initialize buffer for ospf6 prefix */
+          memset (prefix_buf, 0, sizeof (prefix_buf));
+          prefix = (struct ospf6_prefix *) prefix_buf;
+
+          /* set ospf6 prefix according to its state */
+          /* xxx, virtual links */
+          if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) &&
+              (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP
+              /* xxx, PoinToMultiPoint I/F type */ ))
+            {
+              prefix->prefix_length = 128;
+              prefix->prefix_options = OSPF6_PREFIX_OPTION_LA;
+              prefix->prefix_metric = htons (0);
+              memcpy (prefix + 1, &c->address->u.prefix6,
+                      OSPF6_PREFIX_SPACE (prefix->prefix_length));
+            }
+          else
+            {
+              struct prefix_ipv6 prefix_ipv6;
+              /* apply mask */
+              prefix_copy ((struct prefix *) &prefix_ipv6, c->address);
+              apply_mask_ipv6 (&prefix_ipv6);
+
+              prefix->prefix_length = prefix_ipv6.prefixlen;
+              prefix->prefix_options = 0;  /* xxx, no options yet */
+              prefix->prefix_metric = htons (o6i->cost);
+              memcpy (prefix + 1, &prefix_ipv6.prefix,
+                      OSPF6_PREFIX_SPACE (prefix->prefix_length));
+            }
+
+          ospf6_prefix_string (prefix, buf, sizeof (buf));
+          if (IS_OSPF6_DUMP_PREFIX)
+            zlog_info ("    Advertise %s", buf);
+
+          /* check in the prefix to advertising prefix list */
+          ospf6_prefix_add (adv_list, prefix);
+        }
+    }
+
+  /* If no prefix to advertise */
+  if (listcount (adv_list) == 0)
+    {
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("    No prefix to advertise");
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  size = sizeof (struct ospf6_intra_area_prefix_lsa);
+  iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
+
+  /* Set Referenced LSA field */
+  iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER);
+  iap->refer_lsid = htonl (0);
+  iap->refer_advrtr = o6a->ospf6->router_id;
+
+  dst = (struct ospf6_prefix *) (iap + 1);
+  for (node = listhead (adv_list); node; nextnode (node))
+    {
+      src = (struct ospf6_prefix *) getdata (node);
+
+      memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
+
+      size += OSPF6_PREFIX_SIZE (dst);
+      dst = OSPF6_NEXT_PREFIX (dst);
+    }
+  iap->prefix_number = htons (listcount (adv_list));
+
+  while ((node = listhead (adv_list)) != NULL)
+    {
+      prefix = getdata (node);
+      ospf6_prefix_delete (prefix);
+      listnode_delete (adv_list, prefix);
+    }
+  list_delete (adv_list);
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                       htonl (0) /* xxx */, ospf6->router_id,
+                       buffer, size, o6a);
+}
+
+int
+ospf6_lsa_intra_prefix_hook_interface (void *interface)
+{
+  struct ospf6_interface *o6i = interface;
+  if (o6i->area)
+    {
+      ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+      ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
+    }
+  return 0;
+}
+
+int
+ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor)
+{
+  struct ospf6_neighbor *o6n = neighbor;
+  if (o6n->ospf6_interface->area)
+    {
+      ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name);
+      ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id);
+    }
+  return 0;
+}
+
+int
+ospf6_intra_prefix_link_database_hook (void *new)
+{
+  struct ospf6_lsa *lsa = new;
+  struct ospf6_interface *o6i;
+
+  if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK))
+    return 0;
+
+  o6i = lsa->scope;
+  if (o6i->state != IFS_DR)
+    return 0;
+
+  ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+  ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
+  return 0;
+}
+
+int
+ospf6_lsa_intra_prefix_refresh (void *old)
+{
+  struct ospf6_lsa *lsa = old;
+  struct ospf6_interface *o6i;
+  struct ospf6_area *o6a;
+  u_int32_t id;
+
+  id = ntohl (lsa->header->id);
+  if (id)
+    {
+      o6i = ospf6_interface_lookup_by_index (id);
+      if (o6i)
+        ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+      else
+        ospf6_lsa_premature_aging (lsa);
+    }
+  else
+    {
+      o6a = lsa->scope;
+      ospf6_lsa_intra_prefix_update_stub (o6a->area_id);
+    }
+
+  return 0;
+}
+
+void
+ospf6_intra_prefix_register ()
+{
+  struct ospf6_lsa_slot slot, *sp;
+  struct ospf6_hook hook;
+
+  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+  slot.type              = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
+  slot.name              = "Intra-Prefix";
+  slot.func_show         = ospf6_lsa_intra_prefix_show;
+  slot.func_refresh      = ospf6_lsa_intra_prefix_refresh;
+  ospf6_lsa_slot_register (&slot);
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name = "OriginateIntraPrefix";
+  hook.hook_add = ospf6_lsa_intra_prefix_hook_interface;
+  hook.hook_change = ospf6_lsa_intra_prefix_hook_interface;
+  hook.hook_remove = NULL; /* XXX */
+  ospf6_hook_register (&hook, &interface_hook);
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name = "OriginateIntraPrefix";
+  hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor;
+  hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor;
+  hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor;
+  ospf6_hook_register (&hook, &neighbor_hook);
+
+  sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX));
+  hook.name = "CalculateIntraPrefix";
+  hook.hook_add = ospf6_intra_prefix_database_hook_add;
+  hook.hook_change = ospf6_intra_prefix_database_hook_add;
+  hook.hook_remove = ospf6_intra_prefix_database_hook_remove;
+  ospf6_hook_register (&hook, &sp->database_hook);
+}
+
+void
+ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old,
+                                        struct ospf6_lsa *new)
+{
+  if (old)
+    ospf6_intra_prefix_database_hook_remove (old);
+  if (new && ! IS_LSA_MAXAGE (new))
+    ospf6_intra_prefix_database_hook_add (new);
+}
+
+void
+ospf6_intra_database_hook_link (struct ospf6_lsa *old,
+                                struct ospf6_lsa *new)
+{
+  ospf6_intra_prefix_link_database_hook (new);
+  ospf6_spf_database_hook (old, new);
+}
+
+void
+ospf6_intra_init ()
+{
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook =
+    ospf6_intra_database_hook_intra_prefix;
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_intra_database_hook_link;
+
+  intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n");
+  ospf6_intra_prefix_register ();
+}
+
+
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
new file mode 100644 (file)
index 0000000..4fb68e9
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2001 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_INTRA_H
+#define OSPF6_INTRA_H
+
+void ospf6_intra_topology_add (void *);
+void ospf6_intra_topology_remove (void *);
+
+void ospf6_intra_init ();
+
+#endif /* OSPF6_INTRA_H */
+
diff --git a/ospf6d/ospf6_ism.c b/ospf6d/ospf6_ism.c
new file mode 100644 (file)
index 0000000..d13be12
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+/* Interface State Machine */
+
+#include "ospf6d.h"
+
+int
+ifs_change (state_t ifs_next, char *reason, struct ospf6_interface *o6i)
+{
+  state_t ifs_prev;
+
+  ifs_prev = o6i->state;
+
+  if (ifs_prev == ifs_next)
+    return 0;
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: %s -> %s (%s)",
+               o6i->interface->name,
+               ospf6_interface_state_string[ifs_prev],
+               ospf6_interface_state_string[ifs_next], reason);
+
+  if ((ifs_prev == IFS_DR || ifs_prev == IFS_BDR) &&
+      (ifs_next != IFS_DR && ifs_next != IFS_BDR))
+    ospf6_leave_alldrouters (o6i->interface->ifindex);
+  else if ((ifs_prev != IFS_DR && ifs_prev != IFS_BDR) &&
+           (ifs_next == IFS_DR || ifs_next == IFS_BDR))
+    ospf6_join_alldrouters (o6i->interface->ifindex);
+
+  o6i->state = ifs_next;
+
+  if (o6i->prevdr != o6i->dr || o6i->prevbdr != o6i->bdr)
+    {
+      if (IS_OSPF6_DUMP_INTERFACE)
+        {
+          char dr[16], bdr[16], prevdr[16], prevbdr[16];
+          inet_ntop (AF_INET, &o6i->prevdr, prevdr, sizeof (prevdr));
+          inet_ntop (AF_INET, &o6i->prevbdr, prevbdr, sizeof (prevbdr));
+          inet_ntop (AF_INET, &o6i->dr, dr, sizeof (dr));
+          inet_ntop (AF_INET, &o6i->bdr, bdr, sizeof (bdr));
+          zlog_info ("I/F: %s: DR: %s -> %s", o6i->interface->name,
+                     prevdr, dr);
+          zlog_info ("I/F: %s: BDR: %s -> %s", o6i->interface->name,
+                     prevbdr, bdr);
+        }
+    }
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  return 0;
+}
+
+\f
+/* Interface State Machine */
+int
+interface_up (struct thread *thread)
+{
+  struct ospf6_interface *ospf6_interface;
+
+  ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+
+  assert (ospf6_interface);
+  assert (ospf6_interface->interface);
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: InterfaceUp",
+               ospf6_interface->interface->name);
+
+  /* check physical interface is up */
+  if (!if_is_up (ospf6_interface->interface))
+    {
+      if (IS_OSPF6_DUMP_INTERFACE)
+        zlog_warn ("  interface %s down, can't execute InterfaceUp",
+                   ospf6_interface->interface->name);
+      return -1;
+    }
+
+  /* if already enabled, do nothing */
+  if (ospf6_interface->state > IFS_DOWN)
+    {
+      zlog_warn ("Interface %s already up",
+                 ospf6_interface->interface->name);
+      return 0;
+    }
+
+  /* ifid of this interface */
+  ospf6_interface->if_id = ospf6_interface->interface->ifindex;
+
+  /* Join AllSPFRouters */
+  ospf6_join_allspfrouters (ospf6_interface->interface->ifindex);
+
+  /* set socket options */
+  ospf6_set_reuseaddr ();
+  ospf6_reset_mcastloop ();
+  ospf6_set_pktinfo ();
+  ospf6_set_checksum ();
+
+  /* Schedule Hello */
+  if (! CHECK_FLAG (ospf6_interface->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+    thread_add_event (master, ospf6_send_hello, ospf6_interface, 0);
+
+  /* decide next interface state */
+  if (if_is_pointopoint (ospf6_interface->interface))
+    ifs_change (IFS_PTOP, "IF Type PointToPoint", ospf6_interface);
+  else if (ospf6_interface->priority == 0)
+    ifs_change (IFS_DROTHER, "Router Priority = 0", ospf6_interface);
+  else
+    {
+      ifs_change (IFS_WAITING, "Priority > 0", ospf6_interface);
+      thread_add_timer (master, wait_timer, ospf6_interface,
+                        ospf6_interface->dead_interval);
+    }
+
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
+
+  return 0;
+}
+
+int
+wait_timer (struct thread *thread)
+{
+  struct ospf6_interface *ospf6_interface;
+
+  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
+  assert (ospf6_interface);
+
+  if (ospf6_interface->state != IFS_WAITING)
+    return 0;
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: WaitTimer", ospf6_interface->interface->name);
+
+  ifs_change (dr_election (ospf6_interface),
+              "WaitTimer:DR Election", ospf6_interface);
+  return 0;
+}
+
+int backup_seen (struct thread *thread)
+{
+  struct ospf6_interface *ospf6_interface;
+
+  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
+  assert (ospf6_interface);
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: BackupSeen", ospf6_interface->interface->name);
+
+  if (ospf6_interface->state == IFS_WAITING)
+    ifs_change (dr_election (ospf6_interface),
+                "BackupSeen:DR Election", ospf6_interface);
+
+  return 0;
+}
+
+int neighbor_change (struct thread *thread)
+{
+  struct ospf6_interface *ospf6_interface;
+
+  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
+  assert (ospf6_interface);
+
+  if (ospf6_interface->state != IFS_DROTHER &&
+      ospf6_interface->state != IFS_BDR &&
+      ospf6_interface->state != IFS_DR)
+    return 0;
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: NeighborChange", ospf6_interface->interface->name);
+
+  ifs_change (dr_election (ospf6_interface),
+              "NeighborChange:DR Election", ospf6_interface);
+
+  return 0;
+}
+
+int
+loopind (struct thread *thread)
+{
+  struct ospf6_interface *ospf6_interface;
+
+  ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
+  assert (ospf6_interface);
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: LoopInd", ospf6_interface->interface->name);
+
+  /* XXX not yet */
+
+  return 0;
+}
+
+int
+interface_down (struct thread *thread)
+{
+  struct ospf6_interface *ospf6_interface;
+
+  ospf6_interface = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (ospf6_interface);
+
+  if (IS_OSPF6_DUMP_INTERFACE)
+    zlog_info ("I/F: %s: InterfaceDown", ospf6_interface->interface->name);
+
+  if (ospf6_interface->state == IFS_NONE)
+    return 1;
+
+  /* Leave AllSPFRouters */
+  if (ospf6_interface_is_enabled (ospf6_interface->interface->ifindex))
+    ospf6_leave_allspfrouters (ospf6_interface->interface->ifindex);
+
+  ifs_change (IFS_DOWN, "Configured", ospf6_interface);
+
+  return 0;
+}
+
+\f
+/* 9.4 of RFC2328 */
+int
+dr_election (struct ospf6_interface *ospf6_interface)
+{
+  list candidate_list = list_new ();
+  listnode i, j, n;
+  ifid_t prevdr, prevbdr, dr = 0, bdr;
+  struct ospf6_neighbor *nbpi, *nbpj, myself, *nbr;
+  int declare = 0;
+  int gofive = 0;
+
+  /* statistics */
+  ospf6_interface->ospf6_stat_dr_election++;
+
+  /* pseudo neighbor "myself" */
+  memset (&myself, 0, sizeof (myself));
+  myself.state = NBS_TWOWAY;
+  myself.dr = ospf6_interface->dr;
+  myself.bdr = ospf6_interface->bdr;
+  myself.priority = ospf6_interface->priority;
+  myself.ifid = ospf6_interface->if_id;
+  myself.router_id = ospf6_interface->area->ospf6->router_id;
+
+/* step_one: */
+
+  ospf6_interface->prevdr = prevdr = ospf6_interface->dr;
+  ospf6_interface->prevbdr = prevbdr = ospf6_interface->bdr;
+
+step_two:
+
+  /* Calculate Backup Designated Router. */
+  /* Make Candidate list */
+  if (!list_isempty (candidate_list))
+    list_delete_all_node (candidate_list);
+  declare = 0;
+  for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
+    {
+      nbpi = (struct ospf6_neighbor *)getdata (i);
+      if (nbpi->priority == 0)
+        continue;
+      if (nbpi->state < NBS_TWOWAY)
+        continue;
+      if (nbpi->dr == nbpi->router_id)
+        continue;
+      if (nbpi->bdr == nbpi->router_id)
+        declare++;
+      listnode_add (candidate_list, nbpi);
+    }
+
+  if (myself.priority)
+    {
+      if (myself.dr != myself.router_id)
+        {
+          if (myself.bdr == myself.router_id)
+            declare++;
+          listnode_add (candidate_list, &myself);
+        }
+    }
+
+  /* Elect BDR */
+  for (i = listhead (candidate_list);
+       candidate_list->count > 1;
+       i = listhead (candidate_list))
+    {
+      j = i;
+      nextnode(j);
+      assert (j);
+      nbpi = (struct ospf6_neighbor *)getdata (i);
+      nbpj = (struct ospf6_neighbor *)getdata (j);
+      if (declare)
+        {
+          int deleted = 0;
+          if (nbpi->bdr != nbpi->router_id)
+            {
+              listnode_delete (candidate_list, nbpi);
+              deleted++;
+            }
+          if (nbpj->bdr != nbpj->router_id)
+            {
+              listnode_delete (candidate_list, nbpj);
+              deleted++;
+            }
+          if (deleted)
+            continue;
+        }
+      if (nbpi->priority > nbpj->priority)
+        {
+          listnode_delete (candidate_list, nbpj);
+          continue;
+        }
+      else if (nbpi->priority < nbpj->priority)
+        {
+          listnode_delete (candidate_list, nbpi);
+          continue;
+        }
+      else /* equal, case of tie */
+        {
+          if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id))
+            {
+              listnode_delete (candidate_list, nbpj);
+              continue;
+            }
+          else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id))
+            {
+              listnode_delete (candidate_list, nbpi);
+              continue;
+            }
+          else
+            assert (0);
+        }
+    }
+
+  if (!list_isempty (candidate_list))
+    {
+      assert (candidate_list->count == 1);
+      n = listhead (candidate_list);
+      nbr = (struct ospf6_neighbor *)getdata (n);
+      bdr = nbr->router_id;
+    }
+  else
+    bdr = 0;
+
+/* step_three: */
+
+  /* Calculate Designated Router. */
+  /* Make Candidate list */
+  if (!list_isempty (candidate_list))
+    list_delete_all_node (candidate_list);
+  declare = 0;
+  for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
+    {
+      nbpi = (struct ospf6_neighbor *)getdata (i);
+      if (nbpi->priority == 0)
+        continue;
+      if (nbpi->state < NBS_TWOWAY)
+        continue;
+      if (nbpi->dr == nbpi->router_id)
+        {
+          declare++;
+          listnode_add (candidate_list, nbpi);
+        }
+    }
+  if (myself.priority)
+    {
+      if (myself.dr == myself.router_id)
+        {
+          declare++;
+          listnode_add (candidate_list, &myself);
+        }
+    }
+
+  /* Elect DR */
+  if (declare == 0)
+    {
+      assert (list_isempty (candidate_list));
+      /* No one declare but candidate_list not empty */
+      dr = bdr;
+    }
+  else
+    {
+      assert (!list_isempty (candidate_list));
+      for (i = listhead (candidate_list);
+           candidate_list->count > 1;
+           i = listhead (candidate_list))
+        {
+          j = i;
+          nextnode (j);
+          assert (j);
+          nbpi = (struct ospf6_neighbor *)getdata (i);
+          nbpj = (struct ospf6_neighbor *)getdata (j);
+
+          if (nbpi->dr != nbpi->router_id)
+            {
+              list_delete_node (candidate_list, i);
+              continue;
+            }
+          if (nbpj->dr != nbpj->router_id)
+            {
+              list_delete_node (candidate_list, j);
+              continue;
+            }
+
+          if (nbpi->priority > nbpj->priority)
+            {
+              list_delete_node (candidate_list, j);
+              continue;
+            }
+          else if (nbpi->priority < nbpj->priority)
+            {
+              list_delete_node (candidate_list, i);
+              continue;
+            }
+          else /* equal, case of tie */
+            {
+              if (nbpi->router_id > nbpj->router_id)
+                {
+                  list_delete_node (candidate_list, j);
+                  continue;
+                }
+              else if (nbpi->router_id < nbpj->router_id)
+                {
+                  list_delete_node (candidate_list, i);
+                  continue;
+                }
+              else
+                {
+                  zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR");
+                  zlog_warn ("!!!MISCONFIGURATION?");
+                  list_delete_node (candidate_list, i);
+                  continue;
+                }
+            }
+        }
+      if (!list_isempty (candidate_list))
+        {
+          assert (candidate_list->count == 1);
+          n = listhead (candidate_list);
+          nbr = (struct ospf6_neighbor *)getdata (n);
+          dr = nbr->router_id;
+        }
+      else
+        assert (0);
+    }
+
+/* step_four: */
+
+  if (gofive)
+    goto step_five;
+
+  if (dr != prevdr)
+    {
+      if ((dr == myself.router_id || prevdr == myself.router_id)
+          && !(dr == myself.router_id && prevdr == myself.router_id))
+        {
+          myself.dr = dr;
+          myself.bdr = bdr;
+          gofive++;
+          goto step_two;
+        }
+    }
+  if (bdr != prevbdr)
+    {
+      if ((bdr == myself.router_id || prevbdr == myself.router_id)
+          && !(bdr == myself.router_id && prevbdr == myself.router_id))
+        {
+          myself.dr = dr;
+          myself.bdr = bdr;
+          gofive++;
+          goto step_two;
+        }
+    }
+
+step_five:
+
+  ospf6_interface->dr = dr;
+  ospf6_interface->bdr = bdr;
+
+  if (prevdr != dr || prevbdr != bdr)
+    {
+      for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
+        {
+          nbpi = getdata (i);
+          if (nbpi->state < NBS_TWOWAY)
+            continue;
+          /* Schedule or Execute AdjOK. which does "invoke" mean? */
+          thread_add_event (master, adj_ok, nbpi, 0);
+        }
+    }
+
+  list_delete (candidate_list);
+
+  if (dr == myself.router_id)
+    {
+      assert (bdr != myself.router_id);
+      return IFS_DR;
+    }
+  else if (bdr == myself.router_id)
+    {
+      assert (dr != myself.router_id);
+      return IFS_BDR;
+    }
+  else
+    return IFS_DROTHER;
+}
+
+
diff --git a/ospf6d/ospf6_ism.h b/ospf6d/ospf6_ism.h
new file mode 100644 (file)
index 0000000..12470d9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_ISM_H
+#define OSPF6_ISM_H
+
+/* interface state */
+#define IFS_NONE     0
+#define IFS_DOWN     1
+#define IFS_LOOPBACK 2
+#define IFS_WAITING  3
+#define IFS_PTOP     4
+#define IFS_DROTHER  5
+#define IFS_BDR      6
+#define IFS_DR       7
+#define IFS_MAX      8
+
+\f
+
+/* Function Prototypes */
+/* interface event */
+int interface_up (struct thread *);
+int interface_down (struct thread *);
+int wait_timer (struct thread *);
+int backup_seen (struct thread *);
+int neighbor_change (struct thread *);
+
+
+#include "ospf6_types.h"
+
+int dr_change (struct ospf6_interface *);
+int ifs_change (state_t, char *, struct ospf6_interface *);
+
+#endif /* OSPF6_ISM_H */
+
diff --git a/ospf6d/ospf6_linklist.c b/ospf6d/ospf6_linklist.c
new file mode 100644 (file)
index 0000000..8c17935
--- /dev/null
@@ -0,0 +1,193 @@
+
+#include <zebra.h>
+
+#include "ospf6_linklist.h"
+
+static struct linklist_node *
+linklist_lookup_node (void *data, struct linklist *linklist)
+{
+  struct linklist_node *node;
+
+  for (node = linklist->head; node; node = node->next)
+    {
+      if (linklist->cmp && (*linklist->cmp) (node->data, data) == 0)
+        return node;
+      if (node->data == data)
+        return node;
+    }
+
+  return NULL;
+}
+
+void *
+linklist_lookup (void *data, struct linklist *linklist)
+{
+  struct linklist_node *node;
+
+  node = linklist_lookup_node (data, linklist);
+  if (node)
+    return node->data;
+  return NULL;
+}
+
+int
+linklist_add (void *data, struct linklist *linklist)
+{
+  struct linklist_node *node = NULL, *add;
+
+  if (linklist_lookup_node (data, linklist))
+    return -1;
+
+  add = malloc (sizeof (struct linklist_node));
+  if (add == NULL)
+    return -1;
+  memset (add, 0, sizeof (struct linklist_node));
+  add->data = data;
+
+  if (linklist->cmp)
+    {
+      for (node = linklist->head; node; node = node->next)
+        {
+          if ((*linklist->cmp) (node->data, add->data) > 0)
+            break;
+        }
+    }
+
+  if (! node)
+    {
+      /* add to tail */
+      if (linklist->tail)
+        {
+          linklist->tail->next = add;
+          add->prev = linklist->tail;
+        }
+      else
+        {
+          linklist->head = add;
+          add->prev = NULL;
+        }
+
+      linklist->tail = add;
+      add->next = NULL;
+    }
+  else
+    {
+      /* insert just before 'node' */
+      if (node->prev)
+        {
+          node->prev->next = add;
+          add->prev = node->prev;
+        }
+      else
+        {
+          linklist->head = add;
+          add->prev = NULL;
+        }
+
+      add->next = node;
+      node->prev = add;
+    }
+
+  linklist->count++;
+  return 0;
+}
+
+int
+linklist_remove (void *data, struct linklist *linklist)
+{
+  struct linklist_node *rem;
+
+  rem = linklist_lookup_node (data, linklist);
+  if (rem == NULL)
+    return -1;
+
+  if (rem->prev)
+    rem->prev->next = rem->next;
+  else
+    linklist->head = rem->next;
+
+  if (rem->next)
+    rem->next->prev = rem->prev;
+  else
+    linklist->tail = rem->prev;
+
+  free (rem);
+  linklist->count--;
+  return 0;
+}
+
+void
+linklist_head (struct linklist *linklist, struct linklist_node *node)
+{
+  if (linklist->head == NULL)
+    {
+      node->prev = NULL;
+      node->next = NULL;
+      node->data = NULL;
+      return;
+    }
+
+  node->prev = linklist->head->prev;
+  node->next = linklist->head->next;
+  node->data = linklist->head->data;
+}
+
+int
+linklist_end (struct linklist_node *node)
+{
+  if (node->data == NULL && node->next == NULL)
+    return 1;
+  return 0;
+}
+
+void
+linklist_next (struct linklist_node *node)
+{
+  if (node->next == NULL)
+    {
+      node->prev = NULL;
+      node->next = NULL;
+      node->data = NULL;
+      return;
+    }
+
+  node->data = node->next->data;
+  node->prev = node->next->prev;
+  node->next = node->next->next;
+}
+
+struct linklist *
+linklist_create ()
+{
+  struct linklist *linklist;
+
+  linklist = malloc (sizeof (struct linklist));
+  if (linklist == NULL)
+    return NULL;
+  memset (linklist, 0, sizeof (struct linklist));
+
+  return linklist;
+}
+
+void
+linklist_remove_all (struct linklist *linklist)
+{
+  struct linklist_node node;
+
+  for (linklist_head (linklist, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    linklist_remove (node.data, linklist);
+}
+
+void
+linklist_delete (struct linklist *linklist)
+{
+  linklist_remove_all (linklist);
+  assert (linklist->count == 0);
+  assert (linklist->head == NULL);
+  assert (linklist->tail == NULL);
+
+  free (linklist);
+}
+
+
diff --git a/ospf6d/ospf6_linklist.h b/ospf6d/ospf6_linklist.h
new file mode 100644 (file)
index 0000000..6d97899
--- /dev/null
@@ -0,0 +1,35 @@
+
+#ifndef _LINKLIST_H_
+#define _LINKLIST_H_
+
+struct linklist_node
+{
+  struct linklist_node *prev;
+  struct linklist_node *next;
+
+  void *data;
+};
+
+struct linklist
+{
+  int count;
+  struct linklist_node *head;
+  struct linklist_node *tail;
+
+  int    (*cmp) (void *, void *);
+};
+
+void *linklist_lookup (void *data, struct linklist *linklist);
+int   linklist_add (void *data, struct linklist *linklist);
+int   linklist_remove (void *data, struct linklist *linklist);
+void  linklist_remove_all (struct linklist *linklist);
+
+void linklist_head (struct linklist *linklist, struct linklist_node *node);
+int  linklist_end (struct linklist_node *node);
+void linklist_next (struct linklist_node *node);
+
+struct linklist *linklist_create ();
+void linklist_delete (struct linklist *);
+
+#endif /*_LINKLIST_H_*/
+
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
new file mode 100644 (file)
index 0000000..b14979f
--- /dev/null
@@ -0,0 +1,1926 @@
+/*
+ * LSA function
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* Include other stuffs */
+#include "version.h"
+#include "log.h"
+#include "getopt.h"
+#include "linklist.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "if.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "filter.h"
+#include "zclient.h"
+#include "table.h"
+#include "plist.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_dump.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_ism.h"
+#include "ospf6_nsm.h"
+#include "ospf6_dbex.h"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* test LSAs identity */
+static int
+ospf6_lsa_issame (struct ospf6_lsa_header__ *lsh1,
+                  struct ospf6_lsa_header__ *lsh2)
+{
+  assert (lsh1 && lsh2);
+
+  if (lsh1->adv_router != lsh2->adv_router)
+    return 0;
+
+  if (lsh1->id != lsh2->id)
+    return 0;
+
+  if (lsh1->type != lsh2->type)
+    return 0;
+
+  return 1;
+}
+
+/* RFC2328: Section 13.2 */
+int
+ospf6_lsa_differ (struct ospf6_lsa *lsa1,
+                  struct ospf6_lsa *lsa2)
+{
+  int diff, cmplen;
+
+  if (! ospf6_lsa_issame (lsa1->header, lsa2->header))
+    return 1;
+
+  /* check Options field */
+  /* xxx */
+
+  ospf6_lsa_age_current (lsa1);
+  ospf6_lsa_age_current (lsa2);
+  if (ntohs (lsa1->header->age) == MAXAGE &&
+      ntohs (lsa2->header->age) != MAXAGE)
+    return 1;
+  if (ntohs (lsa1->header->age) != MAXAGE &&
+      ntohs (lsa2->header->age) == MAXAGE)
+    return 1;
+
+  /* compare body */
+  if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length))
+    return 1;
+
+  cmplen = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header);
+  diff = memcmp (lsa1->header + 1, lsa2->header + 1, cmplen);
+
+  return diff;
+}
+
+int
+ospf6_lsa_match (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                 struct ospf6_lsa_header *lsh)
+{
+  if (lsh->advrtr != adv_router)
+    return 0;
+
+  if (lsh->ls_id != id)
+    return 0;
+
+  if (lsh->type != type)
+    return 0;
+
+  return 1;
+}
+
+/* ospf6 age functions */
+/* calculate birth and set expire timer */
+static void
+ospf6_lsa_age_set (struct ospf6_lsa *lsa)
+{
+  struct timeval now;
+
+  assert (lsa && lsa->header);
+
+  if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+    zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s",
+               strerror (errno));
+
+  lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
+  lsa->birth.tv_usec = now.tv_usec;
+  if (ntohs (lsa->header->age) != MAXAGE)
+    lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
+                                    lsa->birth.tv_sec + MAXAGE - now.tv_sec);
+  else
+    lsa->expire = NULL;
+  return;
+}
+
+/* this function calculates current age from its birth,
+   then update age field of LSA header. return value is current age */
+u_int16_t
+ospf6_lsa_age_current (struct ospf6_lsa *lsa)
+{
+  struct timeval now;
+  u_int32_t ulage;
+  u_int16_t age;
+
+  assert (lsa);
+  assert (lsa->header);
+
+  /* current time */
+  if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+    zlog_warn ("LSA: gettimeofday failed, may fail ages: %s",
+               strerror (errno));
+
+  /* calculate age */
+  ulage = now.tv_sec - lsa->birth.tv_sec;
+
+  /* if over MAXAGE, set to it */
+  if (ulage > MAXAGE)
+    age = MAXAGE;
+  else
+    age = ulage;
+
+  lsa->header->age = htons (age);
+  return age;
+}
+
+/* update age field of LSA header with adding InfTransDelay */
+void
+ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay)
+{
+  unsigned short age;
+
+  age = ospf6_lsa_age_current (lsa) + transdelay;
+  if (age > MAXAGE)
+    age = MAXAGE;
+  lsa->header->age = htons (age);
+  return;
+}
+
+void
+ospf6_lsa_premature_aging (struct ospf6_lsa *lsa)
+{
+  /* log */
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: Premature aging: %s", lsa->str);
+
+  if (lsa->expire)
+    thread_cancel (lsa->expire);
+  lsa->expire = (struct thread *) NULL;
+  if (lsa->refresh)
+    thread_cancel (lsa->refresh);
+  lsa->refresh = (struct thread *) NULL;
+
+  memset (&lsa->birth, 0, sizeof (struct timeval));
+  thread_execute (master, ospf6_lsa_expire, lsa, 0);
+}
+
+/* check which is more recent. if a is more recent, return -1;
+   if the same, return 0; otherwise(b is more recent), return 1 */
+int
+ospf6_lsa_check_recent (struct ospf6_lsa *a, struct ospf6_lsa *b)
+{
+  signed long seqnuma, seqnumb;
+  u_int16_t cksuma, cksumb;
+  u_int16_t agea, ageb;
+
+  assert (a && a->header);
+  assert (b && b->header);
+  assert (ospf6_lsa_issame (a->header, b->header));
+
+  seqnuma = ((signed long) ntohl (a->header->seqnum))
+             - (signed long) INITIAL_SEQUENCE_NUMBER;
+  seqnumb = ((signed long) ntohl (b->header->seqnum))
+             - (signed long) INITIAL_SEQUENCE_NUMBER;
+
+  /* compare by sequence number */
+    /* xxx, care about LS sequence number wrapping */
+  recent_reason = "seqnum";
+  if (seqnuma > seqnumb)
+    return -1;
+  else if (seqnuma < seqnumb)
+    return 1;
+
+  /* Checksum */
+  cksuma = ntohs (a->header->checksum);
+  cksumb = ntohs (b->header->checksum);
+  if (cksuma > cksumb)
+    return -1;
+  if (cksuma < cksumb)
+    return 0;
+
+  /* Age check */
+  agea = ospf6_lsa_age_current (a);
+  ageb = ospf6_lsa_age_current (b);
+
+    /* MaxAge check */
+  recent_reason = "max age";
+  if (agea == OSPF6_LSA_MAXAGE && ageb != OSPF6_LSA_MAXAGE)
+    return -1;
+  else if (agea != OSPF6_LSA_MAXAGE && ageb == OSPF6_LSA_MAXAGE)
+    return 1;
+
+  recent_reason = "age differ";
+  if (agea > ageb && agea - ageb >= OSPF6_LSA_MAXAGEDIFF)
+    return 1;
+  else if (agea < ageb && ageb - agea >= OSPF6_LSA_MAXAGEDIFF)
+    return -1;
+
+  /* neither recent */
+  recent_reason = "the same instance";
+  return 0;
+}
+
+int
+ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header)
+{
+  int ldnum = 0;
+  u_int16_t len;
+
+  len = ntohs (lsa_header->length);
+  len -= sizeof (struct ospf6_lsa_header);
+  if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+    {
+      len -= sizeof (struct ospf6_router_lsa);
+      ldnum = len / sizeof (struct ospf6_router_lsd);
+    }
+  else /* (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK)) */
+    {
+      len -= sizeof (struct ospf6_network_lsa);
+      ldnum = len / sizeof (u_int32_t);
+    }
+
+  return ldnum;
+}
+
+void *
+ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header)
+{
+  void *p;
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsd *router_lsd;
+  struct ospf6_network_lsa *network_lsa;
+  struct ospf6_network_lsd *network_lsd;
+
+  if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+    {
+      router_lsa = (struct ospf6_router_lsa *) (lsa_header + 1);
+      router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
+      router_lsd += index;
+      p = (void *) router_lsd;
+    }
+  else if (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+    {
+      network_lsa = (struct ospf6_network_lsa *) (lsa_header + 1);
+      network_lsd = (struct ospf6_network_lsd *) (network_lsa + 1);
+      network_lsd += index;
+      p = (void *) network_lsd;
+    }
+  else
+    {
+      p = (void *) NULL;
+    }
+
+  return p;
+}
+
+/* network_lsd <-> router_lsd */
+static int
+ospf6_lsa_lsd_network_reference_match (struct ospf6_network_lsd *network_lsd1,
+                                       struct ospf6_lsa_header *lsa_header1,
+                                       struct ospf6_router_lsd *router_lsd2,
+                                       struct ospf6_lsa_header *lsa_header2)
+{
+  if (network_lsd1->adv_router != lsa_header2->advrtr)
+    return 0;
+  if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+    return 0;
+  if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
+    return 0;
+  if (router_lsd2->neighbor_interface_id != lsa_header1->ls_id)
+    return 0;
+  return 1;
+}
+
+/* router_lsd <-> router_lsd */
+static int
+ospf6_lsa_lsd_router_reference_match (struct ospf6_router_lsd *router_lsd1,
+                                      struct ospf6_lsa_header *lsa_header1,
+                                      struct ospf6_router_lsd *router_lsd2,
+                                      struct ospf6_lsa_header *lsa_header2)
+{
+  if (router_lsd1->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+    return 0;
+  if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+    return 0;
+  if (router_lsd1->neighbor_router_id != lsa_header2->advrtr)
+    return 0;
+  if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
+    return 0;
+  if (router_lsd1->neighbor_interface_id != router_lsd2->interface_id)
+    return 0;
+  if (router_lsd2->neighbor_interface_id != router_lsd1->interface_id)
+    return 0;
+  return 1;
+}
+
+int
+ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
+                           int index2, struct ospf6_lsa_header *lsa_header2)
+{
+  struct ospf6_router_lsd *r1, *r2;
+  struct ospf6_network_lsd *n;
+
+  r1 = (struct ospf6_router_lsd *) NULL;
+  r2 = (struct ospf6_router_lsd *) NULL;
+  n = (struct ospf6_network_lsd *) NULL;
+  if (lsa_header1->type == htons (OSPF6_LSA_TYPE_ROUTER))
+    r1 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
+  else
+    n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
+
+  if (lsa_header2->type == htons (OSPF6_LSA_TYPE_ROUTER))
+    r2 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
+  else
+    n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
+
+  if (r1 && r2)
+    return ospf6_lsa_lsd_router_reference_match (r1, lsa_header1,
+                                                 r2, lsa_header2);
+  else if (r1 && n)
+    return ospf6_lsa_lsd_network_reference_match (n, lsa_header2,
+                                                  r1, lsa_header1);
+  else if (n && r2)
+    return ospf6_lsa_lsd_network_reference_match (n, lsa_header1,
+                                                 r2, lsa_header2);
+  return 0;
+}
+
+void
+ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char adv_router[64], id[64], type[32];
+
+  assert (lsa);
+  assert (lsa->header);
+
+  ospf6_lsa_type_string (lsa->header->type, type, sizeof (type));
+  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+  inet_ntop (AF_INET, &lsa->header->adv_router,
+             adv_router, sizeof (adv_router));
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+  vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa),
+           type, VTY_NEWLINE);
+  vty_out (vty, "Link State ID: %s%s", id, VTY_NEWLINE);
+  vty_out (vty, "Advertising Router: %s%s", adv_router, VTY_NEWLINE);
+  vty_out (vty, "LS Sequence Number: %#lx%s", (u_long)ntohl (lsa->header->seqnum),
+           VTY_NEWLINE);
+  vty_out (vty, "CheckSum: %#hx Length: %hu%s", ntohs (lsa->header->checksum),
+           ntohs (lsa->header->length), VTY_NEWLINE);
+
+  {
+    struct ospf6_lsa_slot *slot;
+    slot = ospf6_lsa_slot_get (lsa->header->type);
+    if (slot)
+      {
+        (*slot->func_show) (vty, lsa);
+        vty_out (vty, "%s", VTY_NEWLINE);
+        return;
+      }
+  }
+
+  vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary_header (struct vty *vty)
+{
+  vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s",
+           "Type", "LSId", "AdvRouter", "Age", "SeqNum",
+           "Cksm", "Len", "Duration", VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char adv_router[16], id[16], type[16];
+  struct timeval now, res;
+  char duration[16];
+
+  assert (lsa);
+  assert (lsa->header);
+
+  memset (type, 0, sizeof (type));
+  ospf6_lsa_type_string (lsa->header->type, type, 13);
+  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+  inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
+             sizeof (adv_router));
+
+  gettimeofday (&now, NULL);
+  ospf6_timeval_sub (&now, &lsa->installed, &res);
+  ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+  vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s",
+           type, id, adv_router, ospf6_lsa_age_current (lsa),
+           (u_long) ntohl (lsa->header->seqnum),
+           ntohs (lsa->header->checksum), ntohs (lsa->header->length),
+           duration, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  u_char *start, *end, *current;
+  char byte[4];
+
+  start = (char *) lsa->header;
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+  vty_out (vty, "%s:%s", lsa->str, VTY_NEWLINE);
+
+  for (current = start; current < end; current ++)
+    {
+      if ((current - start) % 16 == 0)
+        vty_out (vty, "%s        ", VTY_NEWLINE);
+      else if ((current - start) % 4 == 0)
+        vty_out (vty, " ");
+
+      snprintf (byte, sizeof (byte), "%02x", *current);
+      vty_out (vty, "%s", byte);
+    }
+
+  vty_out (vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+/* OSPFv3 LSA creation/deletion function */
+
+/* calculate LS sequence number for my new LSA.
+   return value is network byte order */
+static signed long
+ospf6_lsa_seqnum_new (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                      void *scope)
+{
+  struct ospf6_lsa *lsa;
+  signed long seqnum;
+
+  /* get current database copy */
+  lsa = ospf6_lsdb_lookup (type, id, adv_router, scope);
+
+  /* if current database copy not found, return InitialSequenceNumber */
+  if (!lsa)
+    seqnum = INITIAL_SEQUENCE_NUMBER;
+  else
+    seqnum = (signed long) ntohl (lsa->header->seqnum) + 1;
+
+  return (htonl (seqnum));
+}
+
+#if 0
+static void
+ospf6_lsa_header_set (u_int16_t type, u_int32_t ls_id, u_int32_t advrtr,
+                      struct ospf6_lsa_header *lsa_header, int bodysize)
+{
+  /* fill LSA header */
+  lsa_header->age = 0;
+  lsa_header->type = type;
+  lsa_header->ls_id = ls_id;
+  lsa_header->advrtr = advrtr;
+  lsa_header->seqnum =
+    ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
+                          lsa_header->advrtr);
+  lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + bodysize);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+}
+#endif /*0*/
+
+struct ospf6_lsa *
+ospf6_lsa_create (struct ospf6_lsa_header *source)
+{
+  struct ospf6_lsa *lsa = NULL;
+  struct ospf6_lsa_header *lsa_header = NULL;
+  u_int16_t lsa_size = 0;
+  char buf_router[16], buf_id[16], typebuf[32];
+
+  /* whole length of this LSA */
+  lsa_size = ntohs (source->length);
+
+  /* allocate memory for this LSA */
+  lsa_header = (struct ospf6_lsa_header *)
+    XMALLOC (MTYPE_OSPF6_LSA, lsa_size);
+  if (! lsa_header)
+    {
+      zlog_err ("Can't allocate memory for LSA Header");
+      return (struct ospf6_lsa *) NULL;
+    }
+  memset (lsa_header, 0, lsa_size);
+
+  /* copy LSA from source */
+  memcpy (lsa_header, source, lsa_size);
+
+  /* LSA information structure */
+  /* allocate memory */
+  lsa = (struct ospf6_lsa *)
+          XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa));
+  memset (lsa, 0, sizeof (struct ospf6_lsa));
+
+  lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
+  lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
+
+  lsa->summary = 0; /* this is not LSA summary */
+
+  /* dump string */
+  inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
+  inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
+             sizeof (buf_router));
+  snprintf (lsa->str, sizeof (lsa->str), "[%s ID=%s Adv=%s]",
+            ospf6_lsa_type_string (lsa_header->type, typebuf,
+                                   sizeof (typebuf)),
+            buf_id, buf_router);
+
+  /* calculate birth, expire and refresh of this lsa */
+  ospf6_lsa_age_set (lsa);
+
+#ifdef DEBUG
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+  return lsa;
+}
+
+struct ospf6_lsa *
+ospf6_lsa_summary_create (struct ospf6_lsa_header__ *source)
+{
+  struct ospf6_lsa *lsa = NULL;
+  struct ospf6_lsa_header *lsa_header = NULL;
+  u_int16_t lsa_size = 0;
+  char buf_router[16], buf_id[16], typebuf[16];
+
+  /* LSA summary contains LSA Header only */
+  lsa_size = sizeof (struct ospf6_lsa_header);
+
+  /* allocate memory for this LSA */
+  lsa_header = (struct ospf6_lsa_header *)
+    XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, lsa_size);
+  memset (lsa_header, 0, lsa_size);
+
+  /* copy LSA from source */
+  memcpy (lsa_header, source, lsa_size);
+
+  /* LSA information structure */
+  /* allocate memory */
+  lsa = (struct ospf6_lsa *)
+          XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, sizeof (struct ospf6_lsa));
+  memset (lsa, 0, sizeof (struct ospf6_lsa));
+
+  lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
+  lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
+  lsa->summary = 1; /* this is LSA summary */
+
+  /* dump string */
+  inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
+  inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
+             sizeof (buf_router));
+  snprintf (lsa->str, sizeof (lsa->str), "[%s Summary ID=%s Adv=%s]",
+            ospf6_lsa_type_string (lsa->header->type, typebuf,
+                                   sizeof (typebuf)),
+            buf_id, buf_router);
+
+  /* calculate birth, expire and refresh of this lsa */
+  ospf6_lsa_age_set (lsa);
+
+#ifdef DEBUG
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+  return lsa;
+}
+
+void
+ospf6_lsa_delete (struct ospf6_lsa *lsa)
+{
+  /* just to make sure */
+  if (lsa->lock != 0)
+    {
+      zlog_err ("Can't delete %s: lock: %ld", lsa->str, lsa->lock);
+      return;
+    }
+
+  /* cancel threads */
+  if (lsa->expire)
+    thread_cancel (lsa->expire);
+  lsa->expire = (struct thread *) NULL;
+  if (lsa->refresh)
+    thread_cancel (lsa->refresh);
+  lsa->refresh = (struct thread *) NULL;
+
+#ifdef DEBUG
+  if (IS_OSPF6_DUMP_LSA)
+      zlog_info ("Delete %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+  /* do free */
+  if (lsa->summary)
+    XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa->header);
+  else
+    XFREE (MTYPE_OSPF6_LSA, lsa->header);
+  lsa->header = NULL;
+
+  if (lsa->summary)
+    XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa);
+  else
+    XFREE (MTYPE_OSPF6_LSA, lsa);
+}
+
+/* increment reference counter of  struct ospf6_lsa */
+void
+ospf6_lsa_lock (struct ospf6_lsa *lsa)
+{
+  lsa->lock++;
+  return;
+}
+
+/* decrement reference counter of  struct ospf6_lsa */
+void
+ospf6_lsa_unlock (struct ospf6_lsa *lsa)
+{
+  /* decrement reference counter */
+  if (lsa->lock > 0)
+    lsa->lock--;
+  else
+    zlog_warn ("Can't unlock %s: already no lock", lsa->str);
+
+  if (lsa->lock == 0)
+    ospf6_lsa_delete (lsa);
+}
+
+void
+ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                     char *data, int data_len, void *scope)
+{
+  char buffer[MAXLSASIZE];
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsa *old;
+
+  assert (data_len <= sizeof (buffer) - sizeof (struct ospf6_lsa_header));
+
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+
+  /* Copy LSA Body */
+  memcpy (buffer + sizeof (struct ospf6_lsa_header), data, data_len);
+
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = type;
+  lsa_header->ls_id = id;
+  lsa_header->advrtr = adv_router;
+  lsa_header->seqnum =
+    ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
+                          lsa_header->advrtr, scope);
+  lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + data_len);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+
+  /* create LSA */
+  lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer);
+  lsa->scope = scope;
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
+                           lsa->header->adv_router, lsa->scope);
+  if (old)
+    {
+      /* Check if this is neither different instance nor refresh, return */
+      if (! CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH) &&
+          ! ospf6_lsa_differ (lsa, old))
+        {
+          if (IS_OSPF6_DUMP_LSA)
+            zlog_info ("LSA: Suppress updating %s", lsa->str);
+          ospf6_lsa_delete (lsa);
+          return;
+        }
+    }
+
+  lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
+                                   OSPF6_LS_REFRESH_TIME);
+  gettimeofday (&lsa->originated, NULL);
+
+  //if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: originate %s seq: %#x age: %hu %ld.%06ld",
+               lsa->str, ntohl (lsa->header->seqnum),
+               ospf6_lsa_age_current (lsa),
+               lsa->originated.tv_sec, lsa->originated.tv_usec);
+
+  ospf6_dbex_remove_from_all_retrans_list (lsa);
+  ospf6_dbex_flood (lsa, NULL);
+  ospf6_lsdb_install (lsa);
+}
+
+\f
+/* ospf6_lsa expired */
+int
+ospf6_lsa_expire (struct thread *thread)
+{
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsdb *lsdb = NULL;
+  void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+
+  lsa = (struct ospf6_lsa *) THREAD_ARG (thread);
+  assert (lsa && lsa->lsa_hdr);
+
+  /* assertion */
+  assert (IS_LSA_MAXAGE (lsa));
+  assert (!lsa->refresh);
+
+  lsa->expire = (struct thread *) NULL;
+
+  /* log */
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: Expire: %s", lsa->str);
+
+  if (!lsa->summary)
+    {
+      /* reflood lsa */
+      ospf6_dbex_flood (lsa, NULL);
+
+      /* get scoped lsdb, call remove hook */
+      if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa->header->type)))
+        lsdb = ((struct ospf6_interface *) lsa->scope)->lsdb;
+      else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa->header->type)))
+        lsdb = ((struct ospf6_area *) lsa->scope)->lsdb;
+      else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa->header->type)))
+        lsdb = ((struct ospf6 *) lsa->scope)->lsdb;
+      else
+        assert (0);
+
+      /* call LSDB hook to re-process LSA */
+      hook = ospf6_lsdb_hook[ntohs (lsa->header->type) &
+                             OSPF6_LSTYPE_CODE_MASK].hook;
+      if (hook)
+        (*hook) (NULL, lsa);
+
+      /* do not free LSA, and do nothing about lslists.
+         wait event (ospf6_lsdb_check_maxage) */
+    }
+
+  return 0;
+}
+
+int
+ospf6_lsa_refresh (struct thread *thread)
+{
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsa_slot *slot;
+
+  assert (thread);
+  lsa = (struct ospf6_lsa *) THREAD_ARG  (thread);
+  assert (lsa && lsa->lsa_hdr);
+
+  /* this will be used later as flag to decide really originate */
+  lsa->refresh = (struct thread *) NULL;
+  SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_REFRESH);
+
+  /* log */
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA Refresh: %s", lsa->str);
+
+  slot = ospf6_lsa_slot_get (lsa->header->type);
+  if (slot)
+    {
+      zlog_info ("LSA Refresh: %s", slot->name);
+      (*slot->func_refresh) (lsa);
+      return 0;
+    }
+
+  zlog_warn ("Can't Refresh LSA: Unknown type: %#x",
+             ntohs (lsa->header->type));
+  return 1;
+}
+
+\f
+
+/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */
+#define MODX                4102
+#define LSA_CHECKSUM_OFFSET   15
+
+unsigned short
+ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header)
+{
+  u_char *sp, *ep, *p, *q;
+  int c0 = 0, c1 = 0;
+  int x, y;
+  u_int16_t length;
+
+  lsa_header->checksum = 0;
+  length = ntohs (lsa_header->length) - 2;
+  sp = (char *) &lsa_header->type;
+
+  for (ep = sp + length; sp < ep; sp = q)
+    {
+      q = sp + MODX;
+      if (q > ep)
+        q = ep;
+      for (p = sp; p < q; p++)
+        {
+          c0 += *p;
+          c1 += c0;
+        }
+      c0 %= 255;
+      c1 %= 255;
+    }
+
+  /* r = (c1 << 8) + c0; */
+  x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
+  if (x <= 0)
+    x += 255;
+  y = 510 - c0 - x;
+  if (y > 255)
+    y -= 255;
+
+  lsa_header->checksum = htons ((x << 8) + y);
+
+  return (lsa_header->checksum);
+}
+
+int
+ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header)
+{
+  struct ospf6_lsa_slot *slot;
+
+  slot = ospf6_lsa_slot_get (lsa_header->type);
+  if (slot)
+    return 1;
+  return 0;
+}
+
+struct ospf6_lsa_slot *slot_head = NULL;
+
+struct ospf6_lsa_slot *
+ospf6_lsa_slot_get (u_int16_t type)
+{
+  struct ospf6_lsa_slot *slot;
+
+  for (slot = slot_head; slot; slot = slot->next)
+    {
+      if (slot->type == type)
+        return slot;
+    }
+
+  return NULL;
+}
+
+int
+ospf6_lsa_slot_register (struct ospf6_lsa_slot *src)
+{
+  struct ospf6_lsa_slot *new, *slot;
+
+  slot = ospf6_lsa_slot_get (src->type);
+  if (slot)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("LSA: Slot register: already exists: %#x %s",
+                   slot->type, slot->name);
+      return -1;
+    }
+
+  new = (struct ospf6_lsa_slot *)
+    XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_slot));
+  if (! new)
+    {
+      zlog_err ("Can't allocate memory for LSA slot: %s", strerror (errno));
+      return -1;
+    }
+  memset (new, 0, sizeof (struct ospf6_lsa_slot));
+  memcpy (new, src, sizeof (struct ospf6_lsa_slot));
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: Slot register: %#x %s", slot->type, slot->name);
+
+  if (slot_head == NULL)
+    {
+      new->prev = NULL;
+      new->next = NULL;
+      slot_head = new;
+      return 0;
+    }
+
+  slot = slot_head;
+  while (slot->next)
+    slot = slot->next;
+
+  slot->next = new;
+  new->prev = slot;
+
+  return 0;
+}
+
+int
+ospf6_lsa_slot_unregister (u_int16_t type)
+{
+  struct ospf6_lsa_slot *slot;
+
+  slot = ospf6_lsa_slot_get (type);
+  if (slot == NULL)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("Registering LSA slot: no such slot: %#x", type);
+      return -1;
+    }
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("Unregistering LSA Slot: %#x %s", slot->type, slot->name);
+
+  if (slot->prev)
+    slot->prev->next = slot->next;
+  if (slot->next)
+    slot->next->prev = slot->prev;
+
+  if (slot_head == slot)
+    slot_head = slot->next;
+
+  XFREE (MTYPE_OSPF6_LSA, slot);
+  return 0;
+}
+
+char *
+ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize)
+{
+  struct ospf6_lsa_slot *slot;
+
+  slot = ospf6_lsa_slot_get (type);
+  if (slot)
+    snprintf (buf, bufsize, "%s", slot->name);
+  else
+    snprintf (buf, bufsize, "Type=0x%04x", ntohs (type));
+
+  return buf;
+}
+
+\f
+/*******************/
+/* LSA Origination */
+/*******************/
+
+#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
+  if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_LSA)\
+        zlog_info ("  Filter out Linklocal: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
+  if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_LSA)\
+        zlog_info ("  Filter out Unspecified: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
+  if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_LSA)\
+        zlog_info ("  Filter out Loopback: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
+  if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_LSA)\
+        zlog_info ("  Filter out V4Compat: %s", buf);\
+      continue;\
+    }
+
+#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
+  if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
+    {\
+      char buf[64];\
+      prefix2str (addr, buf, sizeof (buf));\
+      if (IS_OSPF6_DUMP_LSA)\
+        zlog_info ("  Filter out V4Mapped: %s", buf);\
+      continue;\
+    }
+
+/******************************/
+/* RFC2740 3.4.3.1 Router-LSA */
+/******************************/
+
+char *
+ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size)
+{
+  char w, v, e, b;
+
+  w = (router_bits & OSPF6_ROUTER_LSA_BIT_W ? 'W' : '-');
+  v = (router_bits & OSPF6_ROUTER_LSA_BIT_V ? 'V' : '-');
+  e = (router_bits & OSPF6_ROUTER_LSA_BIT_E ? 'E' : '-');
+  b = (router_bits & OSPF6_ROUTER_LSA_BIT_B ? 'B' : '-');
+  snprintf (buf, size, "----%c%c%c%c", w, v, e, b);
+  return buf;
+}
+
+int
+ospf6_lsa_router_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char *start, *end, *current;
+  char buf[32], name[32], bits[32], options[32];
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsd *lsdesc;
+
+  assert (lsa->header);
+
+  router_lsa = (struct ospf6_router_lsa *)
+    ((char *) lsa->header + sizeof (struct ospf6_lsa_header));
+
+  ospf6_lsa_router_bits_string (router_lsa->bits, bits, sizeof (bits));
+  ospf6_options_string (router_lsa->options, options, sizeof (options));
+  vty_out (vty, "    Bits: %s Options: %s%s", bits, options, VTY_NEWLINE);
+
+  start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+  for (current = start; current + sizeof (struct ospf6_router_lsd) <= end;
+       current += sizeof (struct ospf6_router_lsd))
+    {
+      lsdesc = (struct ospf6_router_lsd *) current;
+
+      if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+        snprintf (name, sizeof (name), "Point-To-Point");
+      else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+        snprintf (name, sizeof (name), "Transit-Network");
+      else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK)
+        snprintf (name, sizeof (name), "Stub-Network");
+      else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK)
+        snprintf (name, sizeof (name), "Virtual-Link");
+      else
+        snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type);
+
+      vty_out (vty, "    Type: %s Metric: %d%s",
+               name, ntohs (lsdesc->metric), VTY_NEWLINE);
+      vty_out (vty, "    Interface ID: %s%s",
+               inet_ntop (AF_INET, &lsdesc->interface_id,
+                          buf, sizeof (buf)), VTY_NEWLINE);
+      vty_out (vty, "    Neighbor Interface ID: %s%s",
+               inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
+                          buf, sizeof (buf)), VTY_NEWLINE);
+      vty_out (vty, "    Neighbor Router ID: %s%s",
+               inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
+                          buf, sizeof (buf)), VTY_NEWLINE);
+    }
+  return 0;
+}
+
+u_long
+ospf6_lsa_has_elasped (u_int16_t type, u_int32_t id,
+                       u_int32_t adv_router, void *scope)
+{
+  struct ospf6_lsa *old;
+  struct timeval now;
+
+  if (adv_router != ospf6->router_id)
+    zlog_info ("LSA: Router-ID changed ?");
+
+  old = ospf6_lsdb_lookup (type, id, adv_router, scope);
+  if (! old)
+    return OSPF6_LSA_MAXAGE;
+
+  gettimeofday (&now, NULL);
+  return ((u_long) SEC_TVDIFF (&now, &old->originated));
+}
+
+int
+ospf6_lsa_originate_router (struct thread *thread)
+{
+  char buffer [MAXLSASIZE];
+  u_int16_t size;
+  struct ospf6_area *o6a;
+  int count;
+  u_int32_t area_id;
+
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsd *router_lsd;
+  listnode i;
+  struct ospf6_interface *o6i;
+  struct ospf6_neighbor *o6n = NULL;
+
+  area_id = (u_int32_t) THREAD_ARG (thread);
+
+  o6a = ospf6_area_lookup (area_id, ospf6);
+  if (! o6a)
+    {
+      inet_ntop (AF_INET, &area_id, buffer, sizeof (buffer));
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("LSA: Update Router-LSA: No such area: %s", buffer);
+      return 0;
+    }
+
+  /* clear thread */
+  o6a->thread_router_lsa = NULL;
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: originate Router-LSA for Area %s", o6a->str);
+
+  size = sizeof (struct ospf6_router_lsa);
+  memset (buffer, 0, sizeof (buffer));
+  router_lsa = (struct ospf6_router_lsa *) buffer;
+
+  OSPF6_OPT_CLEAR_ALL (router_lsa->options);
+  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
+  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
+  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
+  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
+  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
+  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
+
+  OSPF6_ROUTER_LSA_CLEAR_ALL_BITS (router_lsa);
+  OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_B);
+
+  if (ospf6_is_asbr (o6a->ospf6))
+    OSPF6_ROUTER_LSA_SET (router_lsa, OSPF6_ROUTER_LSA_BIT_E);
+  else
+    OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_E);
+
+  OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_V);
+  OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_W);
+
+  /* describe links for each interfaces */
+  router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
+  for (i = listhead (o6a->if_list); i; nextnode (i))
+    {
+      o6i = (struct ospf6_interface *) getdata (i);
+      assert (o6i);
+
+      /* Interfaces in state Down or Loopback are not described */
+      if (o6i->state == IFS_DOWN || o6i->state == IFS_LOOPBACK)
+        continue;
+
+      /* Nor are interfaces without any full adjacencies described */
+      count = 0;
+      o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+      if (count == 0)
+        continue;
+
+      /* Point-to-Point interfaces */
+      if (if_is_pointopoint (o6i->interface))
+        {
+          if (listcount (o6i->neighbor_list) == 0)
+            continue;
+
+          if (listcount (o6i->neighbor_list) != 1)
+            zlog_warn ("LSA: Multiple neighbors on PoinToPoint: %s",
+                       o6i->interface->name);
+
+          o6n = (struct ospf6_neighbor *)
+                   getdata (listhead (o6i->neighbor_list));
+          assert (o6n);
+
+          router_lsd->type = OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT;
+          router_lsd->metric = htons (o6i->cost);
+          router_lsd->interface_id = htonl (o6i->if_id);
+          router_lsd->neighbor_interface_id = htonl (o6n->ifid);
+          router_lsd->neighbor_router_id = o6n->router_id;
+
+          size += sizeof (struct ospf6_router_lsd);
+          router_lsd ++;
+
+          continue;
+        }
+
+      /* Broadcast and NBMA interfaces */
+      if (if_is_broadcast (o6i->interface))
+        {
+          /* If this router is not DR,
+             and If this router not fully adjacent with DR,
+             this interface is not transit yet: ignore. */
+          if (o6i->state != IFS_DR)
+            {
+              o6n = ospf6_neighbor_lookup (o6i->dr, o6i); /* find DR */
+              if (o6n == NULL || o6n->state != NBS_FULL)
+                continue;
+            }
+          else
+            {
+              count = 0;
+              o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+              if (count == 0)
+                continue;
+            }
+
+          router_lsd->type = OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK;
+          router_lsd->metric = htons (o6i->cost);
+          router_lsd->interface_id = htonl (o6i->if_id);
+          if (o6i->state != IFS_DR)
+            {
+              router_lsd->neighbor_interface_id = htonl (o6n->ifid);
+              router_lsd->neighbor_router_id = o6n->router_id;
+            }
+          else
+            {
+              router_lsd->neighbor_interface_id = htonl (o6i->if_id);
+              router_lsd->neighbor_router_id = o6i->area->ospf6->router_id;
+            }
+
+          size += sizeof (struct ospf6_router_lsd);
+          router_lsd ++;
+
+          continue;
+        }
+
+      /* Virtual links */
+        /* xxx */
+      /* Point-to-Multipoint interfaces */
+        /* xxx */
+    }
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_ROUTER),
+                       htonl (0), o6a->ospf6->router_id,
+                       (char *) router_lsa, size, o6a);
+  return 0;
+}
+
+void
+ospf6_lsa_schedule_router (struct ospf6_area *area)
+{
+  u_long elasped_time, time = 0;
+
+  if (area->thread_router_lsa)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("LSA: schedule: Router-LSA for Area %s: another thread",
+                   area->str);
+      return;
+    }
+
+  elasped_time =
+    ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_ROUTER), htonl (0),
+                           area->ospf6->router_id, area);
+  if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+    time = (u_long) (OSPF6_MIN_LS_INTERVAL - elasped_time);
+  else
+    time = 0;
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: schedule: Router-LSA for Area %s after %lu sec",
+               area->str, time);
+
+  if (time)
+    area->thread_router_lsa =
+      thread_add_timer (master, ospf6_lsa_originate_router,
+                        (void *) area->area_id, time);
+  else
+    area->thread_router_lsa =
+      thread_add_event (master, ospf6_lsa_originate_router,
+                        (void *) area->area_id, 0);
+}
+
+int
+ospf6_lsa_router_hook_neighbor (void *neighbor)
+{
+  struct ospf6_neighbor *o6n = neighbor;
+  if (o6n->ospf6_interface->area)
+    ospf6_lsa_schedule_router (o6n->ospf6_interface->area);
+  return 0;
+}
+
+int
+ospf6_lsa_router_hook_interface (void *interface)
+{
+  struct ospf6_interface *o6i = interface;
+  if (o6i->area)
+    ospf6_lsa_schedule_router (o6i->area);
+  return 0;
+}
+
+int
+ospf6_lsa_router_hook_area (void *area)
+{
+  struct ospf6_area *o6a = area;
+  ospf6_lsa_schedule_router (o6a);
+  return 0;
+}
+
+int
+ospf6_lsa_router_hook_top (void *ospf6)
+{
+  struct ospf6 *o6 = ospf6;
+  struct ospf6_area *o6a;
+  listnode node;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = getdata (node);
+      ospf6_lsa_schedule_router (o6a);
+    }
+  return 0;
+}
+
+int
+ospf6_lsa_router_refresh (void *old)
+{
+  struct ospf6_lsa *lsa = old;
+  struct ospf6_area *o6a;
+
+  o6a = lsa->scope;
+  ospf6_lsa_schedule_router (o6a);
+  return 0;
+}
+
+void
+ospf6_lsa_slot_register_router ()
+{
+  struct ospf6_lsa_slot slot;
+  struct ospf6_hook hook;
+
+  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+  slot.type              = htons (OSPF6_LSA_TYPE_ROUTER);
+  slot.name              = "Router";
+  slot.func_show         = ospf6_lsa_router_show;
+  slot.func_refresh      = ospf6_lsa_router_refresh;
+  ospf6_lsa_slot_register (&slot);
+
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_spf_database_hook;
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name = "OriginateRouter";
+  hook.hook_change  = ospf6_lsa_router_hook_neighbor;
+  ospf6_hook_register (&hook, &neighbor_hook);
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name = "OriginateRouter";
+  hook.hook_change = ospf6_lsa_router_hook_interface;
+  ospf6_hook_register (&hook, &interface_hook);
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name = "OriginateRouter";
+  hook.hook_change      = ospf6_lsa_router_hook_area;
+  ospf6_hook_register (&hook, &area_hook);
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name = "OriginateRouter";
+  hook.hook_change       = ospf6_lsa_router_hook_top;
+  ospf6_hook_register (&hook, &top_hook);
+}
+
+/*******************************/
+/* RFC2740 3.4.3.2 Network-LSA */
+/*******************************/
+
+int
+ospf6_lsa_network_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char *start, *end, *current;
+  struct ospf6_network_lsa *network_lsa;
+  u_int32_t *router_id;
+  char buf[128], options[32];
+
+  assert (lsa->header);
+  network_lsa = (struct ospf6_network_lsa *) (lsa->header + 1);
+  router_id = (u_int32_t *)(network_lsa + 1);
+
+  ospf6_options_string (network_lsa->options, options, sizeof (options));
+  vty_out (vty, "     Options: %s%s", options, VTY_NEWLINE);
+
+  start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+  for (current = start; current + sizeof (u_int32_t) <= end;
+       current += sizeof (u_int32_t))
+    {
+      router_id = (u_int32_t *) current;
+      inet_ntop (AF_INET, router_id, buf, sizeof (buf));
+      vty_out (vty, "     Attached Router: %s%s", buf, VTY_NEWLINE);
+    }
+  return 0;
+}
+
+void
+ospf6_lsa_network_update (char *ifname)
+{
+  char buffer [MAXLSASIZE];
+  u_int16_t size;
+  struct ospf6_lsa *old;
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+  int count;
+
+  struct ospf6_network_lsa *network_lsa;
+  struct ospf6_neighbor *o6n;
+  u_int32_t *router_id;
+  listnode node;
+
+  ifp = if_lookup_by_name (ifname);
+  if (! ifp)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_warn ("Update Network: No such Interface: %s", ifname);
+      return;
+    }
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i || ! o6i->area)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_warn ("Update Network: Interface not enabled: %s", ifname);
+      return;
+    }
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_NETWORK),
+                           htonl (o6i->if_id),
+                           o6i->area->ospf6->router_id, o6i->area);
+
+  /* Don't originate Network-LSA if not DR */
+  if (o6i->state != IFS_DR)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("Update Network: Interface %s is not DR",
+                   o6i->interface->name);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* If none of neighbor is adjacent to us */
+  count = 0;
+  o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
+  if (count == 0)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("Update Network: Interface %s is Stub",
+                   o6i->interface->name);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("Update Network: Interface %s", o6i->interface->name);
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  size = sizeof (struct ospf6_network_lsa);
+  network_lsa = (struct ospf6_network_lsa *) buffer;
+  router_id = (u_int32_t *)(network_lsa + 1);
+
+  /* set fields of myself */
+  *router_id++ = o6i->area->ospf6->router_id;
+  size += sizeof (u_int32_t);
+  network_lsa->options[0] |= o6i->area->options[0];
+  network_lsa->options[1] |= o6i->area->options[1];
+  network_lsa->options[2] |= o6i->area->options[2];
+
+  /* Walk through neighbors */
+  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (node);
+
+      if (o6n->state != NBS_FULL)
+        continue;
+
+      /* set this neighbor's Router-ID to LSA */
+      *router_id++ = o6n->router_id;
+      size += sizeof (u_int32_t);
+
+      /* options field is logical OR */
+      network_lsa->options[0] |= o6n->options[0];
+      network_lsa->options[1] |= o6n->options[1];
+      network_lsa->options[2] |= o6n->options[2];
+    }
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_NETWORK),
+                       htonl (o6i->if_id), o6i->area->ospf6->router_id,
+                       (char *) network_lsa, size, o6i->area);
+}
+
+int
+ospf6_lsa_network_hook_neighbor (void *neighbor)
+{
+  struct ospf6_neighbor *o6n = neighbor;
+  ospf6_lsa_network_update (o6n->ospf6_interface->interface->name);
+  return 0;
+}
+
+int
+ospf6_lsa_network_hook_interface (void *interface)
+{
+  struct ospf6_interface *o6i = interface;
+  if (o6i->area)
+    ospf6_lsa_network_update (o6i->interface->name);
+  return 0;
+}
+
+int
+ospf6_lsa_network_refresh (void *old)
+{
+  struct ospf6_lsa *lsa = old;
+  struct interface *ifp;
+
+  ifp = if_lookup_by_index (ntohl (lsa->header->id));
+  if (! ifp)
+    ospf6_lsa_premature_aging (old);
+  else
+    ospf6_lsa_network_update (ifp->name);
+
+  return 0;
+}
+
+void
+ospf6_lsa_slot_register_network ()
+{
+  struct ospf6_lsa_slot slot;
+  struct ospf6_hook hook;
+
+  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+  slot.type              = htons (OSPF6_LSA_TYPE_NETWORK);
+  slot.name              = "Network";
+  slot.func_show         = ospf6_lsa_network_show;
+  slot.func_refresh      = ospf6_lsa_network_refresh;
+  ospf6_lsa_slot_register (&slot);
+
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_NETWORK & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_spf_database_hook;
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name  = "OriginateNetwork";
+  hook.hook_change  = ospf6_lsa_network_hook_neighbor;
+  ospf6_hook_register (&hook, &neighbor_hook);
+
+  memset (&hook, 0, sizeof (hook));
+  hook.name  = "OriginateNetwork";
+  hook.hook_change = ospf6_lsa_network_hook_interface;
+  ospf6_hook_register (&hook, &interface_hook);
+}
+
+/****************************/
+/* RFC2740 3.4.3.6 Link-LSA */
+/****************************/
+
+int
+ospf6_lsa_link_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char *start, *end, *current;
+  struct ospf6_link_lsa *link_lsa;
+  int prefixnum;
+  struct ospf6_prefix *prefix;
+  char buf[128];
+  struct in6_addr in6;
+
+  assert (lsa->header);
+
+  link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1);
+  prefixnum = ntohl (link_lsa->llsa_prefix_num);
+
+  inet_ntop (AF_INET6, (void *)&link_lsa->llsa_linklocal, buf, sizeof (buf));
+  vty_out (vty, "     LinkLocal Address: %s%s", buf, VTY_NEWLINE);
+  vty_out (vty, "     Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
+
+  start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length); 
+  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
+    {
+      prefix = (struct ospf6_prefix *) current;
+      if (current + OSPF6_PREFIX_SIZE (prefix) > end)
+        {
+          vty_out (vty, "    Trailing %d byte garbage ... Malformed%s",
+                   end - current, VTY_NEWLINE);
+          return -1;
+        }
+
+      ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
+      vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
+      ospf6_prefix_in6_addr (prefix, &in6);
+      inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+      vty_out (vty, "     Prefix: %s/%d%s",
+               buf, prefix->prefix_length, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+
+void
+ospf6_lsa_link_update (char *ifname)
+{
+  char *cp, buffer [MAXLSASIZE], buf[32];
+  u_int16_t size;
+  struct ospf6_lsa *old;
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+
+  struct ospf6_link_lsa *link_lsa;
+  struct ospf6_prefix *p;
+  list prefix_connected;
+  listnode node;
+  struct connected *c;
+
+  ifp = if_lookup_by_name (ifname);
+  if (! ifp)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("Update Link: No such Interface: %s", ifname);
+      return;
+    }
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i || ! o6i->area)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("Update Link: Interface not enabled: %s", ifname);
+      return;
+    }
+
+#if 0
+  /* Link-LSA is on Broadcast or NBMA */
+  if (! if_is_broadcast (o6i->interface) /* && ! NBMA xxx */)
+    {
+      return;
+    }
+#endif /*0*/
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_LINK), htonl (o6i->if_id),
+                           ospf6->router_id, o6i->area);
+
+  /* can't make Link-LSA if linklocal address not set */
+  if (! o6i->lladdr)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_warn ("Update Link: No Linklocal Address: %s",
+                   o6i->interface->name);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("Update Link: Interface %s", o6i->interface->name);
+
+  if (! ospf6_interface_is_enabled (o6i->interface->ifindex))
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("  Interface %s not enabled", o6i->interface->name);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* check connected prefix */
+  prefix_connected = list_new ();
+  for (node = listhead (o6i->interface->connected); node; nextnode (node))
+    {
+      c = (struct connected *) getdata (node);
+
+      /* filter prefix not IPv6 */
+      if (c->address->family != AF_INET6)
+        continue;
+
+      /* for log */
+      prefix2str (c->address, buf, sizeof (buf));
+
+      CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
+      CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
+      CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
+      CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
+      CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
+
+      /* filter prefix specified by configuration */
+      if (o6i->plist_name)
+        {
+          struct prefix_list *plist;
+          enum prefix_list_type result = PREFIX_PERMIT;
+
+          plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
+          if (plist)
+            result = prefix_list_apply (plist, c->address);
+          else if (IS_OSPF6_DUMP_LSA)
+            zlog_warn ("Update Intra-Prefix (Stub): "
+                       "Prefix list \"%s\" not found", o6i->plist_name);
+
+          if (result == PREFIX_DENY)
+            {
+              if (IS_OSPF6_DUMP_LSA)
+                zlog_info ("  Filter out Prefix-list %s: %s",
+                           o6i->plist_name, buf);
+              continue;
+            }
+        }
+
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("    Advertise %s", buf);
+
+      /* hold prefix in list. duplicate is filtered in ospf6_prefix_add() */
+      p = ospf6_prefix_create (0, 0, (struct prefix_ipv6 *) c->address);
+      ospf6_prefix_add (prefix_connected, p);
+    }
+
+  /* Note: even if no prefix configured, still we have to create Link-LSA
+     for next-hop resolution */
+
+  memset (buffer, 0, sizeof (buffer));
+  size = sizeof (struct ospf6_link_lsa);
+  link_lsa = (struct ospf6_link_lsa *) buffer;
+
+  /* fill Link LSA and calculate size */
+  link_lsa->llsa_rtr_pri = o6i->priority;
+  link_lsa->llsa_options[0] = o6i->area->options[0];
+  link_lsa->llsa_options[1] = o6i->area->options[1];
+  link_lsa->llsa_options[2] = o6i->area->options[2];
+
+  /* linklocal address */
+  memcpy (&link_lsa->llsa_linklocal, o6i->lladdr, sizeof (struct in6_addr));
+
+#ifdef KAME /* clear ifindex */
+  if (link_lsa->llsa_linklocal.s6_addr[3] & 0x0f)
+    link_lsa->llsa_linklocal.s6_addr[3] &= ~((char)0x0f);
+#endif /* KAME */
+
+  link_lsa->llsa_prefix_num = htonl (listcount (prefix_connected));
+  cp = (char *)(link_lsa + 1);
+  for (node = listhead (prefix_connected); node; nextnode (node))
+    {
+      p = (struct ospf6_prefix *) getdata (node);
+      size += OSPF6_PREFIX_SIZE (p);
+      memcpy (cp, p, OSPF6_PREFIX_SIZE (p));
+      cp += OSPF6_PREFIX_SIZE (p);
+    }
+
+  for (node = listhead (prefix_connected); node; nextnode (node))
+    {
+      p = (struct ospf6_prefix *) getdata (node);
+      ospf6_prefix_delete (p);
+    }
+  list_delete (prefix_connected);
+
+  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_LINK),
+                       htonl (o6i->if_id), o6i->area->ospf6->router_id,
+                       (char *) link_lsa, size, o6i);
+}
+
+int
+ospf6_lsa_link_hook_interface (void *interface)
+{
+  struct ospf6_interface *o6i = interface;
+  if (o6i->area)
+    ospf6_lsa_link_update (o6i->interface->name);
+  return 0;
+}
+
+int
+ospf6_lsa_link_refresh (void *old)
+{
+  struct ospf6_lsa *lsa = old;
+  struct interface *ifp;
+
+  ifp = if_lookup_by_index (ntohl (lsa->header->id));
+  if (! ifp)
+    ospf6_lsa_premature_aging (old);
+  else
+    ospf6_lsa_link_update (ifp->name);
+
+  return 0;
+}
+
+void
+ospf6_lsa_slot_register_link ()
+{
+  struct ospf6_lsa_slot slot;
+
+  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
+  slot.type              = htons (OSPF6_LSA_TYPE_LINK);
+  slot.name              = "Link";
+  slot.func_show         = ospf6_lsa_link_show;
+  slot.func_refresh      = ospf6_lsa_link_refresh;
+  slot.hook_interface.name = "OriginateLink";
+  slot.hook_interface.hook_change = ospf6_lsa_link_hook_interface;
+  ospf6_lsa_slot_register (&slot);
+
+  /*
+   * Link LSA handling will be shift in ospf6_intra.c
+   * Currently, only database hook only moved to ospf6_intra.c
+   */
+#if 0
+  ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = 
+    ospf6_spf_database_hook;
+#endif /*0*/
+}
+
+int
+ospf6_lsa_add_hook (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_lsa_slot *sp;
+
+  sp = ospf6_lsa_slot_get (lsa->header->type);
+  if (sp)
+    {
+      CALL_CHANGE_HOOK (&sp->database_hook, lsa);
+    }
+  else
+    zlog_warn ("Unknown LSA added to database: %s", lsa->str);
+  return 0;
+}
+
+int
+ospf6_lsa_change_hook (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_lsa_slot *sp;
+
+  sp = ospf6_lsa_slot_get (lsa->header->type);
+  if (sp)
+    {
+      CALL_CHANGE_HOOK (&sp->database_hook, lsa);
+    }
+  else
+    zlog_warn ("Unknown LSA changed in database: %s", lsa->str);
+  return 0;
+}
+
+int
+ospf6_lsa_remove_hook (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_lsa_slot *sp;
+
+  sp = ospf6_lsa_slot_get (lsa->header->type);
+  if (sp)
+    {
+      CALL_REMOVE_HOOK (&sp->database_hook, lsa);
+    }
+  else
+    zlog_warn ("Unknown LSA removed from database: %s", lsa->str);
+  return 0;
+}
+
+/* Initialize LSA slots */
+void
+ospf6_lsa_init ()
+{
+  struct ospf6_hook hook;
+
+  slot_head = NULL;
+  ospf6_lsa_slot_register_router ();
+  ospf6_lsa_slot_register_network ();
+  ospf6_lsa_slot_register_link ();
+#if 0
+  ospf6_lsa_slot_register_intra_prefix ();
+  ospf6_lsa_slot_register_as_external ();
+#endif /*0*/
+
+  hook.name = "LSADatabaseHook";
+  hook.hook_add = ospf6_lsa_add_hook;
+  hook.hook_change = ospf6_lsa_change_hook;
+  hook.hook_remove = ospf6_lsa_remove_hook;
+  ospf6_hook_register (&hook, &database_hook);
+}
+
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
new file mode 100644 (file)
index 0000000..02ad7c6
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * LSA function
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_LSA_H
+#define OSPF6_LSA_H
+
+#include "ospf6_hook.h"
+
+#define ONESECOND_USEC  1000000
+#define USEC_TVDIFF(tv2,tv1) \
+  (((tv2)->tv_sec - (tv1)->tv_sec) * ONESECOND_USEC \
+   + ((tv2)->tv_usec - (tv1)->tv_usec))
+#define SEC_TVDIFF(tv2,tv1) \
+  (USEC_TVDIFF((tv2),(tv1)) / ONESECOND_USEC)
+
+/* LSA definition */
+
+#define MAXLSASIZE   1024
+
+#define OSPF6_LSA_MAXAGE           3600    /* 1 hour */
+#define OSPF6_LSA_CHECKAGE         300     /* 5 min */
+#define OSPF6_LSA_MAXAGEDIFF       900     /* 15 min */
+
+/* Type */
+#define OSPF6_LSA_TYPE_NONE             0x0000
+#define OSPF6_LSA_TYPE_ROUTER           0x2001
+#define OSPF6_LSA_TYPE_NETWORK          0x2002
+#define OSPF6_LSA_TYPE_INTER_PREFIX     0x2003
+#define OSPF6_LSA_TYPE_INTER_ROUTER     0x2004
+#define OSPF6_LSA_TYPE_AS_EXTERNAL      0x4005
+#define OSPF6_LSA_TYPE_GROUP_MEMBERSHIP 0x2006
+#define OSPF6_LSA_TYPE_TYPE_7           0x2007
+#define OSPF6_LSA_TYPE_LINK             0x0008
+#define OSPF6_LSA_TYPE_INTRA_PREFIX     0x2009
+#define OSPF6_LSA_TYPE_MAX              0x000a
+#define OSPF6_LSA_TYPE_SIZE             0x000b
+
+/* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */
+#define OSPF6_LSTYPE_UBIT_MASK        0x8000
+#define OSPF6_LSTYPE_SCOPE_MASK       0x6000
+#define OSPF6_LSTYPE_CODE_MASK        0x1fff
+
+#define OSPF6_LSA_TYPESW_MASK         OSPF6_LSTYPE_CODE_MASK
+#define OSPF6_LSA_TYPESW(x) (ntohs((x)) & OSPF6_LSA_TYPESW_MASK)
+#define OSPF6_LSA_TYPESW_ISKNOWN(x) (OSPF6_LSA_TYPESW(x) < OSPF6_LSA_TYPE_MAX)
+
+/* lsa scope */
+#define OSPF6_LSA_SCOPE_LINKLOCAL  0x0000
+#define OSPF6_LSA_SCOPE_AREA       0x2000
+#define OSPF6_LSA_SCOPE_AS         0x4000
+#define OSPF6_LSA_SCOPE_RESERVED   0x6000
+#define OSPF6_LSA_IS_SCOPE_LINKLOCAL(x) \
+  (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_LINKLOCAL)
+#define OSPF6_LSA_IS_SCOPE_AREA(x) \
+  (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AREA)
+#define OSPF6_LSA_IS_SCOPE_AS(x) \
+  (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AS)
+
+/* NOTE that all LSAs are kept NETWORK BYTE ORDER */
+
+/* Router-LSA */
+struct ospf6_router_lsa
+{
+  u_char bits;
+  u_char options[3];
+  /* followed by ospf6_router_lsd(s) */
+};
+
+#define OSPF6_ROUTER_LSA_BIT_B     (1 << 0)
+#define OSPF6_ROUTER_LSA_BIT_E     (1 << 1)
+#define OSPF6_ROUTER_LSA_BIT_V     (1 << 2)
+#define OSPF6_ROUTER_LSA_BIT_W     (1 << 3)
+
+#define OSPF6_ROUTER_LSA_SET(x,y)    ((x)->bits |=  (y))
+#define OSPF6_ROUTER_LSA_ISSET(x,y)  ((x)->bits &   (y))
+#define OSPF6_ROUTER_LSA_CLEAR(x,y)  ((x)->bits &= ~(y))
+#define OSPF6_ROUTER_LSA_CLEAR_ALL_BITS(x)  ((x)->bits = 0)
+
+/* Link State Description in Router-LSA */
+struct ospf6_router_lsd
+{
+  u_char    type;
+  u_char    reserved;
+  u_int16_t metric;                /* output cost */
+  u_int32_t interface_id;
+  u_int32_t neighbor_interface_id;
+  u_int32_t neighbor_router_id;
+};
+
+#define OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT       1
+#define OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK    2
+#define OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK       3
+#define OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK       4
+
+/* Network-LSA */
+struct ospf6_network_lsa
+{
+  u_char reserved;
+  u_char options[3];
+  /* followed by ospf6_netowrk_lsd(s) */
+};
+
+/* Link State Description in Router-LSA */
+struct ospf6_network_lsd
+{
+  u_int32_t adv_router;
+};
+
+/* Link-LSA */
+struct ospf6_link_lsa
+{
+  u_char          llsa_rtr_pri;
+  u_char          llsa_options[3];
+  struct in6_addr llsa_linklocal;
+  u_int32_t       llsa_prefix_num;
+  /* followed by prefix(es) */
+};
+
+/* Intra-Area-Prefix-LSA */
+struct ospf6_intra_area_prefix_lsa
+{
+  u_int16_t prefix_number;
+  u_int16_t refer_lstype;
+  u_int32_t refer_lsid;
+  u_int32_t refer_advrtr;
+};
+
+/* AS-External-LSA */
+struct ospf6_as_external_lsa
+{
+  u_char    ase_bits;
+  u_char    ase_pre_metric; /* 1st byte of metric */
+  u_int16_t ase_metric;     /* 2nd, 3rd byte of metric */
+#if 1
+  struct ospf6_prefix ospf6_prefix;
+#else
+  u_char    ase_prefix_len;
+  u_char    ase_prefix_opt;
+  u_int16_t ase_refer_lstype;
+  /* followed by one address prefix */
+#endif
+  /* followed by none or one forwarding address */
+  /* followed by none or one external route tag */
+  /* followed by none or one referenced LS-ID */
+};
+#define ASE_LSA_BIT_T     (1 << 0)
+#define ASE_LSA_BIT_F     (1 << 1)
+#define ASE_LSA_BIT_E     (1 << 2)
+
+#define ASE_LSA_SET(x,y)    ((x)->ase_bits |=  (y))
+#define ASE_LSA_ISSET(x,y)  ((x)->ase_bits &   (y))
+#define ASE_LSA_CLEAR(x,y)  ((x)->ase_bits &= ~(y))
+
+/* LSA Header */
+struct ospf6_lsa_hdr
+{
+  u_int16_t lsh_age;      /* LS age */
+  u_int16_t lsh_type;     /* LS type */
+  u_int32_t lsh_id;       /* Link State ID */
+  u_int32_t lsh_advrtr;   /* Advertising Router */
+  u_int32_t lsh_seqnum;   /* LS sequence number */
+  u_int16_t lsh_cksum;    /* LS checksum */
+  u_int16_t lsh_len;      /* length */
+};
+struct ospf6_lsa_header
+{
+  u_int16_t age;       /* LS age */
+  u_int16_t type;      /* LS type */
+  u_int32_t ls_id;     /* Link State ID */
+  u_int32_t advrtr;    /* Advertising Router */
+  u_int32_t seqnum;    /* LS sequence number */
+  u_int16_t checksum;  /* LS checksum */
+  u_int16_t length;    /* LSA length */
+};
+struct ospf6_lsa_header__
+{
+  u_int16_t age;        /* LS age */
+  u_int16_t type;       /* LS type */
+  u_int32_t id;         /* Link State ID */
+  u_int32_t adv_router; /* Advertising Router */
+  u_int32_t seqnum;     /* LS sequence number */
+  u_int16_t checksum;   /* LS checksum */
+  u_int16_t length;     /* LSA length */
+};
+
+#define OSPF6_LSA_NEXT(x) ((struct ospf6_lsa_header *) \
+                             ((char *)(x) + ntohs ((x)->length)))
+
+#define OSPF6_LSA_HEADER_END(header) \
+  ((void *)((char *)(header) + sizeof (struct ospf6_lsa_header)))
+
+struct ospf6_lsa
+{
+  char                   str[256];  /* dump string */
+
+  u_long                 lock;      /* reference counter */
+  int                    summary;   /* indicate this is LS header only */
+  void                  *scope;     /* pointer of scoped data structure */
+  unsigned char          flag;      /* to decide ack type and refresh */
+  struct timeval         birth;     /* tv_sec when LS age 0 */
+  struct timeval         installed; /* installed time */
+  struct timeval         originated; /* installed time */
+  struct thread         *expire;
+  struct thread         *refresh;   /* For self-originated LSA */
+  u_int32_t              from;      /* from which neighbor */
+
+  /* lsa instance */
+  struct ospf6_lsa_hdr  *lsa_hdr;
+  struct ospf6_lsa_header__ *header;
+
+  /* statistics */
+  u_long turnover_num;
+  u_long turnover_total;
+  u_long turnover_min;
+  u_long turnover_max;
+};
+
+struct ospf6_lsa_slot
+{
+  struct ospf6_lsa_slot *prev;
+  struct ospf6_lsa_slot *next;
+
+  u_int16_t  type;
+  char      *name;
+
+  int (*func_print)        (struct ospf6_lsa *lsa);
+  int (*func_show)         (struct vty *vty, struct ospf6_lsa *lsa);
+  int (*func_refresh)      (void *lsa);
+
+  int (*database_add)      (void *lsa);
+  int (*database_remove)   (void *lsa);
+
+  struct ospf6_hook_master database_hook;
+
+  struct ospf6_hook hook_neighbor;
+  struct ospf6_hook hook_interface;
+  struct ospf6_hook hook_area;
+  struct ospf6_hook hook_top;
+  struct ospf6_hook hook_database;
+  struct ospf6_hook hook_route;
+};
+
+#define OSPF6_LSA_FLAG_FLOODBACK  0x01
+#define OSPF6_LSA_FLAG_DUPLICATE  0x02
+#define OSPF6_LSA_FLAG_IMPLIEDACK 0x04
+#define OSPF6_LSA_FLAG_REFRESH    0x08
+
+/* Back pointer check, Is X's reference field bound to Y ? */
+#define x_ipl(x) ((struct intra_area_prefix_lsa *)LSH_NEXT((x)->lsa_hdr))
+#define is_reference_network_ok(x,y) \
+          ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\
+           (x_ipl(x))->intra_prefix_refer_lsid == (y)->lsa_hdr->lsh_id &&\
+           (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr)
+  /* referencing router's ifid must be 0,
+     see draft-ietf-ospf-ospfv6-06.txt */
+#define is_reference_router_ok(x,y) \
+          ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\
+           (x_ipl(x))->intra_prefix_refer_lsid == htonl (0) &&\
+           (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr)
+
+/* MaxAge check.  */
+/* ospf6_lsa_is_maxage (struct ospf6_lsa *lsa) */
+#define IS_LSA_MAXAGE(L)      (ospf6_lsa_age_current (L) == OSPF6_LSA_MAXAGE)
+
+struct ospf6_lsa_slot *ospf6_lsa_slot_get (u_int16_t type);
+int ospf6_lsa_slot_register (struct ospf6_lsa_slot *src);
+int ospf6_lsa_slot_unregister (u_int16_t type);
+
+extern struct ospf6_lsa_slot *slot_head;
+#define CALL_FOREACH_LSA_HOOK(hook,func,data) \
+  if (ospf6)\
+    {\
+      struct ospf6_lsa_slot *slot;\
+      for (slot = slot_head; slot; slot = slot->next)\
+        {\
+          if (slot->hook.func)\
+            (*slot->hook.func) (data);\
+        }\
+    }
+#define CALL_LSA_FUNC(type,func,data) \
+  if (ospf6)\
+    {\
+      struct ospf6_lsa_slot *slot;\
+      slot = ospf6_lsa_slot_get (type);\
+      if (slot && slot->func)\
+        {\
+          (*slot->func) (data);\
+        }\
+      else\
+        {\
+          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+                     ntohs (type), __FILE__, __LINE__);\
+        }\
+    }
+
+#define CALL_LSA_DATABASE_ADD(type,data) \
+  if (ospf6)\
+    {\
+      struct ospf6_lsa_slot *slot;\
+      slot = ospf6_lsa_slot_get (type);\
+      if (slot)\
+        {\
+          CALL_ADD_HOOK (&slot->database_hook, data);\
+        }\
+      else\
+        {\
+          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+                     ntohs (type), __FILE__, __LINE__);\
+        }\
+    }
+#define CALL_LSA_DATABASE_CHANGE(type,data) \
+  if (ospf6)\
+    {\
+      struct ospf6_lsa_slot *slot;\
+      slot = ospf6_lsa_slot_get (type);\
+      if (slot)\
+        {\
+          CALL_CHANGE_HOOK (&slot->database_hook, data);\
+        }\
+      else\
+        {\
+          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+                     ntohs (type), __FILE__, __LINE__);\
+        }\
+    }
+#define CALL_LSA_DATABASE_REMOVE(type,data) \
+  if (ospf6)\
+    {\
+      struct ospf6_lsa_slot *slot;\
+      slot = ospf6_lsa_slot_get (type);\
+      if (slot)\
+        {\
+          CALL_REMOVE_HOOK (&slot->database_hook, data);\
+        }\
+      else\
+        {\
+          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
+                     ntohs (type), __FILE__, __LINE__);\
+        }\
+    }
+
+void ospf6_lsa_init ();
+
+/* Function Prototypes */
+
+struct router_lsd *
+get_router_lsd (u_int32_t, struct ospf6_lsa *);
+unsigned long get_ifindex_to_router (u_int32_t, struct ospf6_lsa *);
+
+int ospf6_lsa_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
+int ospf6_lsa_match (u_int16_t, u_int32_t, u_int32_t,
+                     struct ospf6_lsa_header *);
+
+void ospf6_lsa_show (struct vty *, struct ospf6_lsa *);
+void ospf6_lsa_show_dump (struct vty *, struct ospf6_lsa *);
+void ospf6_lsa_show_summary (struct vty *, struct ospf6_lsa *);
+void ospf6_lsa_show_summary_header (struct vty *);
+
+struct ospf6_lsa *
+ospf6_lsa_create (struct ospf6_lsa_header *);
+struct ospf6_lsa *
+ospf6_lsa_summary_create (struct ospf6_lsa_header__ *);
+void
+ospf6_lsa_delete (struct ospf6_lsa *);
+
+void ospf6_lsa_lock (struct ospf6_lsa *);
+void ospf6_lsa_unlock (struct ospf6_lsa *);
+
+unsigned short ospf6_lsa_age_current (struct ospf6_lsa *);
+int ospf6_lsa_is_maxage (struct ospf6_lsa *);
+void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t);
+void ospf6_lsa_premature_aging (struct ospf6_lsa *);
+
+int ospf6_lsa_check_recent (struct ospf6_lsa *, struct ospf6_lsa *);
+
+int
+ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header);
+void *
+ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header);
+int
+ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
+                           int index2, struct ospf6_lsa_header *lsa_header2);
+
+int ospf6_lsa_expire (struct thread *);
+int ospf6_lsa_refresh (struct thread *);
+
+u_short ospf6_lsa_checksum (struct ospf6_lsa_header *);
+
+void ospf6_lsa_update_network (char *ifname);
+void ospf6_lsa_update_link (char *ifname);
+void ospf6_lsa_update_as_external (u_int32_t ls_id);
+void ospf6_lsa_update_intra_prefix_transit (char *ifname);
+void ospf6_lsa_update_intra_prefix_stub (u_int32_t area_id);
+
+u_int16_t ospf6_lsa_get_scope_type (u_int16_t);
+int ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header);
+
+char *ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize);
+char *ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size);
+
+u_long
+ospf6_lsa_has_elasped (u_int16_t, u_int32_t, u_int32_t, void *);
+void
+ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *);
+
+#endif /* OSPF6_LSA_H */
+
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
new file mode 100644 (file)
index 0000000..ad53eb4
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+#include "command.h"
+#include "if.h"
+
+#include "ospf6_dump.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+#include "ospf6_top.h"
+
+#define OSPF6_LSDB_MATCH_TYPE        0x01
+#define OSPF6_LSDB_MATCH_ID          0x02
+#define OSPF6_LSDB_MATCH_ADV_ROUTER  0x04
+#define OSPF6_LSDB_SHOW_DUMP         0x08
+#define OSPF6_LSDB_SHOW_DETAIL       0x10
+
+struct ospf6_lsdb_hook_t hooks[0x2000];
+struct ospf6_lsdb_hook_t *ospf6_lsdb_hook = hooks;
+
+struct ospf6_lsdb *
+ospf6_lsdb_create ()
+{
+  struct ospf6_lsdb *lsdb;
+
+  lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb));
+  if (lsdb == NULL)
+    {
+      zlog_warn ("Can't malloc lsdb");
+      return NULL;
+    }
+  memset (lsdb, 0, sizeof (struct ospf6_lsdb));
+
+  lsdb->table = route_table_init ();
+  return lsdb;
+}
+
+void
+ospf6_lsdb_delete (struct ospf6_lsdb *lsdb)
+{
+  ospf6_lsdb_remove_all (lsdb);
+  route_table_finish (lsdb->table);
+  XFREE (MTYPE_OSPF6_LSDB, lsdb);
+}
+
+static void
+ospf6_lsdb_set_key (struct prefix_ipv6 *key, int flag,
+                    u_int16_t type, u_int32_t id, u_int32_t adv_router)
+{
+  int len = 0;
+  memset (key, 0, sizeof (struct prefix_ipv6));
+
+  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE))
+    {
+      len += 2;
+      if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER))
+        {
+          len += 4;
+          if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID))
+            len += 4;
+        }
+    }
+
+  if (len > 0)
+    memcpy ((char *)&key->prefix, &type, 2);
+  if (len > 2)
+    memcpy ((char *)&key->prefix + 2, &adv_router, 4);
+  if (len > 6)
+    memcpy ((char *)&key->prefix + 6, &id, 4);
+
+  key->family = AF_INET6;
+  key->prefixlen = len * 8;
+}
+
+void
+ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+  int flag;
+  struct prefix_ipv6 key;
+  struct route_node *rn;
+  struct ospf6_lsa *old = NULL;
+
+  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+         OSPF6_LSDB_MATCH_ADV_ROUTER;
+  ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
+                      lsa->header->adv_router);
+
+  rn = route_node_get (lsdb->table, (struct prefix *) &key);
+  if (rn->info)
+    old = rn->info;
+  rn->info = lsa;
+  ospf6_lsa_lock (lsa);
+
+  if (old)
+    ospf6_lsa_unlock (old);
+  else
+    lsdb->count++;
+}
+
+void
+ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+  int flag;
+  struct prefix_ipv6 key;
+  struct route_node *rn;
+  struct ospf6_lsa *old;
+
+  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+         OSPF6_LSDB_MATCH_ADV_ROUTER;
+  ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
+                      lsa->header->adv_router);
+
+  rn = route_node_lookup (lsdb->table, (struct prefix *) &key);
+  if (! rn || ! rn->info)
+    {
+      zlog_warn ("LSDB: Can't remove: no such LSA: %s", lsa->str);
+      return;
+    }
+
+  old = rn->info;
+  if (old != lsa)
+    {
+      zlog_warn ("LSDB: Can't remove: different instance: %s (%p <-> %p) %s",
+                 lsa->str, lsa, old, old->str);
+      return;
+    }
+
+  rn->info = NULL;
+  ospf6_lsa_unlock (old);
+  lsdb->count--;
+}
+
+static void
+ospf6_lsdb_lookup_node (struct ospf6_lsdb_node *node,
+                        u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                        struct ospf6_lsdb *lsdb)
+{
+  int flag;
+  struct route_node *rn;
+
+  memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
+         OSPF6_LSDB_MATCH_ADV_ROUTER;
+  ospf6_lsdb_set_key (&node->key, flag, type, id, adv_router);
+
+  rn = route_node_lookup (lsdb->table, (struct prefix *) &node->key);
+  if (! rn || ! rn->info)
+    return;
+
+  node->node = rn;
+  node->next = route_next (rn);
+  node->lsa = rn->info;
+  if (node->next != NULL)
+    route_unlock_node (node->next);
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                        struct ospf6_lsdb *lsdb)
+{
+  struct ospf6_lsdb_node node;
+  ospf6_lsdb_lookup_node (&node, type, id, adv_router, lsdb);
+  return node.lsa;
+}
+
+/* Iteration function */
+void
+ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb)
+{
+  struct route_node *rn;
+
+  memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+  rn = route_top (lsdb->table);
+  if (rn == NULL)
+    return;
+
+  while (rn && rn->info == NULL)
+    rn = route_next (rn);
+
+  if (rn && rn->info)
+    {
+      node->node = rn;
+      node->next = route_next (rn);
+      node->lsa = rn->info;
+      if (node->next != NULL)
+        route_unlock_node (node->next);
+    }
+}
+
+void
+ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
+                 struct ospf6_lsdb *lsdb)
+{
+  int flag;
+  struct route_node *rn;
+
+  memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+  flag = OSPF6_LSDB_MATCH_TYPE;
+  ospf6_lsdb_set_key (&node->key, flag, type, 0, 0);
+
+  /* get the closest radix node */
+  rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
+
+  /* skip to the real existing lsdb entry */
+  while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+         prefix_match ((struct prefix *) &node->key, &rn->p))
+    rn = route_next (rn);
+
+  if (rn && rn->info)
+    {
+      node->node = rn;
+      node->next = route_next (rn);
+      node->lsa = rn->info;
+      if (node->next != NULL)
+        route_unlock_node (node->next);
+    }
+}
+
+void
+ospf6_lsdb_type_router (struct ospf6_lsdb_node *node,
+                        u_int16_t type, u_int32_t adv_router,
+                        struct ospf6_lsdb *lsdb)
+{
+  int flag;
+  struct route_node *rn;
+
+  memset (node, 0, sizeof (struct ospf6_lsdb_node));
+
+  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ADV_ROUTER;
+  ospf6_lsdb_set_key (&node->key, flag, type, 0, adv_router);
+
+  /* get the closest radix node */
+  rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
+
+  /* skip to the real existing lsdb entry */
+  while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+         prefix_match ((struct prefix *) &node->key, &rn->p))
+    rn = route_next (rn);
+
+  if (rn && rn->info)
+    {
+      node->node = rn;
+      node->next = route_next (rn);
+      node->lsa = rn->info;
+      if (node->next != NULL)
+        route_unlock_node (node->next);
+    }
+}
+
+void
+ospf6_lsdb_next (struct ospf6_lsdb_node *node)
+{
+  struct route_node *rn;
+
+  route_lock_node (node->node);
+  rn = route_next (node->node);
+
+  /* skip to the real existing lsdb entry */
+  while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
+         prefix_match ((struct prefix *) &node->key, &rn->p))
+    rn = route_next (rn);
+
+  if (rn && rn->info && rn->p.prefixlen >= node->key.prefixlen &&
+      prefix_match ((struct prefix *) &node->key, &rn->p))
+    {
+      node->node = rn;
+      node->next = route_next (rn);
+      node->lsa = rn->info;
+      if (node->next != NULL)
+        route_unlock_node (node->next);
+    }
+  else
+    {
+      node->node = NULL;
+      node->next = NULL;
+      node->lsa = NULL;
+    }
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                   void *scope)
+{
+  struct ospf6_interface *o6i;
+  struct ospf6_area *o6a;
+  listnode i, j;
+
+  if (scope == (void *) ospf6)
+    return ospf6_lsdb_lookup_lsdb (type, id, adv_router, ospf6->lsdb);
+
+  for (i = listhead (ospf6->area_list); i; nextnode (i))
+    {
+      o6a = getdata (i);
+
+      if (scope == (void *) o6a)
+        return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+      for (j = listhead (o6a->if_list); j; nextnode (j))
+        {
+          o6i = getdata (j);
+
+          if (scope == (void *) o6i)
+            return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6i->lsdb);
+        }
+    }
+
+  zlog_warn ("LSDB: Can't lookup: unknown scope, type %#hx", ntohs (type));
+  return NULL;
+}
+
+void
+ospf6_lsdb_install (struct ospf6_lsa *new)
+{
+  struct ospf6_lsdb *lsdb;
+  struct ospf6_lsa *old;
+  int need_hook = 0;
+  void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+
+  struct ospf6 *as = NULL;
+  struct ospf6_area *area = NULL;
+  struct ospf6_interface *linklocal = NULL;
+  hook = NULL;
+
+  switch (ntohs (new->header->type) & OSPF6_LSTYPE_SCOPE_MASK)
+    {
+      case OSPF6_LSA_SCOPE_LINKLOCAL:
+        linklocal = (struct ospf6_interface *) new->scope;
+        lsdb = linklocal->lsdb;
+        break;
+      case OSPF6_LSA_SCOPE_AREA:
+        area = (struct ospf6_area *) new->scope;
+        lsdb = area->lsdb;
+        break;
+      case OSPF6_LSA_SCOPE_AS:
+        as = (struct ospf6 *) new->scope;
+        lsdb = as->lsdb;
+        break;
+      default:
+        zlog_warn ("LSDB: Can't install: scope unknown: %s", new->str);
+        return;
+    }
+
+  /* whether schedule calculation or not */
+  old = ospf6_lsdb_lookup_lsdb (new->header->type, new->header->id,
+                                new->header->adv_router, lsdb);
+
+  if (! old || ospf6_lsa_differ (old, new))
+    need_hook++;
+
+  /* log */
+  if (IS_OSPF6_DUMP_LSDB)
+    zlog_info ("LSDB: Install: %s %s", new->str,
+               ((IS_LSA_MAXAGE (new)) ? "(MaxAge)" : ""));
+
+  if (old)
+    ospf6_lsa_lock (old);
+
+  ospf6_lsdb_add (new, lsdb);
+  gettimeofday (&new->installed, NULL);
+
+  hook = ospf6_lsdb_hook[ntohs (new->header->type) &
+                         OSPF6_LSTYPE_CODE_MASK].hook;
+  if (need_hook && hook)
+    (*hook) (old, new);
+
+  /* old LSA should be freed here */
+  if (old)
+    ospf6_lsa_unlock (old);
+}
+
+void
+ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb)
+{
+  struct ospf6_lsdb_node node;
+  for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    ospf6_lsdb_remove (node.lsa, lsdb);
+}
+
+void
+ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb)
+{
+  struct ospf6_lsdb_node node;
+  struct ospf6_lsa *lsa;
+
+  for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      lsa = node.lsa;
+
+      /* contiue if it's not MaxAge */
+      if (! IS_LSA_MAXAGE (lsa))
+        continue;
+
+      /* continue if it's referenced by some retrans-lists */
+      if (lsa->lock != 1)
+        continue;
+
+      if (IS_OSPF6_DUMP_LSDB)
+        zlog_info ("Remove MaxAge LSA: %s", lsa->str);
+
+      ospf6_lsdb_remove (lsa, lsdb);
+    }
+}
+
+\f
+
+/* vty functions */
+
+static int
+ospf6_lsdb_match (int flag, u_int16_t type, u_int32_t id,
+                  u_int32_t adv_router, struct ospf6_lsa *lsa)
+{
+  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE) &&
+      lsa->header->type != type)
+    return 0;
+
+  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID) &&
+      lsa->header->id != id)
+    return 0;
+
+  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER) &&
+      lsa->header->adv_router != adv_router)
+    return 0;
+
+  return 1;
+}
+
+int
+show_ipv6_ospf6_lsdb (struct vty *vty, int argc, char **argv,
+                      struct ospf6_lsdb *lsdb)
+{
+  u_int flag;
+  u_int16_t type = 0;
+  u_int32_t id, adv_router;
+  int ret;
+  struct ospf6_lsdb_node node;
+  char invalid[32], *invalidp;
+  int l_argc = argc;
+  char **l_argv = argv;
+
+  flag = 0;
+  memset (invalid, 0, sizeof (invalid));
+  invalidp = invalid;
+
+  /* chop tail if the words is 'dump' or 'summary' */
+  if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "dump"))
+    {
+      SET_FLAG (flag, OSPF6_LSDB_SHOW_DUMP);
+      l_argc --;
+    }
+  else if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "detail"))
+    {
+      SET_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL);
+      l_argc --;
+    }
+
+  if (l_argc > 0)
+    {
+      SET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE);
+      if (! strncmp (l_argv[0], "r", 1))
+        type = htons (OSPF6_LSA_TYPE_ROUTER);
+      if (! strncmp (l_argv[0], "n", 1))
+        type = htons (OSPF6_LSA_TYPE_NETWORK);
+      if (! strncmp (l_argv[0], "a", 1))
+        type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+      if (! strcmp (l_argv[0], "intra-prefix"))
+        type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
+      if (! strcmp (l_argv[0], "inter-router"))
+        type = htons (OSPF6_LSA_TYPE_INTER_ROUTER);
+      if (! strcmp (l_argv[0], "inter-prefix"))
+        type = htons (OSPF6_LSA_TYPE_INTER_PREFIX);
+      if (! strncmp (l_argv[0], "l", 1))
+        type = htons (OSPF6_LSA_TYPE_LINK);
+      if (! strncmp (l_argv[0], "0x", 2) && strlen (l_argv[0]) == 6)
+        type = htons ((short) strtol (l_argv[0], (char **)NULL, 16));
+      if (! strncmp (l_argv[0], "*", 1))
+        UNSET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE);
+    }
+
+  if (l_argc > 1)
+    {
+      SET_FLAG (flag, OSPF6_LSDB_MATCH_ID);
+      if (! strncmp (l_argv[1], "*", 1))
+        UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ID);
+      else
+        {
+          ret = inet_pton (AF_INET, l_argv[1], &id);
+          if (ret != 1)
+            {
+              id = htonl (strtoul (l_argv[1], &invalidp, 10));
+              if (invalid[0] != '\0')
+                {
+                  vty_out (vty, "Link State ID is not parsable: %s%s",
+                           l_argv[1], VTY_NEWLINE);
+                  return CMD_SUCCESS;
+                }
+            }
+        }
+    }
+
+  if (l_argc > 2)
+    {
+      SET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER);
+      if (! strncmp (l_argv[2], "*", 1))
+        UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER);
+      else
+        {
+          ret = inet_pton (AF_INET, l_argv[2], &adv_router);
+          if (ret != 1)
+            {
+              adv_router = htonl (strtoul (l_argv[2], &invalidp, 10));
+              if (invalid[0] != '\0')
+                {
+                  vty_out (vty, "Advertising Router is not parsable: %s%s",
+                           l_argv[2], VTY_NEWLINE);
+                  return CMD_SUCCESS;
+                }
+            }
+        }
+    }
+
+  if (! CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL))
+    ospf6_lsa_show_summary_header (vty);
+
+  for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      if (! ospf6_lsdb_match (flag, type, id, adv_router, node.lsa))
+        continue;
+
+      if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DUMP))
+        ospf6_lsa_show_dump (vty, node.lsa);
+      else if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL))
+        ospf6_lsa_show (vty, node.lsa);
+      else
+        ospf6_lsa_show_summary (vty, node.lsa);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_cmd,
+       "show ipv6 ospf6 database",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "LSA Database\n"
+       )
+{
+  struct ospf6_area *o6a;
+  struct ospf6_interface *o6i;
+  listnode i, j;
+
+  /* call show function for each of LSAs in the LSDBs */
+
+  for (i = listhead (ospf6->area_list); i; nextnode (i))
+    {
+      o6a = (struct ospf6_area *) getdata (i);
+
+      /* LinkLocal LSDBs */
+      for (j = listhead (o6a->if_list); j; nextnode (j))
+        {
+          o6i = (struct ospf6_interface *) getdata (j);
+
+          vty_out (vty, "%s", VTY_NEWLINE);
+          vty_out (vty, "                Interface %s (Area: %s):%s",
+                   o6i->interface->name, o6a->str, VTY_NEWLINE);
+          vty_out (vty, "%s", VTY_NEWLINE);
+          show_ipv6_ospf6_lsdb (vty, argc, argv, o6i->lsdb);
+        }
+
+      /* Area LSDBs */
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "                Area %s:%s", o6a->str, VTY_NEWLINE);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      show_ipv6_ospf6_lsdb (vty, argc, argv, o6a->lsdb);
+    }
+
+  /* AS LSDBs */
+  vty_out (vty, "%s", VTY_NEWLINE);
+  vty_out (vty, "                AS:%s", VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+  show_ipv6_ospf6_lsdb (vty, argc, argv, ospf6->lsdb);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_type_cmd,
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX|dump|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Specify LS Type by Hex\n"
+       "Dump raw LSA data in Hex\n"
+       "show detail of LSAs\n"
+       )
+
+ALIAS (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_type_id_cmd,
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*|dump|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Specify LS Type by Hex\n"
+       "Link State ID\n"
+       "All Link State ID\n"
+       "Dump raw LSA data in Hex\n"
+       "show detail of LSAs\n"
+       )
+
+ALIAS (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_type_id_adv_router_cmd,
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*|dump|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Specify LS Type by Hex\n"
+       "Link State ID\n"
+       "All Link State ID\n"
+       "Advertising Router\n"
+       "All Advertising Router\n"
+       "Dump raw LSA data in Hex\n"
+       "show detail of LSAs\n"
+       )
+
+ALIAS (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_type_id_adv_router_dump_cmd,
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*) (dump|detail|)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Specify LS Type by Hex\n"
+       "Link State ID\n"
+       "All Link State ID\n"
+       "Advertising Router\n"
+       "All Advertising Router\n"
+       "Dump raw LSA data in Hex\n"
+       "show detail of LSAs\n"
+       )
+
+void
+ospf6_lsdb_init ()
+{
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
new file mode 100644 (file)
index 0000000..50eedc8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_LSDB_H
+#define OSPF6_LSDB_H
+
+#include "prefix.h"
+#include "table.h"
+
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+
+struct ospf6_lsdb_node
+{
+  struct prefix_ipv6 key;
+
+  struct route_node *node;
+  struct route_node *next;
+
+  struct ospf6_lsa *lsa;
+};
+
+struct ospf6_lsdb
+{
+  struct route_table *table;
+  u_int32_t count;
+  void (*hook) (struct ospf6_lsa *);
+};
+
+/* int  ospf6_lsdb_is_end (struct ospf6_lsdb_node *lsdb_node); */
+#define ospf6_lsdb_is_end(lsdb_node) ((lsdb_node)->node == NULL ? 1 : 0)
+
+/* global holding hooks for each LS type */
+struct ospf6_lsdb_hook_t
+{
+  void (*hook) (struct ospf6_lsa *old, struct ospf6_lsa *new);
+};
+extern struct ospf6_lsdb_hook_t *ospf6_lsdb_hook;
+
+/* Function Prototypes */
+struct ospf6_lsdb * ospf6_lsdb_create ();
+void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb);
+
+void ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb);
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                   void *scope);
+
+void ospf6_lsdb_install (struct ospf6_lsa *new);
+
+void ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
+                      struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_type_router (struct ospf6_lsdb_node *node, u_int16_t type,
+                             u_int32_t adv_router, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_next (struct ospf6_lsdb_node *node);
+
+void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb);
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                        struct ospf6_lsdb *lsdb);
+
+void ospf6_lsdb_init ();
+
+#endif /* OSPF6_LSDB_H */
+
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
new file mode 100644 (file)
index 0000000..5ab517f
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include "getopt.h"
+#include "thread.h"
+#include "log.h"
+#include "version.h"
+#include "command.h"
+#include "vty.h"
+#include "memory.h"
+
+#include "ospf6d.h"
+#include "ospf6_network.h"
+
+void ospf6_init ();
+void ospf6_terminate ();
+void nexthop_init ();
+int ospf6_receive (struct thread *);
+
+extern int ospf6_sock;
+
+/* Default configuration file name for ospf6d. */
+#define OSPF6_DEFAULT_CONFIG       "ospf6d.conf"
+/* Default port values. */
+#define OSPF6_VTY_PORT             2606
+
+/* ospf6d options, we use GNU getopt library. */
+struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "version",     no_argument,       NULL, 'v'},
+  { "help",        no_argument,       NULL, 'h'},
+  { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = OSPF6_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG;
+
+/* ospf6d program name. */
+
+/* is daemon? */
+int daemon_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_OSPF6D_PID;
+
+/* for reload */
+char _cwd[64];
+char _progpath[64];
+int _argc;
+char **_argv;
+char **_envp;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages OSPF version 3.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to yasu@sfc.wide.ad.jp\n", progname);
+    }
+
+  exit (status);
+}
+\f
+
+void
+_reload ()
+{
+  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) reloaded",
+               ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+  ospf6_zebra_finish ();
+  vty_finish ();
+  execve (_progpath, _argv, _envp);
+}
+
+void
+terminate (int i)
+{
+  ospf6_delete (ospf6);
+  unlink (PATH_OSPF6D_PID);
+  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) terminated",
+               ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+  exit (i);
+}
+
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog_info ("SIGHUP received");
+  _reload ();
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog_info ("SIGINT received");
+  terminate (0);
+}
+
+/* SIGTERM handler. */
+void
+sigterm (int sig)
+{
+  zlog_info ("SIGTERM received");
+  terminate (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_info ("SIGUSR1 received");
+  zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigterm);
+  signal_set (SIGPIPE, SIG_IGN);
+#ifdef SIGTSTP
+  signal_set (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+  signal_set (SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+  signal_set (SIGTTOU, SIG_IGN);
+#endif
+  signal_set (SIGUSR1, sigusr1);
+}
+\f
+/* Main routine of ospf6d. Treatment of argument and start ospf finite
+   state machine is handled here. */
+int
+main (int argc, char *argv[], char *envp[])
+{
+  char *p;
+  int opt;
+  char *vty_addr = NULL;
+  int vty_port = 0;
+  char *config_file = NULL;
+  char *progname;
+  struct thread thread;
+  int flag;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* Preserve name of myself. */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  /* 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:hp:A:P:v", longopts, 0);
+    
+      if (opt == EOF)
+        break;
+
+      switch (opt) 
+        {
+        case 0:
+          break;
+        case 'd':
+          daemon_mode = 1;
+          break;
+        case 'f':
+          config_file = optarg;
+          break;
+        case 'A':
+          vty_addr = optarg;
+          break;
+        case 'i':
+          pid_file = optarg;
+          break;
+        case 'P':
+          vty_port = atoi (optarg);
+          break;
+        case 'v':
+          print_version (progname);
+          exit (0);
+          break;
+        case 'h':
+          usage (progname, 0);
+          break;
+        default:
+          usage (progname, 1);
+          break;
+        }
+    }
+
+  /* thread master */
+  master = thread_master_create ();
+
+  /* Initializations. */
+  if (! daemon_mode)
+    flag = ZLOG_STDOUT;
+  else
+    flag = 0;
+
+  zlog_default = openzlog (progname, flag, ZLOG_OSPF6,
+                          LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID,
+                          LOG_DAEMON);
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  ospf6_init ();
+  memory_init ();
+  sort_node ();
+
+  /* parse config file */
+  vty_read_config (config_file, config_current, config_default);
+
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* pid file create */
+#if 0
+  pid_output_lock (pid_file);
+#else
+  pid_output (pid_file);
+#endif
+
+  /* Make ospf protocol socket. */
+  ospf6_serv_sock ();
+  thread_add_read (master, ospf6_receive, NULL, ospf6_sock);
+
+  /* Make ospf vty socket. */
+  vty_serv_sock (vty_addr,
+                vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH);
+
+  /* Print start message */
+  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts",
+               ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+
+  /* Start finite state machine, here we go! */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Log in case thread failed */
+  zlog_warn ("Thread failed");
+  terminate (0);
+
+  /* Not reached. */
+  exit (0);
+}
+
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
new file mode 100644 (file)
index 0000000..f6577a9
--- /dev/null
@@ -0,0 +1,1972 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+int
+is_ospf6_message_dump (u_char type)
+{
+  if (type > OSPF6_MESSAGE_TYPE_LSACK)
+    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+
+  switch (type)
+    {
+      case OSPF6_MESSAGE_TYPE_UNKNOWN:
+          return 1;
+        break;
+      case OSPF6_MESSAGE_TYPE_HELLO:
+        if (IS_OSPF6_DUMP_HELLO)
+          return 1;
+        break;
+      case OSPF6_MESSAGE_TYPE_DBDESC:
+        if (IS_OSPF6_DUMP_DBDESC)
+          return 1;
+        break;
+      case OSPF6_MESSAGE_TYPE_LSREQ:
+        if (IS_OSPF6_DUMP_LSREQ)
+          return 1;
+        break;
+      case OSPF6_MESSAGE_TYPE_LSUPDATE:
+        if (IS_OSPF6_DUMP_LSUPDATE)
+          return 1;
+        break;
+      case OSPF6_MESSAGE_TYPE_LSACK:
+        if (IS_OSPF6_DUMP_LSACK)
+          return 1;
+        break;
+      default:
+        break;
+    }
+  return 0;
+}
+#define IS_OSPF6_DUMP_MESSAGE(x) (is_ospf6_message_dump(x))
+
+char *ospf6_message_type_string[] =
+{
+  "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck", NULL
+};
+
+void
+ospf6_message_log_lsa_header (struct ospf6_lsa_header *lsa_header)
+{
+  char buf_id[16], buf_router[16], typebuf[32];
+
+  inet_ntop (AF_INET, &lsa_header->advrtr, buf_router, sizeof (buf_router));
+  inet_ntop (AF_INET, &lsa_header->ls_id, buf_id, sizeof (buf_id));
+  zlog_info ("   [%s ID=%s Adv=%s]",
+             ospf6_lsa_type_string (lsa_header->type, typebuf,
+                                    sizeof (typebuf)),
+             buf_id, buf_router);
+  zlog_info ("    Age=%hu SeqNum=%#lx Cksum=%#hx Len=%hu",
+             ntohs (lsa_header->age), (u_long)ntohl (lsa_header->seqnum),
+             ntohs (lsa_header->checksum), ntohs (lsa_header->length));
+}
+
+static void
+ospf6_message_log_unknown (struct iovec *message)
+{
+  zlog_info ("Message:  Unknown");
+}
+
+static void
+ospf6_message_log_hello (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  struct ospf6_hello *hello;
+  char dr_str[16], bdr_str[16];
+  char *start, *end, *current;
+
+  /* calculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+  hello = (struct ospf6_hello *) message[1].iov_base;
+
+  inet_ntop (AF_INET, &hello->dr, dr_str, sizeof (dr_str));
+  inet_ntop (AF_INET, &hello->bdr, bdr_str, sizeof (bdr_str));
+
+  zlog_info ("    IFID:%ld Priority:%d Option:%s",
+             (u_long)ntohl (hello->interface_id), hello->rtr_pri, "xxx");
+  zlog_info ("    HelloInterval:%hu Deadinterval:%hu",
+             ntohs (hello->hello_interval),
+             ntohs (hello->router_dead_interval));
+  zlog_info ("    DR:%s BDR:%s", dr_str, bdr_str);
+
+  start = (char *) (hello + 1);
+  if (start >= (char *) message[1].iov_base + message[1].iov_len)
+    start = message[2].iov_base;
+  end = (char *) start + (length_left - sizeof (struct ospf6_hello));
+
+  for (current = start; current < end; current += sizeof (u_int32_t))
+    {
+      char neighbor[16];
+      inet_ntop (AF_INET, current, neighbor, sizeof (neighbor));
+      zlog_info ("    Neighbor: %s", neighbor);
+    }
+}
+
+static void
+ospf6_message_log_dbdesc (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  struct ospf6_dbdesc *dbdesc;
+  int i;
+  char buffer[16];
+  struct ospf6_lsa_header *lsa_header;
+
+  /* calculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+  ospf6_options_string (dbdesc->options, buffer, sizeof (buffer));
+
+  zlog_info ("    Option:%s IFMTU:%hu", buffer, ntohs (dbdesc->ifmtu));
+  zlog_info ("    Bits:%s%s%s SeqNum:%#lx",
+             (DD_IS_IBIT_SET (dbdesc->bits) ? "I" : "-"),
+             (DD_IS_MBIT_SET (dbdesc->bits) ? "M" : "-"),
+             (DD_IS_MSBIT_SET (dbdesc->bits) ? "m" : "s"),
+             (u_long)ntohl (dbdesc->seqnum));
+
+  for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
+       (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + message[1].iov_len) &&
+       (char *)(lsa_header + 1) <= (char *)dbdesc + length_left;
+       lsa_header++)
+    ospf6_message_log_lsa_header (lsa_header);
+
+  length_left -= message[1].iov_len;
+  for (i = 2; message[i].iov_base; i++)
+    {
+      for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
+           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base +
+                                                 message[i].iov_len) &&
+           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left);
+           lsa_header++)
+        ospf6_message_log_lsa_header (lsa_header);
+      length_left -= message[i].iov_len;
+    }
+}
+
+static void
+ospf6_message_log_lsreq (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  int i;
+  struct ospf6_lsreq *lsreq;
+  char buf_router[16], buf_id[16], buf_type[16];
+
+  /* calculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+  for (i = 1; message[i].iov_base; i++)
+    {
+      for (lsreq = (struct ospf6_lsreq *) message[i].iov_base;
+           (char *)(lsreq + 1) <= (char *) (message[i].iov_base + message[i].iov_len) &&
+           (char *)(lsreq + 1) <= (char *) (message[i].iov_base + length_left);
+           lsreq++)
+        {
+          inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
+          inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
+          zlog_info ("    [%s ID=%s Adv=%s]",
+                     ospf6_lsa_type_string (lsreq->type, buf_type,
+                                            sizeof (buf_type)),
+                     buf_id, buf_router);
+        }
+      length_left -= message[i].iov_len;
+    }
+}
+
+static void
+ospf6_message_log_lsupdate (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  int i, lsanum;
+  struct ospf6_lsupdate *lsupdate;
+  struct ospf6_lsa_header *lsa_header;
+
+  /* calculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+  lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+  lsanum = ntohl (lsupdate->lsupdate_num);
+
+  zlog_info ("    Number of LSA: #%d", lsanum);
+
+  for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1);
+       (char *)lsa_header < (char *)(message[1].iov_base + message[1].iov_len) &&
+       (char *)lsa_header < (char *)(message[1].iov_base + length_left);
+       lsa_header = OSPF6_LSA_NEXT (lsa_header))
+    ospf6_message_log_lsa_header (lsa_header);
+  length_left -= message[1].iov_len;
+
+  for (i = 2; message[i].iov_base; i++)
+    {
+
+      for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
+           (char *)lsa_header < (char *) (message[i].iov_base + message[i].iov_len) &&
+           (char *)lsa_header < (char *) (message[i].iov_base + length_left);
+           lsa_header = OSPF6_LSA_NEXT (lsa_header))
+        ospf6_message_log_lsa_header (lsa_header);
+      length_left -= message[i].iov_len;
+    }
+}
+
+static void
+ospf6_message_log_lsack (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  struct ospf6_lsa_header *lsa_header;
+  int i;
+
+  /* calculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
+                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+
+  for (i = 1; message[i].iov_base; i++)
+    {
+      for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
+           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base +
+                                                 message[i].iov_len) &&
+           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left);
+           lsa_header++)
+        ospf6_message_log_lsa_header (lsa_header);
+      length_left -= message[i].iov_len;
+    }
+}
+
+struct {
+  void (*message_log) (struct iovec *);
+} ospf6_message_log_body [] =
+{
+  {ospf6_message_log_unknown},
+  {ospf6_message_log_hello},
+  {ospf6_message_log_dbdesc},
+  {ospf6_message_log_lsreq},
+  {ospf6_message_log_lsupdate},
+  {ospf6_message_log_lsack},
+};
+
+static void
+ospf6_message_log (struct iovec *message)
+{
+  struct ospf6_header *o6h;
+  char router_id[16], area_id[16];
+  u_char type;
+
+  assert (message[0].iov_len == sizeof (struct ospf6_header));
+  o6h = (struct ospf6_header *) message[0].iov_base;
+
+  inet_ntop (AF_INET, &o6h->router_id, router_id, sizeof (router_id));
+  inet_ntop (AF_INET, &o6h->area_id, area_id, sizeof (area_id));
+
+  zlog_info ("    OSPFv%d Type:%d Len:%hu RouterID:%s",
+             o6h->version, o6h->type, ntohs (o6h->len), router_id);
+  zlog_info ("    AreaID:%s Cksum:%hx InstanceID:%d",
+             area_id, ntohs (o6h->cksum), o6h->instance_id);
+
+  type = (OSPF6_MESSAGE_TYPE_UNKNOWN < o6h->type &&
+          o6h->type <= OSPF6_MESSAGE_TYPE_LSACK ?
+          o6h->type : OSPF6_MESSAGE_TYPE_UNKNOWN);
+  (* ospf6_message_log_body[type].message_log) (&message[0]);
+}
+
+int
+ospf6_opt_is_mismatch (unsigned char opt, char *options1, char *options2)
+{
+  return (OSPF6_OPT_ISSET (options1, opt) ^ OSPF6_OPT_ISSET (options2, opt));
+}
+
+\f
+void
+ospf6_process_unknown (struct iovec *message,
+                       struct in6_addr *src,
+                       struct in6_addr *dst,
+                       struct ospf6_interface *o6i,
+                       u_int32_t router_id)
+{
+  zlog_warn ("unknown message type, drop");
+}
+
+void
+ospf6_process_hello (struct iovec *message,
+                     struct in6_addr *src,
+                     struct in6_addr *dst,
+                     struct ospf6_interface *o6i,
+                     u_int32_t router_id)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length;
+  struct ospf6_hello *hello;
+  char changes = 0;
+#define CHANGE_RTRPRI (1 << 0)
+#define CHANGE_DR     (1 << 1)
+#define CHANGE_BDR    (1 << 2)
+  int twoway = 0, backupseen = 0, nbchange = 0;
+  u_int32_t *router_id_ptr;
+  int i, seenrtrnum = 0, router_id_space = 0;
+  char strbuf[64];
+  struct ospf6_neighbor *o6n = NULL;
+
+  /* assert interface */
+  assert (o6i);
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* set hello pointer */
+  hello = (struct ospf6_hello *) message[1].iov_base;
+
+  /* find neighbor. if cannot be found, create */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (!o6n)
+    {
+      o6n = ospf6_neighbor_create (router_id, o6i);
+      o6n->ifid = ntohl (hello->interface_id);
+      o6n->prevdr = o6n->dr = hello->dr;
+      o6n->prevbdr = o6n->bdr = hello->bdr;
+      o6n->priority = hello->rtr_pri;
+      memcpy (&o6n->hisaddr, src, sizeof (struct in6_addr));
+    }
+
+  /* HelloInterval check */
+  if (ntohs (hello->hello_interval) != o6i->hello_interval)
+    {
+      zlog_warn ("HelloInterval mismatch with %s", o6n->str);
+      return;
+    }
+
+  /* RouterDeadInterval check */
+  if (ntohs (hello->router_dead_interval)
+      != o6i->dead_interval)
+    {
+      zlog_warn ("RouterDeadInterval mismatch with %s", o6n->str);
+      return;
+    }
+
+  /* check options */
+  /* Ebit */
+  if (ospf6_opt_is_mismatch (OSPF6_OPT_E, hello->options, o6i->area->options))
+    {
+      zlog_warn ("Ebit mismatch with %s", o6n->str);
+      return;
+    }
+
+  /* RouterPriority set */
+  if (o6n->priority != hello->rtr_pri)
+    {
+      o6n->priority = hello->rtr_pri;
+      if (IS_OSPF6_DUMP_HELLO)
+        zlog_info ("%s: RouterPriority changed", o6n->str);
+      changes |= CHANGE_RTRPRI;
+    }
+
+  /* DR set */
+  if (o6n->dr != hello->dr)
+    {
+      /* save previous dr, set current */
+      o6n->prevdr = o6n->dr;
+      o6n->dr = hello->dr;
+      inet_ntop (AF_INET, &o6n->dr, strbuf, sizeof (strbuf));
+      if (IS_OSPF6_DUMP_HELLO)
+        zlog_info ("%s declare %s as DR", o6n->str, strbuf);
+      changes |= CHANGE_DR;
+    }
+
+  /* BDR set */
+  if (o6n->bdr != hello->bdr)
+    {
+      /* save previous bdr, set current */
+      o6n->prevbdr = o6n->bdr;
+      o6n->bdr = hello->bdr;
+      inet_ntop (AF_INET, &o6n->bdr, strbuf, sizeof (strbuf));
+      if (IS_OSPF6_DUMP_HELLO)
+        zlog_info ("%s declare %s as BDR", o6n->str, strbuf);
+      changes |= CHANGE_BDR;
+    }
+
+  /* TwoWay check */
+  router_id_space = length - sizeof (struct ospf6_hello);
+  seenrtrnum = router_id_space / sizeof (u_int32_t);
+  router_id_ptr = (u_int32_t *) (hello + 1);
+  for (i = 0; i < seenrtrnum; i++)
+    {
+      if (*router_id_ptr == o6i->area->ospf6->router_id)
+        twoway++;
+      router_id_ptr++;
+    }
+
+  /* execute neighbor events */
+  thread_execute (master, hello_received, o6n, 0);
+  if (twoway)
+    thread_execute (master, twoway_received, o6n, 0);
+  else
+    thread_execute (master, oneway_received, o6n, 0);
+
+  /* BackupSeen check */
+  if (o6i->state == IFS_WAITING)
+    {
+      if (hello->dr == hello->bdr &&
+          hello->dr == o6n->router_id)
+        zlog_warn ("*** DR Election of %s is illegal", o6n->str);
+
+      if (hello->bdr == o6n->router_id)
+        backupseen++;
+      else if (hello->dr == o6n->router_id && hello->bdr == 0)
+        backupseen++;
+    }
+
+  /* NeighborChange check */
+  if (changes & CHANGE_RTRPRI)
+    nbchange++;
+  if (changes & CHANGE_DR)
+    if (o6n->prevdr == o6n->router_id || o6n->dr == o6n->router_id)
+      nbchange++;
+  if (changes & CHANGE_BDR)
+    if (o6n->prevbdr == o6n->router_id || o6n->bdr == o6n->router_id)
+      nbchange++;
+
+  /* schedule interface events */
+  if (backupseen)
+    thread_add_event (master, backup_seen, o6i, 0);
+  if (nbchange)
+    thread_add_event (master, neighbor_change, o6i, 0);
+
+  return;
+}
+
+int
+ospf6_dbdesc_is_master (struct ospf6_neighbor *o6n)
+{
+  char buf[128];
+
+  if (o6n->router_id == ospf6->router_id)
+    {
+      inet_ntop (AF_INET6, &o6n->hisaddr, buf, sizeof (buf));
+      zlog_warn ("Message: Neighbor router-id conflicts: %s: %s",
+                 o6n->str, buf);
+      return -1;
+    }
+  else if (ntohl (o6n->router_id) > ntohl (ospf6->router_id))
+    return 0;
+  return 1;
+}
+
+int
+ospf6_dbdesc_is_duplicate (struct ospf6_dbdesc *received,
+                           struct ospf6_dbdesc *last_received)
+{
+  if (memcmp (received->options, last_received->options, 3) != 0)
+    return 0;
+  if (received->ifmtu != last_received->ifmtu)
+    return 0;
+  if (received->bits != last_received->bits)
+    return 0;
+  if (received->seqnum != last_received->seqnum)
+    return 0;
+  return 1;
+}
+
+void
+ospf6_process_dbdesc_master (struct iovec *message, struct ospf6_neighbor *o6n)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length, lsa_count;
+  struct ospf6_dbdesc *dbdesc;
+  struct ospf6_lsa_header *lsa_header;
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* set database description pointer */
+  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+
+  switch (o6n->state)
+    {
+      case NBS_DOWN:
+      case NBS_ATTEMPT:
+      case NBS_TWOWAY:
+        if (IS_OSPF6_DUMP_DBDESC)
+          zlog_info ("DbDesc from %s Ignored: state less than Init",
+                     o6n->str);
+        return;
+
+      case NBS_INIT:
+        thread_execute (master, twoway_received, o6n, 0);
+        if (o6n->state != NBS_EXSTART)
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("DbDesc from %s Ignored: state less than ExStart",
+                         o6n->str);
+            return;
+          }
+        /* else fall through to ExStart */
+      case NBS_EXSTART:
+        if (DDBIT_IS_SLAVE (dbdesc->bits) &&
+            !DDBIT_IS_INITIAL (dbdesc->bits) &&
+            ntohl (dbdesc->seqnum) == o6n->dbdesc_seqnum)
+          {
+            ospf6_neighbor_dbex_init (o6n);
+
+            if (o6n->thread_rxmt_dbdesc)
+              thread_cancel (o6n->thread_rxmt_dbdesc);
+            o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+            thread_add_event (master, negotiation_done, o6n, 0);
+          }
+        else
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  negotiation failed with %s", o6n->str);
+            return;
+          }
+        break;
+
+      case NBS_EXCHANGE:
+        /* duplicate dbdesc dropped by master */
+        if (!memcmp (dbdesc, &o6n->last_dd,
+                     sizeof (struct ospf6_dbdesc)))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  duplicate dbdesc, drop");
+            return;
+          }
+
+        /* check Initialize bit and Master/Slave bit */
+        if (DDBIT_IS_INITIAL (dbdesc->bits))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("Initialize bit mismatch");
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+        if (DDBIT_IS_MASTER (dbdesc->bits))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("Master/Slave bit mismatch");
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+
+        /* dbdesc option check */
+        if (memcmp (dbdesc->options, o6n->last_dd.options,
+                    sizeof (dbdesc->options)))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("dbdesc option field changed");
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+
+        /* dbdesc sequence number check */
+        if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum)
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_warn ("*** dbdesc seqnumber mismatch: %d expected",
+                         o6n->dbdesc_seqnum);
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+        break;
+
+      case NBS_LOADING:
+      case NBS_FULL:
+        /* duplicate dbdesc dropped by master */
+        if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  duplicate dbdesc, drop");
+            return;
+          }
+        else
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  not duplicate dbdesc in state %s",
+                         ospf6_neighbor_state_string[o6n->state]);
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+        break; /* not reached */
+
+      default:
+        assert (0);
+        break; /* not reached */
+    }
+
+  /* process LSA headers */
+  lsa_count = 0;
+  for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
+       (char *)(lsa_header + 1) <= (char *)dbdesc + length;
+       lsa_header++)
+    {
+      if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0)
+        {
+          thread_add_event (master, seqnumber_mismatch, o6n, 0);
+          return;
+        }
+      lsa_count ++;
+    }
+
+  /* increment dbdesc seqnum */
+  o6n->dbdesc_seqnum++;
+
+  /* cancel transmission/retransmission thread */
+  if (o6n->thread_send_dbdesc)
+    thread_cancel (o6n->thread_send_dbdesc);
+  o6n->thread_send_dbdesc = (struct thread *) NULL;
+  if (o6n->thread_rxmt_dbdesc)
+    thread_cancel (o6n->thread_rxmt_dbdesc);
+  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+  /* more bit check */
+  if (!DD_IS_MBIT_SET (dbdesc->bits) && !DD_IS_MBIT_SET (o6n->dbdesc_bits))
+    thread_add_event (master, exchange_done, o6n, 0);
+  else
+    o6n->thread_send_dbdesc =
+      thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+  /* save last received dbdesc */
+  memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc));
+
+  /* statistics */
+  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count;
+
+  return;
+}
+
+void
+ospf6_process_dbdesc_slave (struct iovec *message, struct ospf6_neighbor *o6n)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length, lsa_count;
+  struct ospf6_dbdesc *dbdesc;
+  struct ospf6_lsa_header *lsa_header;
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* set database description pointer */
+  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+
+  switch (o6n->state)
+    {
+      case NBS_DOWN:
+      case NBS_ATTEMPT:
+      case NBS_TWOWAY:
+        return;
+      case NBS_INIT:
+        thread_execute (master, twoway_received, o6n, 0);
+        if (o6n->state != NBS_EXSTART)
+          {
+            return;
+          }
+        /* else fall through to ExStart */
+      case NBS_EXSTART:
+        if (DD_IS_IBIT_SET (dbdesc->bits) &&
+            DD_IS_MBIT_SET (dbdesc->bits) &&
+            DD_IS_MSBIT_SET (dbdesc->bits))
+          {
+            /* Master/Slave bit set to slave */
+            DD_MSBIT_CLEAR (o6n->dbdesc_bits);
+            /* Initialize bit clear */
+            DD_IBIT_CLEAR (o6n->dbdesc_bits);
+            /* sequence number set to master's */
+            o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum);
+            ospf6_neighbor_dbex_init (o6n);
+
+            if (o6n->thread_rxmt_dbdesc)
+              thread_cancel (o6n->thread_rxmt_dbdesc);
+            o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+            thread_add_event (master, negotiation_done, o6n, 0);
+          }
+        else
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("negotiation failed");
+            return;
+          }
+        break;
+
+      case NBS_EXCHANGE:
+        /* duplicate dbdesc dropped by master */
+        if (!memcmp (dbdesc, &o6n->last_dd,
+                     sizeof (struct ospf6_dbdesc)))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  duplicate dbdesc, retransmit dbdesc");
+
+            if (o6n->thread_rxmt_dbdesc)
+              thread_cancel (o6n->thread_rxmt_dbdesc);
+            o6n->thread_rxmt_dbdesc =
+              thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0);
+
+            return;
+          }
+
+        /* check Initialize bit and Master/Slave bit */
+        if (DDBIT_IS_INITIAL (dbdesc->bits))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("Initialize bit mismatch");
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+        if (DDBIT_IS_SLAVE (dbdesc->bits))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("Master/Slave bit mismatch");
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+
+        /* dbdesc option check */
+        if (memcmp (dbdesc->options, o6n->last_dd.options,
+                    sizeof (dbdesc->options)))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("dbdesc option field changed");
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+
+        /* dbdesc sequence number check */
+        if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum + 1)
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_warn ("*** dbdesc seqnumber mismatch: %d expected",
+                         o6n->dbdesc_seqnum + 1);
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+        break;
+
+      case NBS_LOADING:
+      case NBS_FULL:
+        /* duplicate dbdesc cause slave to retransmit */
+        if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd))
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  duplicate dbdesc, retransmit");
+
+            if (o6n->thread_rxmt_dbdesc)
+              thread_cancel (o6n->thread_rxmt_dbdesc);
+            o6n->thread_rxmt_dbdesc =
+              thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0);
+
+            return;
+          }
+        else
+          {
+            if (IS_OSPF6_DUMP_DBDESC)
+              zlog_info ("  not duplicate dbdesc in state %s",
+                         ospf6_neighbor_state_string[o6n->state]);
+            thread_add_event (master, seqnumber_mismatch, o6n, 0);
+            return;
+          }
+        break; /* not reached */
+
+      default:
+        assert (0);
+        break; /* not reached */
+    }
+
+  /* process LSA headers */
+  lsa_count = 0;
+  for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
+       (char *)(lsa_header + 1) <= (char *)dbdesc + length;
+       lsa_header++)
+    {
+      if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0)
+        {
+          thread_add_event (master, seqnumber_mismatch, o6n, 0);
+          return;
+        }
+      lsa_count ++;
+    }
+
+  /* set dbdesc seqnum to master's */
+  o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum);
+
+  if (o6n->thread_send_dbdesc)
+    thread_cancel (o6n->thread_send_dbdesc);
+  o6n->thread_send_dbdesc =
+    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+  /* save last received dbdesc */
+  memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc));
+
+  /* statistics */
+  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count;
+
+  return;
+}
+
+void
+ospf6_process_dbdesc (struct iovec *message,
+                      struct in6_addr *src,
+                      struct in6_addr *dst,
+                      struct ospf6_interface *o6i,
+                      u_int32_t router_id)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length;
+  struct ospf6_neighbor *o6n;
+  struct ospf6_dbdesc *dbdesc;
+  int Im_master = 0;
+
+  /* assert interface */
+  assert (o6i);
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* set database description pointer */
+  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+
+  /* find neighbor. if cannot be found, reject this message */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (!o6n)
+    {
+      if (IS_OSPF6_DUMP_DBDESC)
+        zlog_info ("neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* interface mtu check */
+    /* xxx */
+
+  /* check am I master */
+  Im_master = ospf6_dbdesc_is_master (o6n);
+  if (Im_master < 0)
+    {
+      return; /* can't decide which is master, return */
+    }
+
+  if (Im_master)
+    ospf6_process_dbdesc_master (message, o6n);
+  else
+    ospf6_process_dbdesc_slave (message, o6n);
+
+  return;
+}
+
+void
+ospf6_process_lsreq (struct iovec *message,
+                     struct in6_addr *src,
+                     struct in6_addr *dst,
+                     struct ospf6_interface *o6i,
+                     u_int32_t router_id)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length;
+  struct ospf6_neighbor *o6n;
+  struct ospf6_lsreq *lsreq;
+  struct iovec response[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsa *lsa;
+  unsigned long lsanum = 0;
+  struct ospf6_lsupdate lsupdate;
+  char buf_id[16], buf_router[16], buf_type[16];
+
+  /* assert interface */
+  assert (o6i);
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* find neighbor. if cannot be found, reject this message */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (!o6n)
+    {
+      if (IS_OSPF6_DUMP_LSREQ)
+        zlog_info ("  neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* In states other than ExChange, Loading, or Full, the packet
+     should be ignored. */
+  if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING
+      && o6n->state != NBS_FULL)
+    {
+      if (IS_OSPF6_DUMP_LSREQ)
+        zlog_info ("  neighbor state less than Exchange, reject");
+      return;
+    }
+
+  /* Initialize response LSUpdate packet */
+  OSPF6_MESSAGE_CLEAR (response);
+  memset (&lsupdate, 0, sizeof (struct ospf6_lsupdate));
+  OSPF6_MESSAGE_ATTACH (response, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+  /* process each request */
+  lsanum = 0;
+  for (lsreq = (struct ospf6_lsreq *) message[1].iov_base;
+       (char *)(lsreq + 1) <= (char *)(message[1].iov_base + length);
+       lsreq++)
+    {
+      inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
+      inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
+
+      /* find instance of database copy */
+      lsa = ospf6_lsdb_lookup (lsreq->type, lsreq->id, lsreq->adv_router,
+                               ospf6_lsa_get_scope (lsreq->type, o6i));
+
+      if (!lsa)
+        {
+          if (IS_OSPF6_DUMP_LSREQ)
+            zlog_info ("BadLSReq: %s requests [%s ID=%s Adv=%s] not found",
+                       o6n->str, ospf6_lsa_type_string (lsreq->type, buf_type,
+                                                        sizeof (buf_type)),
+                       buf_id, buf_router);
+          thread_add_event (master, bad_lsreq, o6n, 0);
+          return;
+        }
+
+      /* I/F MTU check */
+      if (sizeof (struct ospf6_header) + sizeof (struct ospf6_lsupdate)
+          + iov_totallen (response) + ntohs (lsa->header->length)
+          > o6i->ifmtu)
+        break;
+
+      OSPF6_MESSAGE_ATTACH (response, lsa->header, ntohs (lsa->header->length));
+      lsanum++;
+    }
+
+  /* send response LSUpdate to this request */
+  if (lsanum)
+    {
+      lsupdate.lsupdate_num = htonl (lsanum);
+
+      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, response,
+                          &o6n->hisaddr, o6i->if_id);
+    }
+
+  /* statistics */
+  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ]
+    += length / sizeof (struct ospf6_lsreq);
+}
+
+void
+ospf6_process_lsupdate (struct iovec *message,
+                        struct in6_addr *src,
+                        struct in6_addr *dst,
+                        struct ospf6_interface *o6i,
+                        u_int32_t router_id)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length;
+  struct ospf6_lsupdate *lsupdate;
+  struct ospf6_neighbor *o6n;
+  unsigned long lsanum;
+  struct ospf6_lsa_header *lsa_header;
+
+  /* assert interface */
+  assert (o6i);
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* find neighbor. if cannot be found, reject this message */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (! o6n)
+    {
+      if (IS_OSPF6_DUMP_LSUPDATE)
+        zlog_info ("  neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* if neighbor state less than ExChange, reject this message */
+  if (o6n->state < NBS_EXCHANGE)
+    {
+      if (IS_OSPF6_DUMP_LSUPDATE)
+        zlog_info ("  neighbor state less than Exchange, reject");
+      return;
+    }
+
+  /* set linkstate update pointer */
+  lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+
+  /* save linkstate update info */
+  lsanum = ntohl (lsupdate->lsupdate_num);
+
+  /* statistics */
+  o6n->ospf6_stat_received_lsa += lsanum;
+  o6n->ospf6_stat_received_lsupdate++;
+
+  /* RFC2328 Section 10.9: When the neighbor responds to these requests
+     with the proper Link State Update packet(s), the Link state request
+     list is truncated and a new Link State Request packet is sent. */
+
+  /* process LSAs */
+  for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1);
+       lsanum && (char *)lsa_header < (char *)lsupdate + length;
+       lsanum--)
+    {
+      ospf6_dbex_receive_lsa (lsa_header, o6n);
+      lsa_header = OSPF6_LSA_NEXT (lsa_header);
+    }
+
+  /* send new Link State Request packet if this LS Update packet
+     can be recognized as a response to our previous LS request */
+  if (! IN6_IS_ADDR_MULTICAST(dst) &&
+      (o6n->state == NBS_EXCHANGE || o6n->state == NBS_LOADING))
+    thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+
+  return;
+}
+
+void
+ospf6_process_lsack (struct iovec *message,
+                     struct in6_addr *src,
+                     struct in6_addr *dst,
+                     struct ospf6_interface *o6i,
+                     u_int32_t router_id)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length;
+  struct ospf6_neighbor *o6n;
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *lsa, *copy, *rem;
+
+  /* assert interface */
+  assert (o6i);
+
+  /* caluculate length */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
+  length = (length < message[1].iov_len ? length : message[1].iov_len);
+
+  /* find neighbor. if cannot be found, reject this message */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (!o6n)
+    {
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* if neighbor state less than ExChange, reject this message */
+  if (o6n->state < NBS_EXCHANGE)
+    {
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: neighbor state less than Exchange, reject");
+      return;
+    }
+
+  /* process each LSA header */
+  for (lsa_header = (struct ospf6_lsa_header *) message[1].iov_base;
+       (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + length);
+       lsa_header++)
+    {
+      /* find database copy */
+      copy = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
+                                lsa_header->advrtr,
+                                ospf6_lsa_get_scope (lsa_header->type, o6i));
+
+      /* if no database copy */
+      if (!copy)
+        {
+          if (IS_OSPF6_DUMP_LSACK)
+            zlog_info ("LSACK: no database copy, ignore");
+          continue;
+        }
+
+      /* if not on his retrans list */
+      rem = ospf6_lsdb_lookup_lsdb (copy->header->type, copy->header->id,
+                                    copy->header->adv_router,
+                                    o6n->retrans_list);
+      if (rem == NULL)
+        {
+          if (IS_OSPF6_DUMP_LSACK)
+            zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str);
+          continue;
+        }
+
+      /* create temporary LSA from Ack message */
+      lsa = ospf6_lsa_summary_create ((struct ospf6_lsa_header__ *) lsa_header);
+
+      /* if the same instance, remove from retrans list.
+         else, log and ignore */
+      if (ospf6_lsa_check_recent (lsa, copy) == 0)
+        ospf6_neighbor_retrans_remove (rem, o6n);
+      else
+        {
+          /* Log the questionable acknowledgement,
+             and examine the next one. */
+          zlog_info ("LSACK: questionable acknowledge: %s", copy->str);
+          zlog_info ("LSACK:   received: seq: %#x age: %hu",
+                     ntohl (lsa->header->seqnum),
+                     ntohs (lsa->header->age));
+          zlog_info ("LSACK:   instance: seq: %#x age: %hu",
+                     ntohl (copy->header->seqnum),
+                     ospf6_lsa_age_current (copy));
+        }
+
+      /* release temporary LSA from Ack message */
+      ospf6_lsa_delete (lsa);
+    }
+
+  ospf6_maxage_remover ();
+  return;
+}
+
+struct {
+  void (*process) (struct iovec *, struct in6_addr *, struct in6_addr *,
+                   struct ospf6_interface *, u_int32_t);
+} ospf6_message_process_type [] =
+{
+  {ospf6_process_unknown},
+  {ospf6_process_hello},
+  {ospf6_process_dbdesc},
+  {ospf6_process_lsreq},
+  {ospf6_process_lsupdate},
+  {ospf6_process_lsack}
+};
+
+/* process ospf6 protocol header. then, call next process function
+   for each message type */
+static void 
+ospf6_message_process (struct iovec *message,
+                       struct in6_addr *src,
+                       struct in6_addr *dst,
+                       struct ospf6_interface *o6i)
+{
+  struct ospf6_header *ospf6_header = NULL;
+  u_char type;
+  u_int32_t router_id;
+  char srcname[64];
+
+  assert (o6i);
+  assert (src);
+  assert (dst);
+
+  /* set ospf6_hdr pointer to head of buffer */
+  ospf6_header = (struct ospf6_header *) message[0].iov_base;
+
+  /* version check */
+  if (ospf6_header->version != OSPF6_VERSION)
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("version mismatch, drop");
+      return;
+    }
+
+  /* area id check */
+  if (ospf6_header->area_id != o6i->area->area_id)
+    {
+      if (ospf6_header->area_id == 0)
+        {
+          if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+            zlog_info ("virtual link not yet, drop");
+          return;
+        }
+
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("area id mismatch, drop");
+      return;
+    }
+
+  /* instance id check */
+  if (ospf6_header->instance_id != o6i->instance_id)
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("instance id mismatch, drop");
+      return;
+    }
+
+  /* message type check */
+  type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ?
+          OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type);
+
+  /* log */
+  if (IS_OSPF6_DUMP_MESSAGE (type))
+    {
+      char srcname[64], dstname[64];
+      inet_ntop (AF_INET6, dst, dstname, sizeof (dstname));
+      inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
+      zlog_info ("Receive %s on %s",
+                 ospf6_message_type_string[type], o6i->interface->name);
+      zlog_info ("    %s -> %s", srcname, dstname);
+      ospf6_message_log (message);
+    }
+
+  /* router id check */
+  router_id = ospf6_header->router_id;
+  if (ospf6_header->router_id == o6i->area->ospf6->router_id)
+    {
+      inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
+      zlog_warn ("*** Router-ID mismatch: from %s on %s",
+                 srcname, o6i->interface->name);
+      return;
+    }
+
+  /* octet statistics relies on some asumption:
+       on ethernet, no IPv6 Extention header, etc */
+#define OSPF6_IP6_HEADER_SIZE   40
+#define OSPF6_ETHER_HEADER_SIZE 14
+  o6i->message_stat[type].recv++;
+  o6i->message_stat[type].recv_octet += ntohs (ospf6_header->len)
+    + OSPF6_IP6_HEADER_SIZE + OSPF6_ETHER_HEADER_SIZE;
+
+  /* futher process */
+  (*ospf6_message_process_type[type].process) (&message[0], src, dst, o6i, router_id);
+
+  return;
+}
+
+int
+ospf6_receive (struct thread *thread)
+{
+  int sockfd;
+  struct in6_addr src, dst;
+  unsigned int ifindex;
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_header ospf6_header;
+  char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE];
+  struct ospf6_interface *o6i;
+  unsigned char type;
+
+  /* get socket */
+  sockfd = THREAD_FD (thread);
+
+  /* add next read thread */
+  thread_add_read (master, ospf6_receive, NULL, sockfd);
+
+  /* initialize */
+  OSPF6_MESSAGE_CLEAR (message);
+  memset (&ospf6_header, 0, sizeof (struct ospf6_header));
+
+  OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
+  OSPF6_MESSAGE_ATTACH (message, buffer, OSPF6_MESSAGE_RECEIVE_BUFSIZE);
+
+  /* receive message */
+  ospf6_recvmsg (&src, &dst, &ifindex, message);
+
+  type = (OSPF6_MESSAGE_TYPE_UNKNOWN < ospf6_header.type &&
+          ospf6_header.type <= OSPF6_MESSAGE_TYPE_LSACK ?
+          ospf6_header.type : OSPF6_MESSAGE_TYPE_UNKNOWN);
+  o6i = ospf6_interface_lookup_by_index (ifindex);
+  if (!o6i || !o6i->area)
+    {
+      //zlog_warn ("*** received interface ospf6 disabled");
+      return 0;
+    }
+
+  /* if not passive, process message */
+  if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+    ospf6_message_process (message, &src, &dst, o6i);
+  else if (IS_OSPF6_DUMP_MESSAGE (type))
+    zlog_info ("Ignore message on passive interface %s",
+               o6i->interface->name);
+
+  return 0;
+}
+
+\f
+/* send section */
+int
+ospf6_message_length (struct iovec *message)
+{
+  int i, length = 0;
+  for (i = 0; i < OSPF6_MESSAGE_IOVEC_SIZE; i++)
+    {
+      if (message[i].iov_base == NULL && message[i].iov_len == 0)
+        break;
+      length += message[i].iov_len;
+    }
+  return length;
+}
+#define OSPF6_MESSAGE_LENGTH(msg) \
+(ospf6_message_length (msg))
+
+void
+ospf6_message_send (unsigned char type, struct iovec *msg,
+                    struct in6_addr *dst, u_int ifindex)
+{
+  struct ospf6_interface *o6i;
+  struct ospf6_header ospf6_header;
+  char dst_name[64], src_name[64];
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  int msg_len;
+
+  /* ospf6 interface lookup */
+  o6i = ospf6_interface_lookup_by_index (ifindex);
+  assert (o6i);
+
+  msg_len = OSPF6_MESSAGE_LENGTH (msg);
+
+  /* I/F MTU check */
+#if 0
+  if (msg_len + sizeof (struct ospf6_header) >= o6i->interface->mtu)
+#else
+  if (msg_len + sizeof (struct ospf6_header) >= o6i->ifmtu)
+#endif
+    {
+      /* If Interface MTU is 0, save the case
+         since zebra had been failed to get MTU from Kernel */
+      if (o6i->interface->mtu != 0)
+        {
+          zlog_warn ("Message: Send failed on %s: exceeds I/F MTU",
+                     o6i->interface->name);
+          zlog_warn ("Message:   while sending %s: Len:%d MTU:%d",
+                     ospf6_message_type_string[type],
+                     msg_len + sizeof (struct ospf6_header),
+                     o6i->ifmtu);
+          return;
+        }
+      else
+        {
+          zlog_warn ("Message: I/F MTU check ignored on %s",
+                     o6i->interface->name);
+        }
+    }
+
+  /* Initialize */
+  OSPF6_MESSAGE_CLEAR (message);
+
+  /* set OSPF header */
+  memset (&ospf6_header, 0, sizeof (ospf6_header));
+  ospf6_header.version = OSPF6_VERSION;
+  ospf6_header.type = type;
+  ospf6_header.len = htons (msg_len + sizeof (struct ospf6_header));
+  ospf6_header.router_id = ospf6->router_id;
+  ospf6_header.area_id = o6i->area->area_id;
+  /* checksum is calculated by kernel */
+  ospf6_header.instance_id = o6i->instance_id;
+  ospf6_header.reserved = 0;
+  OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
+
+  /* Attach rest to message */
+  OSPF6_MESSAGE_JOIN (message, msg);
+
+  /* statistics */
+  if (type >= OSPF6_MESSAGE_TYPE_MAX)
+    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+  o6i->message_stat[type].send++;
+  o6i->message_stat[type].send_octet += ntohs (ospf6_header.len);
+
+  /* log */
+  if (IS_OSPF6_DUMP_MESSAGE (type))
+    {
+      inet_ntop (AF_INET6, dst, dst_name, sizeof (dst_name));
+      if (o6i->lladdr)
+        inet_ntop (AF_INET6, o6i->lladdr, src_name, sizeof (src_name));
+      else
+        memcpy (src_name, "Unknown", sizeof (src_name));
+      zlog_info ("Send %s on %s",
+                 ospf6_message_type_string[type], o6i->interface->name);
+      zlog_info ("    %s -> %s", src_name, dst_name);
+      ospf6_message_log (message);
+    }
+
+  /* send message */
+  ospf6_sendmsg (o6i->lladdr, dst, &ifindex, message);
+}
+
+
+int
+ospf6_send_hello (struct thread *thread)
+{
+  listnode n;
+  struct ospf6_interface *o6i;
+  struct ospf6_neighbor *o6n;
+  struct in6_addr dst;
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_hello hello;
+  char router_buffer[1024]; /* xxx */
+  u_int router_size;
+
+  /* which ospf6 interface to send */
+  o6i = (struct ospf6_interface *) THREAD_ARG (thread);
+  o6i->thread_send_hello = (struct thread *) NULL;
+
+  /* assure interface is up */
+  if (o6i->state <= IFS_DOWN)
+    {
+      if (IS_OSPF6_DUMP_HELLO)
+        zlog_warn ("Send HELLO Failed: Interface not enabled: %s",
+                   o6i->interface->name);
+      return 0;
+    }
+
+  /* clear message buffer */
+  OSPF6_MESSAGE_CLEAR (message);
+
+  /* set Hello fields */
+  hello.interface_id = htonl (o6i->if_id);
+  hello.rtr_pri = o6i->priority;
+  memcpy (hello.options, o6i->area->options, sizeof (hello.options));
+  hello.hello_interval = htons (o6i->hello_interval);
+  hello.router_dead_interval = htons (o6i->dead_interval);
+  hello.dr = o6i->dr;
+  hello.bdr = o6i->bdr;
+  OSPF6_MESSAGE_ATTACH (message, &hello, sizeof (struct ospf6_hello));
+
+  /* set neighbor router id */
+  router_size = 0;
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+
+      if (o6n->state < NBS_INIT)
+        continue;
+
+      if (router_size + sizeof (o6n->router_id) > sizeof (router_buffer))
+        {
+          zlog_warn ("Send HELLO: Buffer shortage on %s",
+                     o6i->interface->name);
+          break;
+        }
+
+      /* Copy Router-ID to Buffer */
+      memcpy (router_buffer + router_size, &o6n->router_id,
+              sizeof (o6n->router_id));
+      router_size += sizeof (o6n->router_id);
+    }
+  OSPF6_MESSAGE_ATTACH (message, router_buffer, router_size);
+
+  /* set destionation */
+  inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
+
+  /* send hello */
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_HELLO, message, &dst,
+                      o6i->interface->ifindex);
+
+  /* set next timer thread */
+  o6i->thread_send_hello = thread_add_timer (master, ospf6_send_hello,
+                                             o6i, o6i->hello_interval);
+
+  return 0;
+}
+
+void
+ospf6_dbdesc_seqnum_init (struct ospf6_neighbor *o6n)
+{
+  struct timeval tv;
+
+  if (gettimeofday (&tv, (struct timezone *) NULL) < 0)
+    tv.tv_sec = 1;
+
+  o6n->dbdesc_seqnum = tv.tv_sec;
+
+  if (IS_OSPF6_DUMP_DBDESC)
+    zlog_info ("set dbdesc seqnum %d for %s", o6n->dbdesc_seqnum, o6n->str);
+}
+
+int
+ospf6_send_dbdesc_rxmt (struct thread *thread)
+{
+  struct ospf6_lsdb_node node;
+  struct ospf6_neighbor *o6n;
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_dbdesc dbdesc;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  /* clear thread */
+  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+  /* if state less than ExStart, do nothing */
+  if (o6n->state < NBS_EXSTART)
+    return 0;
+
+  OSPF6_MESSAGE_CLEAR (message);
+
+  /* set dbdesc */
+  memcpy (dbdesc.options, o6n->ospf6_interface->area->options,
+          sizeof (dbdesc.options));
+  dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu);
+  dbdesc.bits = o6n->dbdesc_bits;
+  dbdesc.seqnum = htonl (o6n->dbdesc_seqnum);
+  OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc));
+
+  /* if this is not initial, set LSA summary to dbdesc */
+  if (! DD_IS_IBIT_SET (o6n->dbdesc_bits))
+    {
+      for (ospf6_lsdb_head (&node, o6n->dbdesc_list);
+           ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+        {
+          lsa = node.lsa;
+
+          /* xxx, no MTU check: no support for Dynamic MTU change */
+
+          /* set age and add InfTransDelay */
+          ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+
+          /* set LSA summary to send buffer */
+          lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
+          OSPF6_MESSAGE_ATTACH (message, lsa_header,
+                                sizeof (struct ospf6_lsa_header));
+        }
+    }
+
+  /* send dbdesc */
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr,
+                      o6n->ospf6_interface->interface->ifindex);
+
+  /* if master, set futher retransmission */
+  if (DD_IS_MSBIT_SET (o6n->dbdesc_bits))
+    o6n->thread_rxmt_dbdesc =
+      thread_add_timer (master, ospf6_send_dbdesc_rxmt,
+                        o6n, o6n->ospf6_interface->rxmt_interval);
+
+  /* statistics */
+  o6n->ospf6_stat_retrans_dbdesc++;
+
+  return 0;
+}
+
+int
+ospf6_send_dbdesc (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+  struct ospf6_lsa *lsa;
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_dbdesc dbdesc;
+  struct ospf6_lsdb_node node;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  /* clear thread */
+  o6n->thread_send_dbdesc = (struct thread *) NULL;
+  if (o6n->thread_rxmt_dbdesc)
+    thread_cancel (o6n->thread_rxmt_dbdesc);
+  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+  /* if state less than ExStart, do nothing */
+  if (o6n->state < NBS_EXSTART)
+    return 0;
+
+  OSPF6_MESSAGE_CLEAR (message);
+  OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc));
+
+  /* clear previous LSA summary sent */
+  ospf6_lsdb_remove_all (o6n->dbdesc_list);
+  assert (o6n->dbdesc_list->count == 0);
+
+  /* if this is not initial, set LSA summary to dbdesc */
+  if (! DD_IS_IBIT_SET (o6n->dbdesc_bits))
+    {
+      for (ospf6_lsdb_head (&node, o6n->summary_list);
+           ! ospf6_lsdb_is_end (&node);
+           ospf6_lsdb_next (&node))
+        {
+          lsa = node.lsa;
+
+          /* MTU check */
+          if (OSPF6_MESSAGE_LENGTH (message)
+              + sizeof (struct ospf6_lsa_header)
+              + sizeof (struct ospf6_header)
+              > o6n->ospf6_interface->ifmtu)
+            break;
+
+          /* debug */
+          if (IS_OSPF6_DUMP_DBDESC)
+            zlog_info ("Include DbDesc: %s", lsa->str);
+
+          /* attach to dbdesclist */
+          ospf6_neighbor_dbdesc_add (lsa, o6n);
+          /* detach from summarylist */
+          ospf6_neighbor_summary_remove (lsa, o6n);
+
+          /* set age and add InfTransDelay */
+          ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+
+          /* set LSA summary to send buffer */
+          OSPF6_MESSAGE_ATTACH (message, lsa->header,
+                                sizeof (struct ospf6_lsa_header));
+        }
+
+      if (o6n->summary_list->count == 0)
+        {
+          /* Clear more bit */
+          DD_MBIT_CLEAR (o6n->dbdesc_bits);
+
+          /* slave must schedule ExchangeDone on sending, here */
+          if (! DD_IS_MSBIT_SET (o6n->dbdesc_bits))
+            {
+              if (! DD_IS_MBIT_SET (o6n->dbdesc_bits) &&
+                  ! DD_IS_MBIT_SET (o6n->last_dd.bits))
+                thread_add_event (master, exchange_done, o6n, 0);
+            }
+        }
+    }
+
+  /* if this is initial, set seqnum */
+  if (DDBIT_IS_INITIAL (o6n->dbdesc_bits))
+    ospf6_dbdesc_seqnum_init (o6n);
+
+  /* set dbdesc */
+  memcpy (dbdesc.options, o6n->ospf6_interface->area->options,
+          sizeof (dbdesc.options));
+  dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu);
+  dbdesc.bits = o6n->dbdesc_bits;
+  dbdesc.seqnum = htonl (o6n->dbdesc_seqnum);
+
+  /* send dbdesc */
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr,
+                      o6n->ospf6_interface->interface->ifindex);
+
+  /* if master, set retransmission */
+  if (DD_IS_MSBIT_SET (o6n->dbdesc_bits))
+    o6n->thread_rxmt_dbdesc =
+      thread_add_timer (master, ospf6_send_dbdesc_rxmt,
+                          o6n, o6n->ospf6_interface->rxmt_interval);
+
+  /* statistics */
+  o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC] += o6n->dbdesc_list->count;
+
+  return 0;
+}
+
+int
+ospf6_send_lsreq_rxmt (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+  o6n->thread_send_lsreq = thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+  return 0;
+}
+
+int
+ospf6_send_lsreq (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsreq lsreq[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsdb_node node;
+  int i;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  /* LSReq will be send only in ExStart or Loading */
+  if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING)
+    return 0;
+
+  /* clear thread */
+  o6n->thread_send_lsreq = (struct thread *) NULL;
+  if (o6n->thread_rxmt_lsreq)
+    thread_cancel (o6n->thread_rxmt_lsreq);
+  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+
+  /* schedule loading_done if request list is empty */
+  if (o6n->request_list->count == 0)
+    {
+      thread_add_event (master, loading_done, o6n, 0);
+      return 0;
+    }
+
+  /* clear message buffer */
+  OSPF6_MESSAGE_CLEAR (message);
+
+  i = 0;
+  for (ospf6_lsdb_head (&node, o6n->request_list);
+       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+    {
+      lsa = node.lsa;
+
+      /* Buffer Overflow */
+      if (i >= OSPF6_MESSAGE_IOVEC_SIZE)
+        break;
+
+      /* I/F MTU check */
+      if (OSPF6_MESSAGE_LENGTH (message)
+          + sizeof (struct ospf6_lsreq)
+          + sizeof (struct ospf6_header)
+          > o6n->ospf6_interface->ifmtu)
+        break;
+
+      lsreq[i].mbz = 0;
+      lsreq[i].type = lsa->header->type;
+      lsreq[i].id = lsa->header->id;
+      lsreq[i].adv_router = lsa->header->adv_router;
+
+      OSPF6_MESSAGE_ATTACH (message, &lsreq[i], sizeof (struct ospf6_lsreq));
+      i++;
+    }
+
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSREQ, message, &o6n->hisaddr,
+                      o6n->ospf6_interface->interface->ifindex);
+
+  /* set retransmit thread */
+  o6n->thread_rxmt_lsreq =
+    thread_add_timer (master, ospf6_send_lsreq_rxmt,
+                      o6n, o6n->ospf6_interface->rxmt_interval);
+
+  /* statistics */
+  o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ] += i;
+
+  return 0;
+}
+
+/* Send LSUpdate directly to the neighbor, from his retransmission list */
+int
+ospf6_send_lsupdate_rxmt (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsupdate lsupdate;
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsdb_node node;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  o6n->send_update = (struct thread *) NULL;
+
+  if (o6n->ospf6_interface->state <= IFS_WAITING)
+    return -1;
+
+  /* clear message buffer */
+  OSPF6_MESSAGE_CLEAR (message);
+
+  /* set lsupdate header */
+  lsupdate.lsupdate_num = 0; /* set gradually */
+  OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+  /* for each LSA listed on retransmission-list */
+  for (ospf6_lsdb_head (&node, o6n->retrans_list);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      lsa = node.lsa;
+
+      /* I/F MTU check */
+      if (OSPF6_MESSAGE_LENGTH (message)
+          + sizeof (struct ospf6_lsupdate)
+          + sizeof (struct ospf6_header)
+          + ntohs (lsa->header->length)
+          > o6n->ospf6_interface->ifmtu)
+        break;
+
+      ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+      OSPF6_MESSAGE_ATTACH (message, lsa->header, ntohs (lsa->header->length));
+      lsupdate.lsupdate_num++;
+    }
+
+  /* check and correct lsupdate */
+  if (lsupdate.lsupdate_num == 0)
+    return 0;
+  lsupdate.lsupdate_num = htonl (lsupdate.lsupdate_num);
+
+  if (IS_OSPF6_DUMP_LSUPDATE)
+    zlog_info ("MESSAGE: retrsnsmit LSUpdate to %s", o6n->str);
+
+  /* statistics */
+  o6n->ospf6_stat_retrans_lsupdate++;
+
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message,
+                      &o6n->hisaddr, o6n->ospf6_interface->if_id);
+
+  o6n->send_update = thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
+                                       o6n->ospf6_interface->rxmt_interval);
+  return 0;
+}
+
+/* Send LSUpdate containing one LSA directly to the neighbor.
+   This is "implied acknowledgement" */
+void
+ospf6_send_lsupdate_direct (struct ospf6_lsa *lsa, struct ospf6_neighbor *o6n)
+{
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsupdate lsupdate;
+  int lsa_len;
+
+  /* clear message buffer */
+  OSPF6_MESSAGE_CLEAR (message);
+
+  /* set lsupdate header */
+  lsupdate.lsupdate_num = ntohl (1);
+  OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+  /* set one LSA */
+  lsa_len = ntohs (lsa->lsa_hdr->lsh_len);
+  ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
+  OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len);
+
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &o6n->hisaddr,
+                      o6n->ospf6_interface->if_id);
+}
+
+/* Send LSUpdate containing one LSA by multicast.
+   On non-broadcast link, send it to each neighbor by unicast.
+   This is ordinary flooding */
+void
+ospf6_send_lsupdate_flood (struct ospf6_lsa *lsa, struct ospf6_interface *o6i)
+{
+  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_lsupdate lsupdate;
+  struct in6_addr dst;
+  int lsa_len;
+
+  /* clear message buffer */
+  OSPF6_MESSAGE_CLEAR (message);
+
+  /* set lsupdate header */
+  lsupdate.lsupdate_num = ntohl (1);
+  OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
+
+  /* set one LSA */
+  lsa_len = ntohs (lsa->lsa_hdr->lsh_len);
+  ospf6_lsa_age_update_to_send (lsa, o6i->transdelay);
+  OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len);
+
+  if (if_is_broadcast (o6i->interface))
+    {
+      /* set destination */
+      if (o6i->state == IFS_DR || o6i->state == IFS_BDR)
+        inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
+      else
+        inet_pton (AF_INET6, ALLDROUTERS6, &dst);
+    }
+  else
+    {
+      /* IPv6 relies on link local multicast */
+      inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
+    }
+
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &dst,
+                      o6i->if_id);
+}
+
+int
+ospf6_send_lsack_delayed (struct thread *thread)
+{
+  struct ospf6_interface *o6i;
+  struct iovec message[MAXIOVLIST];
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsdb_node node;
+
+  o6i = THREAD_ARG (thread);
+  assert (o6i);
+
+  if (IS_OSPF6_DUMP_LSACK)
+    zlog_info ("LSACK: Delayed LSAck for %s\n", o6i->interface->name);
+
+  o6i->thread_send_lsack_delayed = (struct thread *) NULL;
+
+  if (o6i->state <= IFS_WAITING)
+    return 0;
+
+  if (o6i->ack_list->count == 0)
+    return 0;
+
+  iov_clear (message, MAXIOVLIST);
+
+  for (ospf6_lsdb_head (&node, o6i->ack_list);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      lsa = node.lsa;
+      if (IS_OVER_MTU (message, o6i->ifmtu, sizeof (struct ospf6_lsa_hdr)))
+        break;
+
+      OSPF6_MESSAGE_ATTACH (message, lsa->header,
+                            sizeof (struct ospf6_lsa_header));
+      ospf6_interface_delayed_ack_remove (lsa, o6i);
+    }
+
+  /* statistics */
+  o6i->ospf6_stat_delayed_lsack++;
+
+  switch (o6i->state)
+    {
+    case IFS_DR:
+    case IFS_BDR:
+      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message,
+                          &allspfrouters6.sin6_addr, o6i->if_id);
+      break;
+    default:
+      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message,
+                          &alldrouters6.sin6_addr, o6i->if_id);
+      break;
+    }
+
+  iov_clear (message, MAXIOVLIST);
+  return 0;
+}
+
diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h
new file mode 100644 (file)
index 0000000..105cb4f
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_MESSAGE_H
+#define OSPF6_MESSAGE_H
+
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+
+/* Type */
+#define OSPF6_MESSAGE_TYPE_NONE     0x0
+#define OSPF6_MESSAGE_TYPE_UNKNOWN  0x0
+#define OSPF6_MESSAGE_TYPE_HELLO    0x1  /* Discover/maintain neighbors */
+#define OSPF6_MESSAGE_TYPE_DBDESC   0x2  /* Summarize database contents */
+#define OSPF6_MESSAGE_TYPE_LSREQ    0x3  /* Database download */
+#define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4  /* Database update */
+#define OSPF6_MESSAGE_TYPE_LSACK    0x5  /* Flooding acknowledgment */
+#define OSPF6_MESSAGE_TYPE_MAX      0x6
+
+/* OSPFv3 packet header */
+struct ospf6_header
+{
+  u_char    version;
+  u_char    type;
+  u_int16_t len;
+  u_int32_t router_id;
+  u_int32_t area_id;
+  u_int16_t cksum;
+  u_char    instance_id;
+  u_char    reserved;
+};
+
+/* Hello */
+#define MAXLISTEDNBR     64
+struct ospf6_hello
+{
+  u_int32_t interface_id;
+  u_char    rtr_pri;
+  u_char    options[3];
+  u_int16_t hello_interval;
+  u_int16_t router_dead_interval;
+  u_int32_t dr;
+  u_int32_t bdr;
+};
+
+/* Database Description */
+struct ospf6_dbdesc
+{
+  u_char    mbz1;
+  u_char    options[3];
+  u_int16_t ifmtu;
+  u_char    mbz2;
+  u_char    bits;
+  u_int32_t seqnum;
+  /* Followed by LSAs */
+};
+#define DEFAULT_INTERFACE_MTU 1500
+
+#define DD_IS_MSBIT_SET(x) ((x) & (1 << 0))
+#define DD_MSBIT_SET(x) ((x) |= (1 << 0))
+#define DD_MSBIT_CLEAR(x) ((x) &= ~(1 << 0))
+#define DD_IS_MBIT_SET(x) ((x) & (1 << 1))
+#define DD_MBIT_SET(x) ((x) |= (1 << 1))
+#define DD_MBIT_CLEAR(x) ((x) &= ~(1 << 1))
+#define DD_IS_IBIT_SET(x) ((x) & (1 << 2))
+#define DD_IBIT_SET(x) ((x) |= (1 << 2))
+#define DD_IBIT_CLEAR(x) ((x) &= ~(1 << 2))
+
+#define DDBIT_IS_MASTER(x)   ((x) &   (1 << 0))
+#define DDBIT_IS_SLAVE(x)  (!((x) &   (1 << 0)))
+#define DDBIT_SET_MASTER(x)  ((x) |=  (1 << 0))
+#define DDBIT_SET_SLAVE(x)   ((x) |= ~(1 << 0))
+#define DDBIT_IS_MORE(x)     ((x) &   (1 << 1))
+#define DDBIT_SET_MORE(x)    ((x) |=  (1 << 1))
+#define DDBIT_CLR_MORE(x)    ((x) |= ~(1 << 1))
+#define DDBIT_IS_INITIAL(x)  ((x) &   (1 << 2))
+#define DDBIT_SET_INITIAL(x) ((x) |=  (1 << 2))
+#define DDBIT_CLR_INITIAL(x) ((x) |= ~(1 << 2))
+
+#define OSPF6_DBDESC_BIT_MASTER  0x01
+#define OSPF6_DBDESC_BIT_MORE    0x02
+#define OSPF6_DBDESC_BIT_INITIAL 0x04
+
+/* Link State Request */
+struct ospf6_lsreq
+{
+  u_int16_t mbz;          /* Must Be Zero */
+  u_int16_t type;         /* LS type */
+  u_int32_t id;           /* Link State ID */
+  u_int32_t adv_router;   /* Advertising Router */
+};
+
+/* Link State Update */
+struct ospf6_lsupdate
+{
+  u_int32_t lsupdate_num;
+};
+
+/* Link State Acknowledgement */
+  /* no need for structure,
+     it will include only LSA header in the packet body.*/
+
+/* definition for ospf6_message.c */
+#define OSPF6_MESSAGE_RECEIVE_BUFSIZE 5120
+#define OSPF6_MESSAGE_IOVEC_END       1024
+
+#define IS_OVER_MTU(message,mtu,addsize) \
+          (iov_totallen(message)+(addsize) >= \
+            (mtu)-sizeof(struct ospf6_header))
+
+#define OSPF6_MESSAGE_IOVEC_SIZE  1024
+#define OSPF6_MESSAGE_CLEAR(msg) \
+do { \
+  int x; \
+  for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
+    { \
+      (msg)[x].iov_base = NULL; \
+      (msg)[x].iov_len = 0; \
+    } \
+} while (0)
+
+#define OSPF6_MESSAGE_ATTACH(msg,buf,bufsize) \
+do { \
+  int x; \
+  for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
+    if ((msg)[x].iov_base == (void *)NULL && (msg)[x].iov_len == 0) \
+      break; \
+  if (x < OSPF6_MESSAGE_IOVEC_SIZE - 1) \
+    { \
+      (msg)[x].iov_base = (void *)(buf); \
+      (msg)[x].iov_len = (bufsize); \
+    } \
+} while (0)
+
+#define OSPF6_MESSAGE_JOIN(msg,join) \
+do { \
+  int x,y; \
+  for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
+    if ((msg)[x].iov_base == NULL && (msg)[x].iov_len == 0) \
+      break; \
+  for (y = x; y < OSPF6_MESSAGE_IOVEC_SIZE; y++) \
+    { \
+      (msg)[y].iov_base = (join)[y - x].iov_base; \
+      (msg)[y].iov_len = (join)[y - x].iov_len; \
+    } \
+} while (0)
+
+
+/* Statistics */
+struct ospf6_message_stat
+{
+  u_int32_t send;
+  u_int32_t send_octet;
+  u_int32_t recv;
+  u_int32_t recv_octet;
+};
+
+/* Type string */
+extern char *ospf6_message_type_string[];
+
+/* Function Prototypes */
+int ospf6_receive (struct thread *);
+
+int ospf6_send_hello (struct thread *);
+int ospf6_send_dbdesc_rxmt (struct thread *);
+int ospf6_send_dbdesc (struct thread *);
+int ospf6_send_lsreq (struct thread *);
+
+struct ospf6_neighbor;
+struct ospf6_interface;
+int
+ospf6_send_lsupdate_rxmt (struct thread *);
+void
+ospf6_send_lsupdate_direct (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_send_lsupdate_flood (struct ospf6_lsa *, struct ospf6_interface *);
+
+int ospf6_send_lsack_delayed (struct thread *);
+int ospf6_send_lsack_direct (struct thread *);
+
+void ospf6_message_send (u_char, struct iovec *, struct in6_addr *, u_int);
+
+#endif /* OSPF6_MESSAGE_H */
+
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
new file mode 100644 (file)
index 0000000..72735d5
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+#include <zebra.h>
+
+#include "log.h"
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "command.h"
+
+#include "ospf6_lsa.h"
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_nsm.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+char *ospf6_neighbor_state_string[] =
+{
+  "None", "Down", "Attempt", "Init", "Twoway",
+  "ExStart", "ExChange", "Loading", "Full", NULL
+};
+
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+  memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc));
+  return 0;
+}
+
+\f
+
+void
+ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *o6n)
+{
+  if (o6n->inactivity_timer)
+    thread_cancel (o6n->inactivity_timer);
+  o6n->inactivity_timer = (struct thread *) NULL;
+
+  if (o6n->send_update)
+    thread_cancel (o6n->send_update);
+  o6n->send_update = (struct thread *) NULL;
+
+  if (o6n->thread_send_dbdesc)
+    thread_cancel (o6n->thread_send_dbdesc);
+  o6n->thread_send_dbdesc = (struct thread *) NULL;
+  if (o6n->thread_rxmt_dbdesc)
+    thread_cancel (o6n->thread_rxmt_dbdesc);
+  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+  if (o6n->thread_rxmt_lsreq)
+    thread_cancel (o6n->thread_rxmt_lsreq);
+  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+}
+
+void
+ospf6_neighbor_lslist_clear (struct ospf6_neighbor *nei)
+{
+  ospf6_lsdb_remove_all (nei->summary_list);
+  ospf6_lsdb_remove_all (nei->request_list);
+  ospf6_lsdb_remove_all (nei->retrans_list);
+  ospf6_lsdb_remove_all (nei->dbdesc_list);
+}
+
+void
+ospf6_neighbor_summary_add (struct ospf6_lsa *lsa,
+                            struct ospf6_neighbor *nei)
+{
+  struct ospf6_lsa *summary;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s summary-list:", nei->str);
+      zlog_info ("    Add %s", lsa->str);
+    }
+
+  ospf6_lsa_age_current (lsa);
+  summary = ospf6_lsa_summary_create (lsa->header);
+  ospf6_lsdb_add (summary, nei->summary_list);
+}
+
+void
+ospf6_neighbor_summary_remove (struct ospf6_lsa *lsa,
+                               struct ospf6_neighbor *nei)
+{
+  struct ospf6_lsa *summary;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s summary-list:", nei->str);
+      zlog_info ("    Remove %s", lsa->str);
+    }
+
+  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+                                    lsa->header->adv_router, nei->summary_list);
+  ospf6_lsdb_remove (summary, nei->summary_list);
+}
+
+void
+ospf6_neighbor_request_add (struct ospf6_lsa *lsa,
+                            struct ospf6_neighbor *nei)
+{
+  struct ospf6_lsa *summary;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s request-list:", nei->str);
+      zlog_info ("    Add %s", lsa->str);
+    }
+
+  ospf6_lsa_age_current (lsa);
+  summary = ospf6_lsa_summary_create (lsa->header);
+  ospf6_lsdb_add (summary, nei->request_list);
+}
+
+void
+ospf6_neighbor_request_remove (struct ospf6_lsa *lsa,
+                               struct ospf6_neighbor *nei)
+{
+  struct ospf6_lsa *summary;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s request-list:", nei->str);
+      zlog_info ("    Remove %s", lsa->str);
+    }
+
+  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
+                                    lsa->header->adv_router, nei->request_list);
+  ospf6_lsdb_remove (summary, nei->request_list);
+}
+
+void
+ospf6_neighbor_retrans_add (struct ospf6_lsa *lsa,
+                            struct ospf6_neighbor *nei)
+{
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s retrans-list:", nei->str);
+      zlog_info ("    Add %s", lsa->str);
+    }
+
+  ospf6_lsdb_add (lsa, nei->retrans_list);
+}
+
+void
+ospf6_neighbor_retrans_remove (struct ospf6_lsa *lsa,
+                               struct ospf6_neighbor *nei)
+{
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s retrans-list:", nei->str);
+      zlog_info ("    Remove %s", lsa->str);
+    }
+
+  ospf6_lsdb_remove (lsa, nei->retrans_list);
+
+  if (nei->retrans_list->count == 0)
+    {
+      if (nei->send_update)
+        thread_cancel (nei->send_update);
+      nei->send_update = NULL;
+    }
+}
+
+void
+ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
+                           struct ospf6_neighbor *nei)
+{
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s dbdesc-list:", nei->str);
+      zlog_info ("    Add %s", lsa->str);
+    }
+
+  ospf6_lsdb_add (lsa, nei->dbdesc_list);
+}
+
+void
+ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
+                              struct ospf6_neighbor *nei)
+{
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      zlog_info ("Neighbor %s dbdesc-list:", nei->str);
+      zlog_info ("    Remove %s", lsa->str);
+    }
+
+  ospf6_lsdb_remove (lsa, nei->dbdesc_list);
+}
+
+
+/* prepare summary-list of his neighbor structure */
+void
+ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei)
+{
+  struct ospf6_lsdb_node node;
+
+  /* clear ls-list */
+  ospf6_neighbor_lslist_clear (nei);
+
+  /* AS scope LSAs */
+  for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->ospf6->lsdb);
+       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+    {
+      if (IS_LSA_MAXAGE (node.lsa))
+        ospf6_neighbor_retrans_add (node.lsa, nei);
+      else
+        ospf6_neighbor_summary_add (node.lsa, nei);
+    }
+
+  /* AREA scope LSAs */
+  for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->lsdb);
+       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+    {
+      if (IS_LSA_MAXAGE (node.lsa))
+        ospf6_neighbor_retrans_add (node.lsa, nei);
+      else
+        ospf6_neighbor_summary_add (node.lsa, nei);
+    }
+
+  /* INTERFACE scope LSAs */
+  for (ospf6_lsdb_head (&node, nei->ospf6_interface->lsdb);
+       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+    {
+      if (IS_LSA_MAXAGE (node.lsa))
+        ospf6_neighbor_retrans_add (node.lsa, nei);
+      else
+        ospf6_neighbor_summary_add (node.lsa, nei);
+    }
+}
+
+/* create ospf6_neighbor */
+struct ospf6_neighbor *
+ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *o6i)
+{
+  struct ospf6_neighbor *new;
+  char buf[32];
+
+  new = (struct ospf6_neighbor *)
+    XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor));
+  if (new == NULL)
+    {
+      zlog_warn ("neighbor: malloc failed");
+      return NULL;
+    }
+
+  memset (new, 0, sizeof (struct ospf6_neighbor));
+
+  new->state = OSPF6_NEIGHBOR_STATE_DOWN;
+
+  new->router_id = router_id;
+  inet_ntop (AF_INET, &router_id, buf, sizeof (buf));
+  snprintf (new->str, sizeof (new->str), "%s%%%s", buf, o6i->interface->name);
+  new->inactivity_timer = (struct thread *) NULL;
+
+  new->summary_list = ospf6_lsdb_create ();
+  new->request_list = ospf6_lsdb_create ();
+  new->retrans_list = ospf6_lsdb_create ();
+  new->dbdesc_list = ospf6_lsdb_create ();
+
+  listnode_add (o6i->neighbor_list, new);
+  new->ospf6_interface = o6i;
+
+  CALL_ADD_HOOK (&neighbor_hook, new);
+
+  return new;
+}
+
+void
+ospf6_neighbor_delete (struct ospf6_neighbor *o6n)
+{
+  CALL_REMOVE_HOOK (&neighbor_hook, o6n);
+
+  ospf6_neighbor_thread_cancel_all (o6n);
+  ospf6_neighbor_lslist_clear (o6n);
+
+  list_free (o6n->dbdesc_lsa);
+
+  ospf6_lsdb_delete (o6n->summary_list);
+  ospf6_lsdb_delete (o6n->request_list);
+  ospf6_lsdb_delete (o6n->retrans_list);
+  ospf6_lsdb_delete (o6n->dbdesc_list);
+
+  XFREE (MTYPE_OSPF6_NEIGHBOR, o6n);
+}
+
+struct ospf6_neighbor *
+ospf6_neighbor_lookup (u_int32_t router_id,
+                       struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      if (o6n->router_id == router_id)
+        return o6n;
+    }
+  return (struct ospf6_neighbor *) NULL;
+}
+
+\f
+/* vty functions */
+/* show neighbor structure */
+void
+ospf6_neighbor_show_summary (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+  char router_id[16];
+  char dr[16], bdr[16];
+  char duration[16];
+  struct timeval now, res;
+
+/*
+    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+             "State", VTY_NEWLINE);
+*/
+
+  inet_ntop (AF_INET, &o6n->router_id, router_id, sizeof (router_id));
+  inet_ntop (AF_INET, &o6n->dr, dr, sizeof (dr));
+  inet_ntop (AF_INET, &o6n->bdr, bdr, sizeof (bdr));
+
+  gettimeofday (&now, NULL);
+  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
+  ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+  vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+           router_id, ospf6_neighbor_state_string[o6n->state],
+           duration, dr, bdr, o6n->ospf6_interface->interface->name,
+           ospf6_interface_state_string[o6n->ospf6_interface->state],
+           VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+  char hisaddr[64], timestring[32];
+  struct timeval now, res;
+
+  inet_ntop (AF_INET6, &o6n->hisaddr, hisaddr, sizeof (hisaddr));
+  vty_out (vty, " Neighbor %s, interface address %s%s",
+           o6n->str, hisaddr, VTY_NEWLINE);
+  vty_out (vty, "    Area %s via interface %s (ifindex %d)%s",
+           o6n->ospf6_interface->area->str,
+           o6n->ospf6_interface->interface->name,
+           o6n->ospf6_interface->interface->ifindex,
+           VTY_NEWLINE);
+  vty_out (vty, "    Priority: %d, State: %s, %d state changes%s",
+           o6n->priority, ospf6_neighbor_state_string[o6n->state],
+           o6n->ospf6_stat_state_changed, VTY_NEWLINE);
+
+  gettimeofday (&now, NULL);
+  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
+  ospf6_timeval_string_summary (&res, timestring, sizeof (timestring));
+  vty_out (vty, "    Last state changed: %s ago%s", timestring, VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+  char hisdr[16], hisbdr[16];
+
+  ospf6_neighbor_show (vty, o6n);
+
+  inet_ntop (AF_INET, &o6n->dr, hisdr, sizeof (hisdr));
+  inet_ntop (AF_INET, &o6n->bdr, hisbdr, sizeof (hisbdr));
+
+  vty_out (vty, "    His Ifindex of myside: %d%s",
+                o6n->ifid, VTY_NEWLINE);
+  vty_out (vty, "    His DR Election: DR %s, BDR %s%s",
+                hisdr, hisbdr, VTY_NEWLINE);
+
+  vty_out (vty, "    Last received DbDesc: opt:%s"
+                " ifmtu:%hu bit:%s%s%s seqnum:%ld%s",
+                "xxx", ntohs (o6n->last_dd.ifmtu),
+                (DD_IS_IBIT_SET (o6n->last_dd.bits) ? "I" : "-"),
+                (DD_IS_MBIT_SET (o6n->last_dd.bits) ? "M" : "-"),
+                (DD_IS_MSBIT_SET (o6n->last_dd.bits) ? "m" : "s"),
+                (u_long)ntohl (o6n->last_dd.seqnum), VTY_NEWLINE);
+  vty_out (vty, "    My DbDesc bit for this neighbor: %s%s%s%s",
+           (DD_IS_IBIT_SET (o6n->dbdesc_bits) ? "I" : "-"),
+           (DD_IS_MBIT_SET (o6n->dbdesc_bits) ? "M" : "-"),
+           (DD_IS_MSBIT_SET (o6n->dbdesc_bits) ? "m" : "s"),
+           VTY_NEWLINE);
+
+  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
+                "SeqnumMismatch", o6n->ospf6_stat_seqnum_mismatch,
+                "BadLSReq", o6n->ospf6_stat_bad_lsreq, VTY_NEWLINE);
+  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
+                "OnewayReceived", o6n->ospf6_stat_oneway_received,
+                "InactivityTimer", o6n->ospf6_stat_inactivity_timer,
+                VTY_NEWLINE);
+  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
+                "DbDescRetrans", o6n->ospf6_stat_retrans_dbdesc,
+                "LSReqRetrans", o6n->ospf6_stat_retrans_lsreq,
+                VTY_NEWLINE);
+  vty_out (vty, "    %-16s %5d times%s",
+                "LSUpdateRetrans", o6n->ospf6_stat_retrans_lsupdate,
+                VTY_NEWLINE);
+  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
+                "LSAReceived", o6n->ospf6_stat_received_lsa,
+                "LSUpdateReceived", o6n->ospf6_stat_received_lsupdate,
+                VTY_NEWLINE);
+
+  vty_out (vty, "    %-12s %-12s %-12s%s",
+           "Message", "DbDesc", "LSReq", VTY_NEWLINE);
+  vty_out (vty, "    %-12s %12d %12d%s", "LSA Send",
+           o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC],
+           o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
+  vty_out (vty, "    %-12s %12d %12d%s", "LSA Receive",
+           o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC],
+           o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_timestamp_hello (struct ospf6_neighbor *o6n)
+{
+  struct timeval now, interval;
+  gettimeofday (&now, (struct timezone *) NULL);
+  if (o6n->tv_last_hello_received.tv_sec)
+    {
+      ospf6_timeval_sub (&now, &o6n->tv_last_hello_received, &interval);
+      zlog_info ("Hello Interval %s : %ld msec",
+                  o6n->str, interval.tv_sec * 1000 + interval.tv_usec % 1000);
+    }
+  o6n->tv_last_hello_received.tv_sec = now.tv_sec;
+  o6n->tv_last_hello_received.tv_usec = now.tv_usec;
+}
+
+DEFUN (show_ipv6_ospf6_neighbor_routerid,
+       show_ipv6_ospf6_neighbor_routerid_cmd,
+       "show ipv6 ospf6 neighbor A.B.C.D",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Neighbor list\n"
+       "OSPF6 neighbor Router ID in IP address format\n"
+       )
+{
+  u_int32_t router_id;
+  struct ospf6_neighbor *o6n;
+  struct ospf6_interface *o6i;
+  struct ospf6_area *o6a;
+  listnode nodei, nodej, nodek;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc == 0)
+    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+             "State", VTY_NEWLINE);
+  else if (inet_pton (AF_INET, argv[0], &router_id) != 1)
+    {
+      vty_out (vty, "Malformed Router-ID: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  for (nodei = listhead (ospf6->area_list); nodei; nextnode (nodei))
+    {
+      o6a = getdata (nodei);
+      for (nodej = listhead (o6a->if_list); nodej; nextnode (nodej))
+        {
+          o6i = getdata (nodej);
+          for (nodek = listhead (o6i->neighbor_list); nodek; nextnode (nodek))
+            {
+              o6n = getdata (nodek);
+              if (argc == 0)
+                ospf6_neighbor_show_summary (vty, o6n);
+              else if (o6n->router_id == router_id)
+                ospf6_neighbor_show_detail (vty, o6n);
+            }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_neighbor_routerid,
+       show_ipv6_ospf6_neighbor_cmd,
+       "show ipv6 ospf6 neighbor",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Neighbor list\n"
+       )
+
+DEFUN (show_ipv6_ospf6_neighborlist,
+       show_ipv6_ospf6_neighborlist_cmd,
+       "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Link State summary list\n"
+       "Link State request list\n"
+       "Link State retransmission list\n"
+       "Link State Description list (Used to retrans DbDesc)\n"
+       )
+{
+  struct ospf6_area *o6a;
+  struct ospf6_interface *o6i;
+  struct ospf6_neighbor *o6n;
+  listnode i, j, k, l;
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsdb *lsdb = NULL;
+  char type[16], id[16], adv_router[16];
+  struct ospf6_lsdb_node node;
+  u_int16_t age, cksum, len;
+  u_int32_t seqnum;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+  i = j = k = l = NULL;
+
+  for (i = listhead (ospf6->area_list); i; nextnode (i))
+    {
+      o6a = (struct ospf6_area *) getdata (i);
+      for (j = listhead (o6a->if_list); j; nextnode (j))
+        {
+          o6i = (struct ospf6_interface *) getdata (j);
+          for (k = listhead (o6i->neighbor_list); k; nextnode (k))
+            {
+              o6n = (struct ospf6_neighbor *) getdata (k);
+
+              if (strncmp (argv[0], "sum", 3) == 0)
+                lsdb = o6n->summary_list;
+              else if (strncmp (argv[0], "req", 3) == 0)
+                lsdb = o6n->request_list;
+              else if (strncmp (argv[0], "ret", 3) == 0)
+                lsdb = o6n->retrans_list;
+              else if (strncmp (argv[0], "dbd", 3) == 0)
+                lsdb = o6n->dbdesc_list;
+
+              vty_out (vty, "neighbor %s on interface %s: %d%s", o6n->str,
+                       o6i->interface->name, lsdb->count,
+                       VTY_NEWLINE);
+              for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
+                   ospf6_lsdb_next (&node))
+                {
+                  lsa = node.lsa;
+                  ospf6_lsa_age_current (lsa);
+
+                  ospf6_lsa_type_string (lsa->header->type, type,
+                                         sizeof (type));
+                  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+                  inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
+                             sizeof (adv_router));
+                  age = ntohs (lsa->header->age);
+                  seqnum = ntohl (lsa->header->seqnum);
+                  cksum = ntohs (lsa->header->checksum);
+                  len = ntohs (lsa->header->length);
+
+                  vty_out (vty, "  %s-LSA ID=%s Adv=%s%s",
+                           type, id, adv_router, VTY_NEWLINE);
+                  vty_out (vty, "  Age: %hu SeqNum: %#x Cksum: %hx Len: %hu%s",
+                           age, seqnum, cksum, len, VTY_NEWLINE);
+                }
+            }
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_neighbor_init ()
+{
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
new file mode 100644 (file)
index 0000000..c3821c6
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_NEIGHBOR_H
+#define OSPF6_NEIGHBOR_H
+
+/* Neighbor structure */
+struct ospf6_neighbor
+{
+  /* Neighbor Router ID String */
+  char str[32];
+
+  /* OSPFv3 Interface this neighbor belongs to */
+  struct ospf6_interface *ospf6_interface;
+
+  /* Neighbor state */
+  u_char state;
+  struct timeval last_changed;
+
+  /* Neighbor Router ID */
+  u_int32_t router_id;
+
+  /* Router Priority of this neighbor */
+  u_char priority;
+
+  u_int32_t ifid;
+  u_int32_t dr;
+  u_int32_t bdr;
+  u_int32_t prevdr;
+  u_int32_t prevbdr;
+
+  /* Link-LSA's options field */
+  char options[3];
+
+  /* IPaddr of I/F on our side link */
+  struct in6_addr hisaddr;
+
+  /* new */
+  struct ospf6_lsdb *summary_list;
+  struct ospf6_lsdb *request_list;
+  struct ospf6_lsdb *retrans_list;
+
+  /* For Database Exchange */
+  u_char               dbdesc_bits;
+  u_int32_t            dbdesc_seqnum;
+  struct ospf6_dbdesc *dbdesc_previous;
+
+  /* last received DD , including OSPF capability of this neighbor */
+  struct ospf6_dbdesc last_dd;
+
+  /* LSAs to retransmit to this neighbor */
+  list dbdesc_lsa;
+
+  /* placeholder for DbDesc */
+  struct iovec dbdesc_last_send[1024];
+
+  struct thread *inactivity_timer;
+
+  /* DbDesc */
+  struct thread *thread_send_dbdesc;
+  struct thread *thread_rxmt_dbdesc;
+  list dbdesclist;
+  struct ospf6_lsdb *dbdesc_list;
+
+  /* LSReq */
+  struct thread *thread_send_lsreq;
+  struct thread *thread_rxmt_lsreq;
+
+  /* LSUpdate */
+  struct thread *send_update;
+  struct thread *thread_send_update;
+  struct thread *thread_rxmt_update;
+
+  /* statistics */
+  u_int message_send[OSPF6_MESSAGE_TYPE_MAX];
+  u_int message_receive[OSPF6_MESSAGE_TYPE_MAX];
+  u_int lsa_send[OSPF6_MESSAGE_TYPE_MAX];
+  u_int lsa_receive[OSPF6_MESSAGE_TYPE_MAX];
+
+  u_int ospf6_stat_state_changed;
+  u_int ospf6_stat_seqnum_mismatch;
+  u_int ospf6_stat_bad_lsreq;
+  u_int ospf6_stat_oneway_received;
+  u_int ospf6_stat_inactivity_timer;
+  u_int ospf6_stat_dr_election;
+  u_int ospf6_stat_retrans_dbdesc;
+  u_int ospf6_stat_retrans_lsreq;
+  u_int ospf6_stat_retrans_lsupdate;
+  u_int ospf6_stat_received_lsa;
+  u_int ospf6_stat_received_lsupdate;
+
+  struct timeval tv_last_hello_received;
+};
+
+extern char *ospf6_neighbor_state_string[];
+
+\f
+/* Function Prototypes */
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *);
+
+void
+ospf6_neighbor_lslist_clear (struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_summary_add (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_neighbor_summary_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_request_add (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_neighbor_request_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_retrans_add (struct ospf6_lsa *, struct ospf6_neighbor *);
+void
+ospf6_neighbor_retrans_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
+
+void
+ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
+                           struct ospf6_neighbor *nei);
+void
+ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
+                              struct ospf6_neighbor *nei);
+
+void
+ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei);
+
+void
+ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *);
+
+struct ospf6_neighbor *
+ospf6_neighbor_create (u_int32_t, struct ospf6_interface *);
+void
+ospf6_neighbor_delete (struct ospf6_neighbor *);
+struct ospf6_neighbor *
+ospf6_neighbor_lookup (u_int32_t, struct ospf6_interface *);
+
+void ospf6_neighbor_init ();
+
+#endif /* OSPF6_NEIGHBOR_H */
+
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
new file mode 100644 (file)
index 0000000..041d829
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include "memory.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "ospf6d.h"
+#include "ospf6_proto.h"
+
+extern int errno;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern struct thread_master *master;
+
+/* iovec functions */
+void
+iov_clear (struct iovec *iov, size_t iovlen)
+{
+  int i;
+  for (i = 0; i < iovlen; i++)
+    {
+      iov[i].iov_base = NULL;
+      iov[i].iov_len = 0;
+    }
+}
+
+int
+iov_count (struct iovec *iov)
+{
+  int i;
+  for (i = 0; iov[i].iov_base; i++)
+    ;
+  return i;
+}
+
+int
+iov_totallen (struct iovec *iov)
+{
+  int i;
+  int totallen = 0;
+  for (i = 0; iov[i].iov_base; i++)
+    totallen += iov[i].iov_len;
+  return totallen;
+}
+
+void *
+iov_prepend (int mtype, struct iovec *iov, size_t len)
+{
+  int i, iovlen;
+  void *base;
+
+  base = (void *) XMALLOC (mtype, len);
+  if (!base)
+    {
+      zlog_warn ("Network: iov_prepend failed");
+      return NULL;
+    }
+  memset (base, 0, len);
+
+  iovlen = iov_count (iov);
+  for (i = iovlen; i; i--)
+    {
+      iov[i].iov_base = iov[i - 1].iov_base;
+      iov[i].iov_len = iov[i - 1].iov_len;
+    }
+  iov[0].iov_base = (char *)base;
+  iov[0].iov_len = len;
+
+  return base;
+}
+
+void *
+iov_append (int mtype, struct iovec *iov, size_t len)
+{
+  int i;
+  void *base;
+
+  base = (void *)XMALLOC (mtype, len);
+  if (!base)
+    {
+      zlog_warn ("Network: iov_append failed");
+      return NULL;
+    }
+  memset (base, 0, len);
+
+  /* proceed to the end */
+  i = iov_count (iov);
+
+  iov[i].iov_base = (char *)base;
+  iov[i].iov_len = len;
+
+  return base;
+}
+
+void *
+iov_attach_last (struct iovec *iov, void *base, size_t len)
+{
+  int i;
+  i = iov_count (iov);
+  iov[i].iov_base = (char *)base;
+  iov[i].iov_len = len;
+  return base;
+}
+
+void *
+iov_detach_first (struct iovec *iov)
+{
+  int i, iovlen;
+  void *base;
+  size_t len;
+
+  base = iov[0].iov_base;
+  len = iov[0].iov_len;
+  iovlen = iov_count (iov);
+  for (i = 0; i < iovlen; i++)
+    {
+      iov[i].iov_base = iov[i + 1].iov_base;
+      iov[i].iov_len = iov[i + 1].iov_len;
+    }
+  return base;
+}
+
+int
+iov_free (int mtype, struct iovec *iov, u_int begin, u_int end)
+{
+  int i;
+
+  for (i = begin; i < end; i++)
+    {
+      XFREE (mtype, iov[i].iov_base);
+      iov[i].iov_base = NULL;
+      iov[i].iov_len = 0;
+    }
+
+  return 0;
+}
+
+void
+iov_trim_head (int mtype, struct iovec *iov)
+{
+  void *base;
+
+  base = iov_detach_first (iov);
+  XFREE (mtype, base);
+  return;
+}
+
+void
+iov_free_all (int mtype, struct iovec *iov)
+{
+  int i, end = iov_count (iov);
+  for (i = 0; i < end; i++)
+    {
+      XFREE (mtype, iov[i].iov_base);
+      iov[i].iov_base = NULL;
+      iov[i].iov_len = 0;
+    }
+}
+
+void
+iov_copy_all (struct iovec *dst, struct iovec *src, size_t size)
+{
+  int i;
+  for (i = 0; i < size; i++)
+    {
+      dst[i].iov_base = src[i].iov_base;
+      dst[i].iov_len = src[i].iov_len;
+    }
+}
+
+\f
+/* Make ospf6d's server socket. */
+int
+ospf6_serv_sock ()
+{
+  ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
+  if (ospf6_sock < 0)
+    {
+      zlog_warn ("Network: can't create OSPF6 socket.");
+      return -1;
+    }
+  sockopt_reuseaddr (ospf6_sock);
+
+  /* setup global sockaddr_in6, allspf6 & alldr6 for later use */
+  allspfrouters6.sin6_family = AF_INET6;
+  alldrouters6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  allspfrouters6.sin6_len = sizeof (struct sockaddr_in6);
+  alldrouters6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6.sin6_addr);
+  inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6.sin6_addr);
+
+  return 0;
+}
+
+/* returns 0 if succeed, else returns -1 */
+int
+ospf6_join_allspfrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+  int retval;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
+          sizeof (struct in6_addr));
+
+  retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                       &mreq6, sizeof (mreq6));
+
+  if (retval < 0)
+    zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s",
+               ifindex, strerror (errno));
+#if 0
+  else
+    zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex);
+#endif
+
+  return retval;
+}
+
+void
+ospf6_leave_allspfrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
+          sizeof (struct in6_addr));
+
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+                  &mreq6, sizeof (mreq6)) < 0)
+    zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s",
+               ifindex, strerror (errno));
+#if 0
+  else
+    zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex);
+#endif
+}
+
+void
+ospf6_join_alldrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
+          sizeof (struct in6_addr));
+
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                  &mreq6, sizeof (mreq6)) < 0)
+    zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s",
+               ifindex, strerror (errno));
+#if 0
+  else
+    zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex);
+#endif
+}
+
+void
+ospf6_leave_alldrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
+          sizeof (struct in6_addr));
+
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+                  &mreq6, sizeof (mreq6)) < 0)
+    zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex);
+#if 0
+  else
+    zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
+#endif
+}
+
+/* setsockopt ReUseAddr to on */
+void
+ospf6_set_reuseaddr ()
+{
+  u_int on = 0;
+  if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on,
+                  sizeof (u_int)) < 0)
+    zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno));
+}
+
+/* setsockopt MulticastLoop to off */
+void
+ospf6_reset_mcastloop ()
+{
+  u_int off = 0;
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+                  &off, sizeof (u_int)) < 0)
+    zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s",
+               strerror (errno));
+}
+
+void
+ospf6_set_pktinfo ()
+{
+  u_int on = 1;
+#ifdef IPV6_RECVPKTINFO        /*2292bis-01*/
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                  &on, sizeof (u_int)) < 0)
+    zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno));
+#else /*RFC2292*/
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO,
+                  &on, sizeof (u_int)) < 0)
+    zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno));
+#endif
+}
+
+void
+ospf6_set_checksum ()
+{
+  int offset = 12;
+#ifndef DISABLE_IPV6_CHECKSUM
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM,
+                  &offset, sizeof (offset)) < 0)
+    zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno));
+#else
+  zlog_warn ("Network: Don't set IPV6_CHECKSUM");
+#endif /* DISABLE_IPV6_CHECKSUM */
+}
+
+void
+ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst,
+               unsigned int *ifindex, struct iovec *message)
+{
+  int retval;
+  struct msghdr smsghdr;
+  struct cmsghdr *scmsgp;
+  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+  struct in6_pktinfo *pktinfo;
+  struct sockaddr_in6 dst_sin6;
+
+  assert (dst);
+  assert (*ifindex);
+
+  scmsgp = (struct cmsghdr *)cmsgbuf;
+  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
+  memset (&dst_sin6, 0, sizeof (struct sockaddr_in6));
+
+  /* source address */
+  pktinfo->ipi6_ifindex = *ifindex;
+  if (src)
+    memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr));
+  else
+    memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr));
+
+  /* destination address */
+  dst_sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  dst_sin6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /*SIN6_LEN*/
+  memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr));
+#ifdef HAVE_SIN6_SCOPE_ID
+  dst_sin6.sin6_scope_id = *ifindex;
+#endif
+
+  /* send control msg */
+  scmsgp->cmsg_level = IPPROTO_IPV6;
+  scmsgp->cmsg_type = IPV6_PKTINFO;
+  scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+  /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
+
+  /* send msg hdr */
+  smsghdr.msg_iov = message;
+  smsghdr.msg_iovlen = iov_count (message);
+  smsghdr.msg_name = (caddr_t) &dst_sin6;
+  smsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+  smsghdr.msg_control = (caddr_t) cmsgbuf;
+  smsghdr.msg_controllen = sizeof (cmsgbuf);
+
+  retval = sendmsg (ospf6_sock, &smsghdr, 0);
+  if (retval != iov_totallen (message))
+    zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)",
+               *ifindex, strerror (errno), errno);
+}
+
+void
+ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst,
+               unsigned int *ifindex, struct iovec *message)
+{
+  int retval;
+  struct msghdr rmsghdr;
+  struct cmsghdr *rcmsgp;
+  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+  struct in6_pktinfo *pktinfo;
+  struct sockaddr_in6 src_sin6;
+
+  rcmsgp = (struct cmsghdr *)cmsgbuf;
+  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
+  memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
+
+  /* receive control msg */
+  rcmsgp->cmsg_level = IPPROTO_IPV6;
+  rcmsgp->cmsg_type = IPV6_PKTINFO;
+  rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+  /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
+
+  /* receive msg hdr */
+  rmsghdr.msg_iov = message;
+  rmsghdr.msg_iovlen = iov_count (message);
+  rmsghdr.msg_name = (caddr_t) &src_sin6;
+  rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+  rmsghdr.msg_control = (caddr_t) cmsgbuf;
+  rmsghdr.msg_controllen = sizeof (cmsgbuf);
+
+  retval = recvmsg (ospf6_sock, &rmsghdr, 0);
+  if (retval < 0)
+    {
+      zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
+    }
+  else if (retval == iov_totallen (message))
+    {
+      zlog_warn ("Network: possibly buffer shortage: %d received, buffer size: %d",
+                  retval, iov_totallen (message));
+    }
+
+  /* source address */
+  assert (src);
+  memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
+
+  /* destination address */
+  if (ifindex)
+    *ifindex = pktinfo->ipi6_ifindex;
+  if (dst)
+    memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
+}
+
+void
+ospf6_recvmsg_peek (struct in6_addr *src, struct in6_addr *dst,
+                    unsigned int *ifindex, struct iovec *message)
+{
+  int retval;
+  struct msghdr rmsghdr;
+  struct cmsghdr *rcmsgp;
+  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+  struct in6_pktinfo *pktinfo;
+  struct sockaddr_in6 src_sin6;
+
+  rcmsgp = (struct cmsghdr *)cmsgbuf;
+  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
+  memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
+
+  /* receive control msg */
+  rcmsgp->cmsg_level = IPPROTO_IPV6;
+  rcmsgp->cmsg_type = IPV6_PKTINFO;
+  rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+  /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
+
+  /* receive msg hdr */
+  rmsghdr.msg_iov = message;
+  rmsghdr.msg_iovlen = iov_count (message);
+  rmsghdr.msg_name = (caddr_t) &src_sin6;
+  rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+  rmsghdr.msg_control = (caddr_t) cmsgbuf;
+  rmsghdr.msg_controllen = sizeof (cmsgbuf);
+
+  retval = recvmsg (ospf6_sock, &rmsghdr, MSG_PEEK);
+  if (retval != iov_totallen (message))
+    zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
+
+  /* source address */
+  assert (src);
+  memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
+
+  /* destination address */
+  if (ifindex)
+    *ifindex = pktinfo->ipi6_ifindex;
+  if (dst)
+    memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
+}
+
diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h
new file mode 100644 (file)
index 0000000..934cce5
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_NETWORK_H
+#define OSPF6_NETWORK_H
+
+\f
+
+/* Function Prototypes */
+void iov_clear (struct iovec *, size_t);
+int iov_count (struct iovec *);
+int iov_totallen (struct iovec *);
+void *iov_prepend (int, struct iovec *, size_t);
+void *iov_append (int, struct iovec *, size_t);
+void *iov_attach_last (struct iovec *, void *, size_t);
+void *iov_detach_first (struct iovec *);
+int iov_free (int, struct iovec *, u_int, u_int);
+void iov_trim_head (int, struct iovec *);
+void iov_free_all (int, struct iovec *);
+void iov_copy_all (struct iovec *, struct iovec *, size_t);
+
+int ospf6_serv_sock ();
+int ospf6_join_allspfrouters (u_int);
+void ospf6_leave_allspfrouters (u_int);
+void ospf6_join_alldrouters (u_int);
+void ospf6_leave_alldrouters (u_int);
+void ospf6_set_reuseaddr ();
+void ospf6_reset_mcastloop ();
+void ospf6_set_pktinfo ();
+void ospf6_set_checksum ();
+
+void ospf6_sendmsg (struct in6_addr *, struct in6_addr *,
+                    unsigned int *, struct iovec *);
+void ospf6_recvmsg (struct in6_addr *, struct in6_addr *,
+                    unsigned int *, struct iovec *);
+void ospf6_recvmsg_peek (struct in6_addr *, struct in6_addr *,
+                         unsigned int *, struct iovec *);
+
+#endif /* OSPF6_NETWORK_H */
+
diff --git a/ospf6d/ospf6_nsm.c b/ospf6d/ospf6_nsm.c
new file mode 100644 (file)
index 0000000..aa08d40
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+static int
+nbs_full_change (struct ospf6_interface *ospf6_interface)
+{
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
+  return 0;
+}
+
+static int
+nbs_change (state_t nbs_next, char *reason, struct ospf6_neighbor *o6n)
+{
+  state_t nbs_previous;
+
+  nbs_previous = o6n->state;
+  o6n->state = nbs_next;
+
+  if (nbs_previous == nbs_next)
+    return 0;
+
+  /* statistics */
+  o6n->ospf6_stat_state_changed++;
+  gettimeofday (&o6n->last_changed, NULL);
+
+  /* log */
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    {
+      if (reason)
+        zlog_info ("Neighbor status change %s: [%s]->[%s](%s)",
+                   o6n->str,
+                   ospf6_neighbor_state_string[nbs_previous],
+                   ospf6_neighbor_state_string[nbs_next],
+                   reason);
+      else
+        zlog_info ("Neighbor status change %s: [%s]->[%s]",
+                   o6n->str,
+                   ospf6_neighbor_state_string[nbs_previous],
+                   ospf6_neighbor_state_string[nbs_next]);
+    }
+
+  if (nbs_previous == NBS_FULL || nbs_next == NBS_FULL)
+    nbs_full_change (o6n->ospf6_interface);
+
+  /* check for LSAs that already reached MaxAge */
+  if ((nbs_previous == NBS_EXCHANGE || nbs_previous == NBS_LOADING) &&
+      (nbs_next != NBS_EXCHANGE && nbs_next != NBS_LOADING))
+    {
+      ospf6_maxage_remover ();
+    }
+
+  CALL_CHANGE_HOOK (&neighbor_hook, o6n);
+
+  return 0;
+}
+
+/* RFC2328 section 10.4 */
+int
+need_adjacency (struct ospf6_neighbor *o6n)
+{
+
+  if (o6n->ospf6_interface->state == IFS_PTOP)
+    return 1;
+  if (o6n->ospf6_interface->state == IFS_DR)
+    return 1;
+  if (o6n->ospf6_interface->state == IFS_BDR)
+    return 1;
+  if (o6n->router_id == o6n->ospf6_interface->dr)
+    return 1;
+  if (o6n->router_id == o6n->ospf6_interface->bdr)
+    return 1;
+
+  return 0;
+}
+
+int
+hello_received (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *HelloReceived*", o6n->str);
+
+  if (o6n->inactivity_timer)
+    thread_cancel (o6n->inactivity_timer);
+
+  o6n->inactivity_timer = thread_add_timer (master, inactivity_timer, o6n,
+                                            o6n->ospf6_interface->dead_interval);
+  if (o6n->state <= NBS_DOWN)
+    nbs_change (NBS_INIT, "HelloReceived", o6n);
+  return 0;
+}
+
+int
+twoway_received (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state > NBS_INIT)
+    return 0;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *2Way-Received*", o6n->str);
+
+  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+  if (!need_adjacency (o6n))
+    {
+      nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+      return 0;
+    }
+  else
+    nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
+
+  DD_MSBIT_SET (o6n->dbdesc_bits);
+  DD_MBIT_SET (o6n->dbdesc_bits);
+  DD_IBIT_SET (o6n->dbdesc_bits);
+
+  if (o6n->thread_send_dbdesc)
+    thread_cancel (o6n->thread_send_dbdesc);
+  o6n->thread_send_dbdesc =
+    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+  if (o6n->thread_rxmt_dbdesc)
+    thread_cancel (o6n->thread_rxmt_dbdesc);
+  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+  return 0;
+}
+
+int
+negotiation_done (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state != NBS_EXSTART)
+    return 0;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *NegotiationDone*", o6n->str);
+
+  nbs_change (NBS_EXCHANGE, "NegotiationDone", o6n);
+  DD_IBIT_CLEAR (o6n->dbdesc_bits);
+
+  return 0;
+}
+
+int
+exchange_done (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state != NBS_EXCHANGE)
+    return 0;
+
+  if (o6n->thread_rxmt_dbdesc)
+    thread_cancel (o6n->thread_rxmt_dbdesc);
+  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *ExchangeDone*", o6n->str);
+
+  ospf6_lsdb_remove_all (o6n->dbdesc_list);
+
+  thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, o6n,
+                    o6n->ospf6_interface->dead_interval);
+
+  if (o6n->request_list->count == 0)
+    nbs_change (NBS_FULL, "Requestlist Empty", o6n);
+  else
+    {
+      thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+      nbs_change (NBS_LOADING, "Requestlist Not Empty", o6n);
+    }
+  return 0;
+}
+
+int
+loading_done (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state != NBS_LOADING)
+    return 0;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *LoadingDone*", o6n->str);
+
+  assert (o6n->request_list->count == 0);
+
+  nbs_change (NBS_FULL, "LoadingDone", o6n);
+
+  return 0;
+}
+
+int
+adj_ok (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *AdjOK?*", o6n->str);
+
+  if (o6n->state == NBS_TWOWAY)
+    {
+      if (!need_adjacency (o6n))
+        {
+          nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+          return 0;
+        }
+      else
+        nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
+
+      DD_MSBIT_SET (o6n->dbdesc_bits);
+      DD_MBIT_SET (o6n->dbdesc_bits);
+      DD_IBIT_SET (o6n->dbdesc_bits);
+
+      if (o6n->thread_send_dbdesc)
+        thread_cancel (o6n->thread_send_dbdesc);
+      o6n->thread_send_dbdesc =
+        thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+      return 0;
+    }
+
+  if (o6n->state >= NBS_EXSTART)
+    {
+      if (need_adjacency (o6n))
+        return 0;
+      else
+        {
+          nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+          ospf6_neighbor_lslist_clear (o6n);
+        }
+    }
+  return 0;
+}
+
+int
+seqnumber_mismatch (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state < NBS_EXCHANGE)
+    return 0;
+
+  /* statistics */
+  o6n->ospf6_stat_seqnum_mismatch++;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", o6n->str);
+
+  nbs_change (NBS_EXSTART, "SeqNumberMismatch", o6n);
+
+  DD_MSBIT_SET (o6n->dbdesc_bits);
+  DD_MBIT_SET (o6n->dbdesc_bits);
+  DD_IBIT_SET (o6n->dbdesc_bits);
+  ospf6_neighbor_lslist_clear (o6n);
+
+  if (o6n->thread_send_dbdesc)
+    thread_cancel (o6n->thread_send_dbdesc);
+  o6n->thread_send_dbdesc =
+    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+  return 0;
+}
+
+int
+bad_lsreq (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state < NBS_EXCHANGE)
+    return 0;
+
+  /* statistics */
+  o6n->ospf6_stat_bad_lsreq++;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *BadLSReq*", o6n->str);
+
+  nbs_change (NBS_EXSTART, "BadLSReq", o6n);
+
+  DD_MSBIT_SET (o6n->dbdesc_bits);
+  DD_MBIT_SET (o6n->dbdesc_bits);
+  DD_IBIT_SET (o6n->dbdesc_bits);
+  ospf6_neighbor_lslist_clear (o6n);
+
+  if (o6n->thread_send_dbdesc)
+    thread_cancel (o6n->thread_send_dbdesc);
+  o6n->thread_send_dbdesc =
+    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+  return 0;
+}
+
+int
+oneway_received (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  if (o6n->state < NBS_TWOWAY)
+    return 0;
+
+  /* statistics */
+  o6n->ospf6_stat_oneway_received++;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *1Way-Received*", o6n->str);
+
+  nbs_change (NBS_INIT, "1Way-Received", o6n);
+
+  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+  ospf6_neighbor_thread_cancel_all (o6n);
+  ospf6_neighbor_lslist_clear (o6n);
+  return 0;
+}
+
+int
+inactivity_timer (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  /* statistics */
+  o6n->ospf6_stat_inactivity_timer++;
+
+  if (IS_OSPF6_DUMP_NEIGHBOR)
+    zlog_info ("Neighbor Event %s: *InactivityTimer*", o6n->str);
+
+  o6n->inactivity_timer = NULL;
+  o6n->dr = o6n->bdr = o6n->prevdr = o6n->prevbdr = 0;
+  nbs_change (NBS_DOWN, "InactivityTimer", o6n);
+
+  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+  listnode_delete (o6n->ospf6_interface->neighbor_list, o6n);
+  ospf6_neighbor_delete (o6n);
+
+  return 0;
+}
+
diff --git a/ospf6d/ospf6_nsm.h b/ospf6d/ospf6_nsm.h
new file mode 100644 (file)
index 0000000..d70f1e8
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_NSM_H
+#define OSPF6_NSM_H
+
+/* Neighbor state */
+#define NBS_DOWN                      1
+#define OSPF6_NEIGHBOR_STATE_DOWN     1
+#define NBS_ATTEMPT                   2
+#define OSPF6_NEIGHBOR_STATE_ATTEMPT  2
+#define NBS_INIT                      3
+#define OSPF6_NEIGHBOR_STATE_INIT     3
+#define NBS_TWOWAY                    4
+#define OSPF6_NEIGHBOR_STATE_TWOWAY   4
+#define NBS_EXSTART                   5
+#define OSPF6_NEIGHBOR_STATE_EXSTART  5
+#define NBS_EXCHANGE                  6
+#define OSPF6_NEIGHBOR_STATE_EXCHANGE 6
+#define NBS_LOADING                   7
+#define OSPF6_NEIGHBOR_STATE_LOADING  7
+#define NBS_FULL                      8
+#define OSPF6_NEIGHBOR_STATE_FULL     8
+
+\f
+
+/* Function Prototypes */
+
+#include "ospf6_types.h"
+
+int need_adjacency (struct ospf6_neighbor *);
+
+
+/* Neighbor event */
+int hello_received (struct thread *);
+int twoway_received (struct thread *);
+int negotiation_done (struct thread *);
+int exchange_done (struct thread *);
+int loading_done (struct thread *);
+int adj_ok (struct thread *);
+int seqnumber_mismatch (struct thread *);
+int bad_lsreq (struct thread *);
+int oneway_received (struct thread *);
+int inactivity_timer (struct thread *);
+
+int dr_election (struct ospf6_interface *);
+
+#endif /* OSPF6_NSM_H */
+
diff --git a/ospf6d/ospf6_prefix.c b/ospf6d/ospf6_prefix.c
new file mode 100644 (file)
index 0000000..1542200
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#if 0
+
+#include <zebra.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "memory.h"
+#include "linklist.h"
+
+#include "ospf6_prefix.h"
+
+#else /*0*/
+
+#include "ospf6d.h"
+
+#endif /*0*/
+
+struct ospf6_prefix *
+ospf6_prefix_create (u_int8_t options, u_int16_t metric, struct prefix_ipv6 *p)
+{
+  struct prefix_ipv6 prefix;
+  struct ospf6_prefix *o6p;
+  size_t size;
+
+  /* copy prefix and apply mask */
+  prefix_copy ((struct prefix *) &prefix, (struct prefix *) p);
+  apply_mask_ipv6 (&prefix);
+
+  size = OSPF6_PREFIX_SPACE (prefix.prefixlen) + sizeof (struct ospf6_prefix);
+  o6p = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX, size);
+  if (! o6p)
+    zlog_warn ("Can't allocate memory for ospf6 prefix: size: %d", size);
+  else
+    memset (o6p, 0, size);
+
+  o6p->prefix_length = prefix.prefixlen;
+  o6p->prefix_options = options;
+  o6p->prefix_metric = htons (metric);
+  memcpy (o6p + 1, &prefix.prefix, OSPF6_PREFIX_SPACE (prefix.prefixlen));
+
+  return o6p;
+}
+
+void
+ospf6_prefix_delete (struct ospf6_prefix *p)
+{
+  XFREE (MTYPE_OSPF6_PREFIX, p);
+}
+
+int
+ospf6_prefix_issame (struct ospf6_prefix *p1, struct ospf6_prefix *p2)
+{
+  if (p1->prefix_length != p2->prefix_length)
+    return 0;
+  if (memcmp (&p1->u, &p2->u, sizeof (p1->u)))
+    return 0;
+  if (memcmp (p1 + 1, p2 + 1, OSPF6_PREFIX_SPACE (p1->prefix_length)))
+    return 0;
+  return 1;
+}
+
+struct ospf6_prefix *
+ospf6_prefix_lookup (list l, struct ospf6_prefix *p1)
+{
+  listnode node;
+  struct ospf6_prefix *p2;
+  for (node = listhead (l); node; nextnode (node))
+    {
+      p2 = (struct ospf6_prefix *) getdata (node);
+      if (ospf6_prefix_issame (p1, p2))
+        return p2;
+    }
+  return NULL;
+}
+
+/* add a copy of given prefix to the list */
+void
+ospf6_prefix_add (list l, struct ospf6_prefix *p)
+{
+  struct ospf6_prefix *add;
+  add = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX,
+                                         OSPF6_PREFIX_SIZE (p));
+  if (add == NULL)
+    {
+      zlog_warn ("Can't allocate memory for ospf6 prefix");
+      return;
+    }
+  else
+    memcpy (add, p, OSPF6_PREFIX_SIZE (p));
+
+  if (ospf6_prefix_lookup (l, add))
+    {
+      ospf6_prefix_delete (add);
+      return;
+    }
+  listnode_add (l, add);
+}
+
+void
+ospf6_prefix_remove (list l, struct ospf6_prefix *p)
+{
+  struct ospf6_prefix *rem;
+  rem = ospf6_prefix_lookup (l, p);
+  if (rem)
+    {
+      listnode_delete (l, rem);
+      ospf6_prefix_delete (rem);
+    }
+}
+
+void
+ospf6_prefix_in6_addr (struct ospf6_prefix *o6p, struct in6_addr *in6)
+{
+  memset (in6, 0, sizeof (struct in6_addr));
+  memcpy (in6, o6p + 1, OSPF6_PREFIX_SPACE (o6p->prefix_length));
+  return;
+}
+
+char *
+ospf6_prefix_options_str (u_int8_t opt, char *buf, size_t bufsize)
+{
+  char *p, *mc, *la, *nu;
+
+  p = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_P) ? "P" : "-");
+  mc = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--");
+  la = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--");
+  nu = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--");
+
+  snprintf (buf, bufsize, "%s|%s|%s|%s", p, mc, la, nu);
+  return buf;
+}
+
+char *
+ospf6_prefix_string (struct ospf6_prefix *prefix, char *buf, size_t size)
+{
+  struct in6_addr in6;
+  char s[64];
+
+  memset (&in6, 0, sizeof (in6));
+  memcpy (&in6, prefix + 1, OSPF6_PREFIX_SPACE (prefix->prefix_length));
+  inet_ntop (AF_INET6, &in6, s, sizeof (s));
+
+  snprintf (buf, size, "%s/%d", s, prefix->prefix_length);
+  return buf;
+}
+
+void
+ospf6_prefix_copy (struct ospf6_prefix *dst, struct ospf6_prefix *src,
+                   size_t dstsize)
+{
+  size_t srcsize;
+
+  memset (dst, 0, dstsize);
+
+  srcsize = OSPF6_PREFIX_SIZE (src);
+  if (dstsize < srcsize)
+    memcpy (dst, src, dstsize);
+  else
+    memcpy (dst, src, srcsize);
+
+  return;
+}
+
+void
+ospf6_prefix_apply_mask (struct ospf6_prefix *o6p)
+{
+  u_char *pnt, mask;
+  int index, offset;
+
+  char buf[128];
+  struct in6_addr in6;
+  ospf6_prefix_in6_addr (o6p, &in6);
+  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+
+  pnt = (u_char *)(o6p + 1);
+  index = o6p->prefix_length / 8;
+  offset = o6p->prefix_length % 8;
+  mask = 0xff << (8 - offset);
+
+  if (index >= 16)
+    return;
+
+  pnt[index] &= mask;
+  index ++;
+
+  while (index < OSPF6_PREFIX_SPACE (o6p->prefix_length))
+    pnt[index++] = 0;
+
+  ospf6_prefix_in6_addr (o6p, &in6);
+  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+}
+
diff --git a/ospf6d/ospf6_prefix.h b/ospf6d/ospf6_prefix.h
new file mode 100644 (file)
index 0000000..65a8cbc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_PREFIX_H
+#define OSPF6_PREFIX_H
+
+#include "linklist.h"
+
+#define OSPF6_PREFIX_OPTION_NU (1 << 0)  /* No Unicast */
+#define OSPF6_PREFIX_OPTION_LA (1 << 1)  /* Local Address */
+#define OSPF6_PREFIX_OPTION_MC (1 << 2)  /* MultiCast */
+#define OSPF6_PREFIX_OPTION_P  (1 << 3)  /* Propagate (NSSA) */
+
+struct ospf6_prefix
+{
+  u_int8_t prefix_length;
+  u_int8_t prefix_options;
+  union {
+    u_int16_t _prefix_metric;
+    u_int16_t _prefix_referenced_lstype;
+  } u;
+#define prefix_metric u._prefix_metric
+#define prefix_refer_lstype u._prefix_referenced_lstype
+  /* followed by one address_prefix */
+};
+
+/* size_t OSPF6_PREFIX_SPACE (int prefixlength); */
+#define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4)
+
+/* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */
+#define OSPF6_PREFIX_SIZE(x) \
+   (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix))
+
+/* struct ospf6_prefix *OSPF6_NEXT_PREFIX (struct ospf6_prefix *); */
+#define OSPF6_NEXT_PREFIX(x) \
+   ((struct ospf6_prefix *)((char *)(x) + OSPF6_PREFIX_SIZE (x)))
+
+\f
+
+/* Function Prototypes */
+struct ospf6_prefix *
+  ospf6_prefix_make (u_int8_t, u_int16_t, struct prefix_ipv6 *);
+void ospf6_prefix_free (struct ospf6_prefix *);
+void ospf6_prefix_in6_addr (struct ospf6_prefix *, struct in6_addr *);
+void ospf6_prefix_copy (struct ospf6_prefix *, struct ospf6_prefix *,
+                        size_t);
+
+void ospf6_prefix_apply_mask (struct ospf6_prefix *);
+int ospf6_prefix_issame (struct ospf6_prefix *, struct ospf6_prefix *);
+
+char *ospf6_prefix_options_str (u_int8_t, char *, size_t);
+char *ospf6_prefix_string (struct ospf6_prefix *, char *, size_t);
+
+struct ospf6_prefix *
+ospf6_prefix_lookup (list l, struct ospf6_prefix *prefix);
+void ospf6_prefix_add (list, struct ospf6_prefix *);
+
+struct ospf6_prefix *
+ospf6_prefix_create (u_int8_t, u_int16_t, struct prefix_ipv6 *);
+void ospf6_prefix_delete (struct ospf6_prefix *);
+
+void ospf6_prefix_init ();
+
+#endif /* OSPF6_PREFIX_H */
+
diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c
new file mode 100644 (file)
index 0000000..71e575f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "ospf6_proto.h"
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, int size)
+{
+  char *dc, *r, *n, *mc, *e, *v6;
+
+  dc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_DC) ? "DC" : "--");
+  r  = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_R) ? "R" : "-");
+  n  = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_N) ? "N" : "-");
+  mc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_MC) ? "MC" : "--");
+  e  = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_E) ? "E" : "-");
+  v6 = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_V6) ? "V6" : "--");
+  snprintf (buffer, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6);
+  return buffer;
+}
+
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
new file mode 100644 (file)
index 0000000..9a95444
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_PROTO_H
+#define OSPF6_PROTO_H
+
+/* OSPF protocol version */
+#define OSPF6_VERSION          3
+
+/* OSPF protocol number. */
+#ifndef IPPROTO_OSPFIGP
+#define IPPROTO_OSPFIGP         89
+#endif
+
+/* TOS field normaly null */
+#define OSPF6_TOS_VALUE               0x0
+
+/* Architectural Constants */
+#define OSPF6_LS_REFRESH_TIME         1800       /* 30 min */
+#define OSPF6_MIN_LS_INTERVAL         5
+#define OSPF6_MIN_LS_ARRIVAL          1
+#define MAXAGE                  3600       /* 1 hour */
+#define CHECK_AGE               300        /* 5 min */
+#define MAX_AGE_DIFF            900        /* 15 min */
+#define LS_INFINITY             0xffffff   /* 24-bit binary value */
+#define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */
+#define MAX_SEQUENCE_NUMBER     0x7fffffff /* signed 32-bit integer */
+
+#define MAXOSPFMESSAGELEN         4096
+
+#define ALLSPFROUTERS6 "ff02::5"
+#define ALLDROUTERS6   "ff02::6"
+
+/* Configurable Constants */
+
+#define DEFAULT_HELLO_INTERVAL    10
+#define DEFAULT_ROUTER_DEAD_TIMER 40
+
+/* OSPF options */
+/* present in HELLO, DD, LSA */
+#define OSPF6_OPT_SET(x,opt)   ((x)[2] |=  (opt))
+#define OSPF6_OPT_ISSET(x,opt) ((x)[2] &   (opt))
+#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt))
+#define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0)
+
+#define OSPF6_OPT_V6 (1 << 0)   /* IPv6 forwarding Capability */
+#define OSPF6_OPT_E  (1 << 1)   /* AS External Capability */
+#define OSPF6_OPT_MC (1 << 2)   /* Multicasting Capability */
+#define OSPF6_OPT_N  (1 << 3)   /* Handling Type-7 LSA Capability */
+#define OSPF6_OPT_R  (1 << 4)   /* Forwarding Capability (Any Protocol) */
+#define OSPF6_OPT_DC (1 << 5)   /* Demand Circuit handling Capability */
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, int size);
+
+#endif /* OSPF6_PROTO_H */
+
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
new file mode 100644 (file)
index 0000000..c35efa6
--- /dev/null
@@ -0,0 +1,1130 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+char *
+dtype_name[OSPF6_DEST_TYPE_MAX] =
+{
+  "Unknown", "Router", "Network", "Discard"
+};
+#define DTYPE_NAME(x) \
+  (0 < (x) && (x) < sizeof (dtype_name) ? \
+   dtype_name[(x)] : dtype_name[0])
+
+char *
+dtype_abname[OSPF6_DEST_TYPE_MAX] =
+{
+  "?", "R", "N", "D"
+};
+#define DTYPE_ABNAME(x) \
+  (0 < (x) && (x) < sizeof (dtype_abname) ? \
+   dtype_abname[(x)] : dtype_abname[0])
+
+char *
+ptype_name[OSPF6_PATH_TYPE_MAX] =
+{
+  "Unknown", "Intra", "Inter", "External-1", "External-2",
+  "System", "Kernel", "Connect", "Static", "RIP", "RIPng",
+  "OSPF", "OSPF6", "BGP"
+};
+#define PTYPE_NAME(x) \
+  (0 < (x) && (x) < sizeof (ptype_name) ? \
+   ptype_name[(x)] : ptype_name[0])
+
+char *
+ptype_abname[OSPF6_PATH_TYPE_MAX] =
+{
+  "??", "Ia", "Ie", "E1", "E2",
+  "-X", "-K", "-C", "-S", "-R", "-R",
+  "-O", "-O", "-B"
+};
+#define PTYPE_ABNAME(x) \
+  (0 < (x) && (x) < sizeof (ptype_abname) ? \
+   ptype_abname[(x)] : ptype_abname[0])
+
+\f
+
+int
+ospf6_path_cmp (void *arg1, void *arg2)
+{
+  struct ospf6_path_node *pn1 = arg1;
+  struct ospf6_path_node *pn2 = arg2;
+  struct ospf6_path *p1 = &pn1->path;
+  struct ospf6_path *p2 = &pn2->path;
+
+  if (p1->type < p2->type)
+    return -1;
+  else if (p1->type > p2->type)
+    return 1;
+
+  if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2)
+    {
+      if (p1->cost_e2 < p2->cost_e2)
+        return -1;
+      else if (p1->cost_e2 > p2->cost_e2)
+        return 1;
+    }
+
+  if (p1->cost < p2->cost)
+    return -1;
+  else if (p1->cost > p2->cost)
+    return 1;
+
+  /* if from the same source, recognize as identical
+     (and treat this as update) */
+  if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) &&
+      p1->area_id == p2->area_id)
+    return 0;
+
+  /* else, always prefer left */
+  return -1;
+}
+
+int
+ospf6_nexthop_cmp (void *arg1, void *arg2)
+{
+  int i, ret = 0;
+  struct ospf6_nexthop_node *nn1 = arg1;
+  struct ospf6_nexthop_node *nn2 = arg2;
+  struct ospf6_nexthop *n1 = &nn1->nexthop;
+  struct ospf6_nexthop *n2 = &nn2->nexthop;
+
+  if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0)
+    return 0;
+
+  for (i = 0; i < sizeof (struct in6_addr); i++)
+    {
+      if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i])
+        {
+          ret = nn1->nexthop.address.s6_addr[i] -
+                nn2->nexthop.address.s6_addr[i];
+          break;
+        }
+    }
+
+  if (ret == 0)
+    ret = -1;
+
+  return ret;
+}
+
+static void
+ospf6_route_request (struct ospf6_route_req *request,
+                     struct ospf6_route_node   *rn,
+                     struct ospf6_path_node    *pn,
+                     struct ospf6_nexthop_node *nn)
+{
+  assert (request);
+  assert (rn && pn && nn);
+
+  request->route_node = rn->route_node;
+
+  linklist_head (rn->path_list, &request->path_lnode);
+  while (request->path_lnode.data != pn)
+    {
+      //assert (! linklist_end (&request->path_lnode));
+      if (linklist_end (&request->path_lnode))
+        {
+          struct linklist_node node;
+
+          zlog_info ("rn: %p, pn: %p", rn, pn);
+          zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost  %d %d %d",
+          pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0],
+          (int)pn->path.capability[1], (int)pn->path.capability[2],
+          (int)pn->path.prefix_options, pn->path.area_id,
+          pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2);
+
+          for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
+               linklist_next (&node))
+            {
+              struct ospf6_path_node *pn2 = node.data;
+
+              zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
+                         (memcmp (&pn->path, &pn2->path,
+                                  sizeof (struct ospf6_path)) ?
+                          "different" : "same"));
+
+          zlog_info ("  origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost  %d %d %d",
+          pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0],
+          (int)pn2->path.capability[1], (int)pn2->path.capability[2],
+          (int)pn2->path.prefix_options, pn2->path.area_id,
+          pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2);
+
+              if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
+                {
+                  pn = pn2;
+                  request->nexthop_lnode.data = pn2;
+                }
+            }
+          break;
+        }
+      linklist_next (&request->path_lnode);
+    }
+  assert (request->path_lnode.data == pn);
+
+  linklist_head (pn->nexthop_list, &request->nexthop_lnode);
+  while (request->nexthop_lnode.data != nn)
+    {
+      assert (! linklist_end (&request->nexthop_lnode));
+      linklist_next (&request->nexthop_lnode);
+    }
+  assert (request->nexthop_lnode.data == nn);
+
+  request->table = rn->table;
+  request->count = rn->count;
+  request->route_id = rn->route_id;
+  memcpy (&request->route,   &rn->route,   sizeof (struct ospf6_route));
+  memcpy (&request->path,    &pn->path,    sizeof (struct ospf6_path));
+  memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop));
+}
+
+int
+ospf6_route_count (struct ospf6_route_req *request)
+{
+  return request->count;
+}
+
+int
+ospf6_route_lookup (struct ospf6_route_req *request,
+                    struct prefix *prefix,
+                    struct ospf6_route_table *table)
+{
+  struct route_node *node;
+  struct ospf6_route_node   *rn = NULL;
+  struct ospf6_path_node    *pn = NULL;
+  struct ospf6_nexthop_node *nn = NULL;
+  struct linklist_node lnode;
+
+  if (request)
+    memset ((void *) request, 0, sizeof (struct ospf6_route_req));
+
+  node = route_node_lookup (table->table, prefix);
+  if (! node)
+    return 0;
+
+  rn = (struct ospf6_route_node *) node->info;
+  if (! rn)
+    return 0;
+
+  if (request)
+    {
+      linklist_head (rn->path_list, &lnode);
+      pn = lnode.data;
+      linklist_head (pn->nexthop_list, &lnode);
+      nn = lnode.data;
+
+      ospf6_route_request (request, rn, pn, nn);
+    }
+
+  return 1;
+}
+
+void
+ospf6_route_head (struct ospf6_route_req *request,
+                  struct ospf6_route_table *table)
+{
+  struct route_node *node;
+  struct ospf6_route_node   *rn = NULL;
+  struct ospf6_path_node    *pn = NULL;
+  struct ospf6_nexthop_node *nn = NULL;
+  struct linklist_node lnode;
+
+  if (request)
+    memset (request, 0, sizeof (struct ospf6_route_req));
+
+  node = route_top (table->table);
+  if (! node)
+    return;
+
+  while (node && node->info == NULL)
+    node = route_next (node);
+  if (! node)
+    return;
+
+  rn = (struct ospf6_route_node *) node->info;
+  linklist_head (rn->path_list, &lnode);
+  pn = lnode.data;
+  linklist_head (pn->nexthop_list, &lnode);
+  nn = lnode.data;
+
+  ospf6_route_request (request, rn, pn, nn);
+}
+
+int
+ospf6_route_end (struct ospf6_route_req *request)
+{
+  if (request->route_node == NULL &&
+      linklist_end (&request->path_lnode) &&
+      linklist_end (&request->nexthop_lnode) &&
+      request->nexthop.ifindex == 0 &&
+      IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address))
+    return 1;
+  return 0;
+}
+
+void
+ospf6_route_next (struct ospf6_route_req *request)
+{
+  struct ospf6_route_node   *route_node = NULL;
+  struct ospf6_path_node    *path_node = NULL;
+  struct ospf6_nexthop_node *nexthop_node = NULL;
+
+  linklist_next (&request->nexthop_lnode);
+  if (linklist_end (&request->nexthop_lnode))
+    {
+      linklist_next (&request->path_lnode);
+      if (linklist_end (&request->path_lnode))
+        {
+          request->route_node = route_next (request->route_node);
+          while (request->route_node && request->route_node->info == NULL)
+            request->route_node = route_next (request->route_node);
+          if (request->route_node)
+            {
+              route_node = request->route_node->info;
+              if (route_node)
+                linklist_head (route_node->path_list, &request->path_lnode);
+            }
+        }
+
+      path_node = request->path_lnode.data;
+      if (path_node)
+        linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
+    }
+
+  nexthop_node = request->nexthop_lnode.data;
+
+  if (nexthop_node == NULL)
+    {
+      assert (path_node == NULL);
+      assert (route_node == NULL);
+
+      memset (&request->route,   0, sizeof (struct ospf6_route));
+      memset (&request->path,    0, sizeof (struct ospf6_path));
+      memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
+    }
+  else
+    {
+      path_node = request->path_lnode.data;
+      route_node = request->route_node->info;
+
+      assert (path_node != NULL);
+      assert (route_node != NULL);
+
+      memcpy (&request->route,   &route_node->route,
+              sizeof (struct ospf6_route));
+      memcpy (&request->path,    &path_node->path,
+              sizeof (struct ospf6_path));
+      memcpy (&request->nexthop, &nexthop_node->nexthop,
+              sizeof (struct ospf6_nexthop));
+    }
+}
+
+#define ADD    0
+#define CHANGE 1
+#define REMOVE 2
+
+void
+ospf6_route_hook_call (int type,
+                       struct ospf6_route_req *request,
+                       struct ospf6_route_table *table)
+{
+  struct linklist_node node;
+  void (*func) (struct ospf6_route_req *);
+
+  for (linklist_head (table->hook_list[type], &node);
+       ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      func = node.data;
+      (*func) (request);
+    }
+}
+
+void
+ospf6_route_hook_register (void (*add)    (struct ospf6_route_req *),
+                           void (*change) (struct ospf6_route_req *),
+                           void (*remove) (struct ospf6_route_req *),
+                           struct ospf6_route_table *table)
+{
+  linklist_add (add,    table->hook_list[ADD]);
+  linklist_add (change, table->hook_list[CHANGE]);
+  linklist_add (remove, table->hook_list[REMOVE]);
+}
+
+void
+ospf6_route_hook_unregister (void (*add)    (struct ospf6_route_req *),
+                             void (*change) (struct ospf6_route_req *),
+                             void (*remove) (struct ospf6_route_req *),
+                             struct ospf6_route_table *table)
+{
+  linklist_remove (add,    table->hook_list[ADD]);
+  linklist_remove (change, table->hook_list[CHANGE]);
+  linklist_remove (remove, table->hook_list[REMOVE]);
+}
+
+
+int
+prefix_ls2str (struct prefix *p, char *str, int size)
+{
+  char id[BUFSIZ], adv_router[BUFSIZ];
+  struct prefix_ls *pl = (struct prefix_ls *) p;
+
+  inet_ntop (AF_INET, &pl->id, id, BUFSIZ);
+  inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ);
+  snprintf (str, size, "%s-%s", adv_router, id);
+  return 0;
+}
+
+void
+ospf6_route_log_request (char *what, char *where,
+                         struct ospf6_route_req *request)
+{
+  char prefix[64];
+  char area_id[16];
+  char type[16], id[16], adv[16];
+  char address[64], ifname[IFNAMSIZ];
+
+  if (request->route.prefix.family != AF_INET &&
+      request->route.prefix.family != AF_INET6)
+    prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix));
+  else
+    prefix2str (&request->route.prefix, prefix, sizeof (prefix));
+
+  inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id));
+
+  ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type));
+  inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id));
+  inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv));
+
+  inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address));
+
+  zlog_info ("ROUTE: %s %s %s %s %s",
+             what, DTYPE_ABNAME (request->route.type), prefix,
+             ((strcmp ("Add", what) == 0) ? "to" : "from"), where);
+  zlog_info ("ROUTE:     Area: %s type: %s cost: %lu (E2: %lu)",
+             area_id, PTYPE_NAME (request->path.type),
+             (u_long) request->path.cost, (u_long) request->path.cost_e2);
+  zlog_info ("ROUTE:     Origin: Type: %s", type);
+  zlog_info ("ROUTE:     Origin: Id: %s Adv: %s", id, adv);
+  zlog_info ("ROUTE:     Nexthop: %s", address);
+  zlog_info ("ROUTE:     Nexthop: Ifindex: %u (%s)",
+             request->nexthop.ifindex,
+             if_indextoname (request->nexthop.ifindex, ifname));
+}
+
+struct ospf6_path_node *
+ospf6_route_find_path_node (struct ospf6_route_req *request,
+                            struct ospf6_route_node *rn)
+{
+  struct linklist_node node;
+
+  for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      struct ospf6_path_node *path_node = node.data;
+
+      if (path_node->path.area_id == request->path.area_id &&
+          path_node->path.origin.type == request->path.origin.type &&
+          path_node->path.origin.id == request->path.origin.id &&
+          path_node->path.origin.adv_router == request->path.origin.adv_router)
+        return path_node;
+    }
+
+#if 0
+  zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
+             request->path.area_id, request->path.origin.type,
+             request->path.origin.id, request->path.origin.adv_router);
+  for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      struct ospf6_path_node *path_node = node.data;
+      zlog_info ("  path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
+                 path_node->path.area_id, path_node->path.origin.type,
+                 path_node->path.origin.id, path_node->path.origin.adv_router);
+    }
+#endif
+
+  return NULL;
+}
+
+struct ospf6_nexthop_node *
+ospf6_route_find_nexthop_node (struct ospf6_route_req *request,
+                               struct ospf6_path_node *pn)
+{
+  struct linklist_node node;
+  for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      struct ospf6_nexthop_node *nexthop_node = node.data;
+
+      if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
+          sizeof (struct ospf6_nexthop)))
+        return nexthop_node;
+    }
+  return NULL;
+}
+
+void
+ospf6_route_add (struct ospf6_route_req *request,
+                 struct ospf6_route_table *table)
+{
+  struct ospf6_route_node   *rn;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+  struct route_node *route_node;
+
+  struct ospf6_route_req route;
+
+  int route_change   = 0;
+  int path_change    = 0;
+  int nexthop_change = 0;
+
+  /* find the requested route */
+  route_node = route_node_get (table->table, &request->route.prefix);
+  rn = (struct ospf6_route_node *) route_node->info;
+
+  if (rn)
+    {
+      if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
+        {
+          memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
+          route_change++;
+        }
+    }
+  else
+    {
+      rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node));
+      rn->table = table;
+      rn->route_node = route_node;
+      rn->route_id = table->route_id++;
+      rn->path_list = linklist_create ();
+      rn->path_list->cmp = ospf6_path_cmp;
+      memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
+      route_node->info = rn;
+    }
+
+  /* find the same path */
+  pn = ospf6_route_find_path_node (request, rn);
+
+  if (pn)
+    {
+      if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
+        {
+          memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
+          path_change++;
+        }
+    }
+  else
+    {
+      pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node));
+      pn->route_node = rn;
+      pn->nexthop_list = linklist_create ();
+      pn->nexthop_list->cmp = ospf6_nexthop_cmp;
+      memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
+      linklist_add (pn, rn->path_list);
+    }
+
+  /* find the same nexthop */
+  nn = ospf6_route_find_nexthop_node (request, pn);
+
+  if (nn)
+    {
+      if (memcmp (&nn->nexthop, &request->nexthop,
+                  sizeof (struct ospf6_nexthop)))
+        {
+          memcpy (&nn->nexthop, &request->nexthop,
+                  sizeof (struct ospf6_nexthop));
+          nexthop_change++;
+          gettimeofday (&nn->installed, (struct timezone *) NULL);
+        }
+    }
+  else
+    {
+      nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node));
+      nn->path_node = pn;
+      memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop));
+      linklist_add (nn, pn->nexthop_list);
+      rn->count++;
+      gettimeofday (&nn->installed, (struct timezone *) NULL);
+    }
+
+  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD);
+  if (route_change)
+    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE);
+  if (path_change)
+    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE);
+  if (nexthop_change)
+    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
+
+  if (table->freeze)
+    return;
+
+  if (IS_OSPF6_DUMP_ROUTE)
+    {
+      ospf6_route_log_request ("Add", table->name, request);
+
+      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE))
+        zlog_info ("ROUTE:   route attribute change");
+      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
+        zlog_info ("ROUTE:   path attribute change");
+      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+        zlog_info ("ROUTE:   nexthop attribute change");
+    }
+
+  if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) ||
+      CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
+    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
+
+  /* Call hooks */
+  ospf6_route_request (&route, rn, pn, nn);
+  if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
+    ospf6_route_hook_call (ADD, &route, table);
+  else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+    ospf6_route_hook_call (CHANGE, &route, table);
+
+  if (table->hook_add &&
+      CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
+    (*table->hook_add) (&route);
+  else if (table->hook_change &&
+           CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+    (*table->hook_change) (&route);
+
+  /* clear flag */
+  nn->flag = 0;
+}
+
+void
+ospf6_route_remove (struct ospf6_route_req *request,
+                    struct ospf6_route_table *table)
+{
+  struct ospf6_route_node   *rn;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+  struct route_node *route_node;
+  struct ospf6_route_req route;
+
+  /* find the requested route */
+  route_node = route_node_get (table->table, &request->route.prefix);
+  rn = (struct ospf6_route_node *) route_node->info;
+
+  if (! rn)
+    {
+      if (IS_OSPF6_DUMP_ROUTE)
+        {
+          ospf6_route_log_request ("Remove", table->name, request);
+          zlog_info ("ROUTE:   Can't remove: No such route");
+        }
+      return;
+    }
+
+  pn = ospf6_route_find_path_node (request, rn);
+  if (! pn)
+    {
+      if (IS_OSPF6_DUMP_ROUTE)
+        {
+          ospf6_route_log_request ("Remove", table->name, request);
+          zlog_info ("ROUTE:   Can't remove: No such path");
+        }
+      return;
+    }
+
+  if (pn->path.area_id != request->path.area_id ||
+      pn->path.origin.type != request->path.origin.type ||
+      pn->path.origin.id != request->path.origin.id ||
+      pn->path.origin.adv_router != request->path.origin.adv_router)
+    {
+      if (IS_OSPF6_DUMP_ROUTE)
+        {
+          ospf6_route_log_request ("Remove", table->name, request);
+          zlog_info ("ROUTE:   Can't remove: Path differ");
+          {
+            char *s, *e, *c;
+            char line[512], *p;
+
+            p = line;
+            s = (char *) &pn->path;
+            e = s + sizeof (struct ospf6_path);
+            for (c = s; c < e; c++)
+              {
+                if ((c - s) % 4 == 0)
+                  snprintf (p++, line + sizeof (line) - p, " ");
+                snprintf (p, line + sizeof (line) - p, "%02x", *c);
+                p += 2;
+              }
+            zlog_info ("ROUTE:     path: %s", line);
+
+            p = line;
+            s = (char *) &request->path;
+            e = s + sizeof (struct ospf6_path);
+            for (c = s; c < e; c++)
+              {
+                if ((c - s) % 4 == 0)
+                  snprintf (p++, line + sizeof (line) - p, " ");
+                snprintf (p, line + sizeof (line) - p, "%02x", *c);
+                p += 2;
+              }
+            zlog_info ("ROUTE:     req : %s", line);
+
+          }
+        }
+      return;
+    }
+
+  nn = ospf6_route_find_nexthop_node (request, pn);
+  if (! nn)
+    {
+      if (IS_OSPF6_DUMP_ROUTE)
+        {
+          ospf6_route_log_request ("Remove", table->name, request);
+          zlog_info ("ROUTE:   Can't remove: No such nexthop");
+        }
+      return;
+    }
+
+  if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
+    {
+      if (IS_OSPF6_DUMP_ROUTE)
+        {
+          ospf6_route_log_request ("Remove", table->name, request);
+          zlog_info ("ROUTE:   Can't remove: Nexthop differ");
+        }
+      return;
+    }
+
+  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
+
+  if (table->freeze)
+    return;
+
+  if (IS_OSPF6_DUMP_ROUTE)
+    ospf6_route_log_request ("Remove", table->name, request);
+
+  ospf6_route_request (&route, rn, pn, nn);
+  ospf6_route_hook_call (REMOVE, &route, table);
+  if (table->hook_remove)
+    (*table->hook_remove) (&route);
+
+  /* clear flag */
+  nn->flag = 0;
+
+  /* remove nexthop */
+  linklist_remove (nn, pn->nexthop_list);
+  rn->count--;
+  XFREE (MTYPE_OSPF6_ROUTE, nn);
+
+  /* remove path if there's no nexthop for the path */
+  if (pn->nexthop_list->count != 0)
+    return;
+  linklist_remove (pn, rn->path_list);
+  linklist_delete (pn->nexthop_list);
+  XFREE (MTYPE_OSPF6_ROUTE, pn);
+
+  /* remove route if there's no path for the route */
+  if (rn->path_list->count != 0)
+    return;
+  route_node->info = NULL;
+  linklist_delete (rn->path_list);
+  XFREE (MTYPE_OSPF6_ROUTE, rn);
+}
+
+void
+ospf6_route_remove_all (struct ospf6_route_table *table)
+{
+  struct ospf6_route_req request;
+
+  for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
+       ospf6_route_next (&request))
+    ospf6_route_remove (&request, table);
+}
+
+
+struct ospf6_route_table *
+ospf6_route_table_create (char *name)
+{
+  int i;
+  struct ospf6_route_table *new;
+
+  new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
+  snprintf (new->name, sizeof (new->name), "%s", name);
+
+  new->table = route_table_init ();
+  for (i = 0; i < 3; i++)
+    new->hook_list[i] = linklist_create ();
+
+  return new;
+}
+
+void
+ospf6_route_table_delete (struct ospf6_route_table *table)
+{
+  int i;
+
+  ospf6_route_remove_all (table);
+  route_table_finish (table->table);
+  for (i = 0; i < 3; i++)
+    linklist_delete (table->hook_list[i]);
+  XFREE (MTYPE_OSPF6_ROUTE, table);
+}
+
+void
+ospf6_route_table_freeze (struct ospf6_route_table *route_table)
+{
+  if (IS_OSPF6_DUMP_ROUTE)
+    zlog_info ("ROUTE: Table freeze: %s", route_table->name);
+  assert (route_table->freeze == 0);
+  route_table->freeze = 1;
+}
+
+void
+ospf6_route_table_thaw (struct ospf6_route_table *route_table)
+{
+  struct route_node *node;
+  struct linklist_node pnode;
+  struct linklist_node nnode;
+
+  struct ospf6_route_node   *rn;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+
+  struct ospf6_route_req request;
+
+  if (IS_OSPF6_DUMP_ROUTE)
+    zlog_info ("ROUTE: Table thaw: %s", route_table->name);
+
+  assert (route_table->freeze == 1);
+  route_table->freeze = 0;
+
+  for (node = route_top (route_table->table); node;
+       node = route_next (node))
+    {
+      rn = node->info;
+      if (! rn)
+        continue;
+
+      for (linklist_head (rn->path_list, &pnode);
+           ! linklist_end (&pnode);
+           linklist_next (&pnode))
+        {
+          pn = pnode.data;
+
+          for (linklist_head (pn->nexthop_list, &nnode);
+               ! linklist_end (&nnode);
+               linklist_next (&nnode))
+            {
+              nn = nnode.data;
+
+              /* if the add and remove flag set without change flag,
+                 do nothing with this route */
+              if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
+                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
+                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
+                {
+                  nn->flag = 0;
+                  continue;
+                }
+
+              memset (&request, 0, sizeof (request));
+              memcpy (&request.route, &rn->route, sizeof (rn->route));
+              memcpy (&request.path, &pn->path, sizeof (pn->path));
+              memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
+
+              if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
+                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
+                ospf6_route_add (&request, route_table);
+              else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
+                ospf6_route_remove (&request, route_table);
+            }
+        }
+    }
+}
+
+\f
+/* VTY commands */
+
+void
+ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
+{
+  struct linklist_node pnode;
+  struct linklist_node nnode;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+
+  struct timeval now, res;
+  char duration[16];
+
+  u_int pc = 0;
+  u_int nc = 0;
+#define HEAD (pc == 0 && nc == 0)
+
+  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+
+  gettimeofday (&now, (struct timezone *) NULL);
+
+  /* destination */
+  if (rn->route.prefix.family == AF_INET ||
+      rn->route.prefix.family == AF_INET6)
+    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+  else
+    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+
+  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
+       linklist_next (&pnode))
+    {
+      pn = pnode.data;
+
+      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
+           linklist_next (&nnode))
+        {
+          nn = nnode.data;
+
+          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
+                     sizeof (nexthop));
+          if (! if_indextoname (nn->nexthop.ifindex, ifname))
+            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
+
+          ospf6_timeval_sub (&now, &nn->installed, &res);
+          ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+
+          vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+                   (HEAD ? '*' : ' '),
+                   DTYPE_ABNAME (rn->route.type),
+                   PTYPE_ABNAME (pn->path.type),
+                   prefix, nexthop, ifname, duration, VTY_NEWLINE);
+
+          nc++;
+        }
+      pc++;
+    }
+}
+
+void
+ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
+{
+  struct linklist_node pnode;
+  struct linklist_node nnode;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+
+  u_int pc = 0;
+  u_int nc = 0;
+
+  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+  char area_id[16], type[16], id[16], adv[16];
+  char capa[64];
+
+  /* destination */
+  if (rn->route.prefix.family == AF_INET ||
+      rn->route.prefix.family == AF_INET6)
+    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+  else
+    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+
+  vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
+  vty_out (vty, "    Destination Type: %s%s",
+           DTYPE_NAME (rn->route.type), VTY_NEWLINE);
+
+  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
+       linklist_next (&pnode))
+    {
+      pn = pnode.data;
+
+      inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
+      ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
+      inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
+      inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
+      ospf6_options_string (pn->path.capability, capa, sizeof (capa));
+
+      vty_out (vty, "  Path:%s", VTY_NEWLINE);
+      vty_out (vty, "    Associated Area: %s%s", area_id, VTY_NEWLINE);
+      vty_out (vty, "    LS Origin: %s ID: %s Adv: %s%s",
+               type, id, adv, VTY_NEWLINE);
+      vty_out (vty, "    Path Type: %s%s",
+               PTYPE_NAME (pn->path.type), VTY_NEWLINE);
+      vty_out (vty, "    Metric Type: %d%s",
+               pn->path.metric_type, VTY_NEWLINE);
+      vty_out (vty, "    Cost: Type-1: %lu Type-2: %lu%s",
+               (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
+               VTY_NEWLINE);
+      vty_out (vty, "    Router Bits: %s|%s|%s|%s%s",
+               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
+                "W" : "-"),
+               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
+                "V" : "-"),
+               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
+                "E" : "-"),
+               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
+                "B" : "-"), VTY_NEWLINE);
+      vty_out (vty, "    Optional Capabilities: %s%s", capa, VTY_NEWLINE);
+      vty_out (vty, "    Prefix Options: %s%s", "xxx", VTY_NEWLINE);
+      vty_out (vty, "    Next Hops:%s", VTY_NEWLINE);
+
+      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
+           linklist_next (&nnode))
+        {
+          nn = nnode.data;
+
+          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
+                     sizeof (nexthop));
+          if (! if_indextoname (nn->nexthop.ifindex, ifname))
+            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
+
+          vty_out (vty, "       %c%s%%%s%s",
+                   (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
+
+          nc++;
+        }
+      pc++;
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+ospf6_route_table_show (struct vty *vty, int argc, char **argv,
+                        struct ospf6_route_table *table)
+{
+  int i, ret;
+  unsigned long ret_ul;
+  char *endptr;
+  struct prefix prefix;
+  int detail = 0;
+  int arg_ipv6  = 0;
+  int arg_ipv4  = 0;
+  int arg_digit = 0;
+  struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
+  struct prefix_ls   *pl = (struct prefix_ls *) &prefix;
+  struct route_node *node;
+
+  u_int route_count = 0;
+  u_int path_count = 0;
+  u_int route_redundant = 0;
+
+  memset (&prefix, 0, sizeof (struct prefix));
+
+  for (i = 0; i < argc; i++)
+    {
+      if (! strcmp (argv[i], "detail"))
+        {
+          detail++;
+          break;
+        }
+
+      if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
+        {
+
+          if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
+            {
+              p6->family = AF_INET6;
+              p6->prefixlen = 128;
+              arg_ipv6++;
+              continue;
+            }
+          else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
+            {
+              pl->family = AF_UNSPEC;
+              pl->prefixlen = 64; /* xxx */
+              arg_ipv4++;
+              continue;
+            }
+          else
+            {
+              ret_ul = strtoul (argv[i], &endptr, 10);
+              if (*endptr == '\0')
+                {
+                  pl->adv_router.s_addr = htonl (ret_ul);
+                  pl->family = AF_UNSPEC;
+                  pl->prefixlen = 64; /* xxx */
+                  arg_digit++;
+                  continue;
+                }
+              else
+                {
+                  vty_out (vty, "Malformed argument: %s%s",
+                           argv[i], VTY_NEWLINE);
+                  return CMD_SUCCESS;
+                }
+            }
+        }
+
+      if (arg_ipv4 || arg_digit)
+        {
+          if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
+            {
+              arg_ipv4++;
+            }
+          else
+            {
+              ret_ul = strtoul (argv[i], &endptr, 10);
+              if (*endptr == '\0')
+                {
+                  pl->id.s_addr = htonl (ret_ul);
+                  arg_digit++;
+                }
+              else
+                {
+                  vty_out (vty, "Malformed argument: %s%s",
+                           argv[i], VTY_NEWLINE);
+                  return CMD_SUCCESS;
+                }
+            }
+        }
+    }
+
+  if (arg_ipv4 || arg_ipv6 || arg_digit)
+    {
+      node = route_node_match (table->table, &prefix);
+      if (node && node->info)
+        ospf6_route_show_detail (vty, node->info);
+      return CMD_SUCCESS;
+    }
+
+  if (! detail)
+    {
+      vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
+               ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
+      vty_out (vty, "---------------------------%s", VTY_NEWLINE);
+    }
+
+  for (node = route_top (table->table); node; node = route_next (node))
+    {
+      struct ospf6_route_node *route = node->info;
+
+      if (! route)
+        continue;
+
+      if (detail)
+        ospf6_route_show_detail (vty, route);
+      else
+        ospf6_route_show (vty, route);
+
+      route_count++;
+      path_count += route->path_list->count;
+      if (route->path_list->count > 1)
+        route_redundant++;
+    }
+
+  vty_out (vty, "===========%s", VTY_NEWLINE);
+  vty_out (vty, "Route: %d Path: %d Redundant: %d%s",
+           route_count, path_count, route_redundant, VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
new file mode 100644 (file)
index 0000000..71b2562
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_ROUTE_H
+#define OSPF6_ROUTE_H
+
+#include "ospf6_hook.h"
+#include "ospf6_linklist.h"
+
+struct ospf6_route_table
+{
+  char name[128];
+
+  int freeze;
+
+  /* radix tree */
+  struct route_table *table;
+
+  /* list of hooks */
+  struct linklist *hook_list[3];
+  void (*hook_add) (void *);
+  void (*hook_change) (void *);
+  void (*hook_remove) (void *);
+
+  u_int32_t route_id;
+};
+
+\f
+
+struct ospf6_route
+{
+  /* Destination ID */
+  struct prefix prefix;
+
+  /* Destination Type */
+  u_char type;
+};
+
+/* Path */
+struct ls_origin
+{
+  u_int16_t type;
+  u_int32_t id;
+  u_int32_t adv_router;
+};
+
+struct ospf6_path
+{
+  /* Link State Origin */
+  struct ls_origin origin;
+
+  /* Router bits */
+  u_char router_bits;
+
+  /* Optional Capabilities */
+  u_char capability[3];
+
+  /* Prefix Options */
+  u_char prefix_options;
+
+  /* Associated Area */
+  u_int32_t area_id;
+
+  /* Path-type */
+  u_char type;
+
+  /* Cost */
+  u_int8_t metric_type;
+  u_int32_t cost;
+  u_int32_t cost_e2;
+};
+
+/* Nexthop */
+struct ospf6_nexthop
+{
+  /* Interface index */
+  unsigned int ifindex;
+
+  /* IP address, if any */
+  struct in6_addr address;
+};
+
+struct ospf6_route_node
+{
+  struct ospf6_route_table *table;
+  int count;
+  u_int32_t route_id;
+
+  struct route_node  *route_node;
+  struct ospf6_route  route;
+  struct linklist    *path_list;
+};
+
+struct ospf6_path_node
+{
+  struct ospf6_route_node *route_node;
+  struct ospf6_path        path;
+  struct linklist         *nexthop_list;
+};
+
+struct ospf6_nexthop_node
+{
+  int            flag;
+  struct timeval installed;
+
+  struct ospf6_path_node *path_node;
+  struct ospf6_nexthop    nexthop;
+};
+
+struct ospf6_route_req
+{
+  struct ospf6_route_table *table;
+  struct route_node    *route_node;
+  struct linklist_node  path_lnode;
+  struct linklist_node  nexthop_lnode;
+  u_int32_t route_id;
+
+  int count;
+  struct ospf6_route   route;
+  struct ospf6_path    path;
+  struct ospf6_nexthop nexthop;
+};
+
+#define OSPF6_DEST_TYPE_NONE       0
+#define OSPF6_DEST_TYPE_ROUTER     1
+#define OSPF6_DEST_TYPE_NETWORK    2
+#define OSPF6_DEST_TYPE_DISCARD    3
+#define OSPF6_DEST_TYPE_MAX        4
+
+#define OSPF6_PATH_TYPE_NONE       0
+#define OSPF6_PATH_TYPE_INTRA      1
+#define OSPF6_PATH_TYPE_INTER      2
+#define OSPF6_PATH_TYPE_EXTERNAL1  3
+#define OSPF6_PATH_TYPE_EXTERNAL2  4
+#define OSPF6_PATH_TYPE_ZOFFSET    5
+#define OSPF6_PATH_TYPE_ZSYSTEM  (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_SYSTEM)
+#define OSPF6_PATH_TYPE_ZKERNEL  (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_KERNEL)
+#define OSPF6_PATH_TYPE_ZCONNECT (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_CONNECT)
+#define OSPF6_PATH_TYPE_ZSTATIC  (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_STATIC)
+#define OSPF6_PATH_TYPE_ZRIP     (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIP)
+#define OSPF6_PATH_TYPE_ZRIPNG   (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIPNG)
+#define OSPF6_PATH_TYPE_ZOSPF    (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF)
+#define OSPF6_PATH_TYPE_ZOSPF6   (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF6)
+#define OSPF6_PATH_TYPE_ZBGP     (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_BGP)
+#define OSPF6_PATH_TYPE_MAX      (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_MAX)
+
+#define OSPF6_ROUTE_FLAG_ROUTE_CHANGE      0x01
+#define OSPF6_ROUTE_FLAG_PATH_CHANGE       0x02
+#define OSPF6_ROUTE_FLAG_ADD               0x04
+#define OSPF6_ROUTE_FLAG_REMOVE            0x08
+#define OSPF6_ROUTE_FLAG_CHANGE            0x10
+
+int ospf6_route_lookup (struct ospf6_route_req *request,
+                        struct prefix *prefix,
+                        struct ospf6_route_table *table);
+void ospf6_route_head  (struct ospf6_route_req *request,
+                        struct ospf6_route_table *table);
+int  ospf6_route_end   (struct ospf6_route_req *request);
+void ospf6_route_next  (struct ospf6_route_req *request);
+
+void ospf6_route_add (struct ospf6_route_req *, struct ospf6_route_table *);
+void ospf6_route_remove (struct ospf6_route_req *, struct ospf6_route_table *);
+void ospf6_route_remove_all (struct ospf6_route_table *);
+
+struct ospf6_route_table *ospf6_route_table_create ();
+void ospf6_route_table_delete (struct ospf6_route_table *);
+
+void ospf6_route_table_freeze (struct ospf6_route_table *);
+void ospf6_route_table_thaw (struct ospf6_route_table *);
+
+void ospf6_route_log_request (char *what, char *where,
+                              struct ospf6_route_req *request);
+
+void
+ospf6_route_hook_register (void (*add)    (struct ospf6_route_req *),
+                           void (*change) (struct ospf6_route_req *),
+                           void (*remove) (struct ospf6_route_req *),
+                           struct ospf6_route_table *table);
+void
+ospf6_route_hook_unregister (void (*add)    (struct ospf6_route_req *),
+                             void (*change) (struct ospf6_route_req *),
+                             void (*remove) (struct ospf6_route_req *),
+                             struct ospf6_route_table *table);
+
+void ospf6_route_init ();
+
+int ospf6_route_table_show (struct vty *, int, char **,
+                            struct ospf6_route_table *);
+
+#endif /* OSPF6_ROUTE_H */
+
diff --git a/ospf6d/ospf6_routemap.c b/ospf6d/ospf6_routemap.c
new file mode 100644 (file)
index 0000000..14df794
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * OSPFv3 Route-Map
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+
+#include "ospf6_route.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_asbr.h"
+
+route_map_result_t
+ospf6_routemap_rule_match_address_prefixlist (void *rule,
+                                              struct prefix *prefix,
+                                              route_map_object_t type,
+                                              void *object)
+{
+  struct prefix_list *plist;
+
+  if (type != RMAP_OSPF6)
+    return RMAP_NOMATCH;
+
+  plist = prefix_list_lookup (AFI_IP6, (char *) rule);
+
+  if (plist == NULL)
+    return RMAP_NOMATCH;
+
+  return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+          RMAP_NOMATCH : RMAP_MATCH);
+}
+
+void *
+ospf6_routemap_rule_match_address_prefixlist_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_match_address_prefixlist_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_match_address_prefixlist_cmd =
+{
+  "ipv6 address prefix-list",
+  ospf6_routemap_rule_match_address_prefixlist,
+  ospf6_routemap_rule_match_address_prefixlist_compile,
+  ospf6_routemap_rule_match_address_prefixlist_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix,
+                                     route_map_object_t type, void *object)
+{
+  char *metric_type = rule;
+  struct ospf6_external_info *info = object;
+
+  if (type != RMAP_OSPF6)
+    return RMAP_OKAY;
+
+  if (strcmp (metric_type, "type-2") == 0)
+    info->metric_type = 2;
+  else
+    info->metric_type = 1;
+
+  return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_metric_type_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_metric_type_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_type_cmd =
+{
+  "metric-type",
+  ospf6_routemap_rule_set_metric_type,
+  ospf6_routemap_rule_set_metric_type_compile,
+  ospf6_routemap_rule_set_metric_type_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix,
+                                route_map_object_t type, void *object)
+{
+  char *metric = rule;
+  struct ospf6_external_info *info = object;
+
+  if (type != RMAP_OSPF6)
+    return RMAP_OKAY;
+
+  info->metric = atoi (metric);
+  return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_metric_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_cmd =
+{
+  "metric",
+  ospf6_routemap_rule_set_metric,
+  ospf6_routemap_rule_set_metric_compile,
+  ospf6_routemap_rule_set_metric_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  char *forwarding = rule;
+  struct ospf6_external_info *info = object;
+
+  if (type != RMAP_OSPF6)
+    return RMAP_OKAY;
+
+  if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
+    {
+      memset (&info->forwarding, 0, sizeof (struct in6_addr));
+      return RMAP_ERROR;
+    }
+
+  return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_forwarding_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_forwarding_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_forwarding_cmd =
+{
+  "forwarding-address",
+  ospf6_routemap_rule_set_forwarding,
+  ospf6_routemap_rule_set_forwarding_compile,
+  ospf6_routemap_rule_set_forwarding_free,
+};
+
+int
+route_map_command_status (struct vty *vty, int ret)
+{
+  if (! ret)
+    return CMD_SUCCESS;
+
+  switch (ret)
+    {
+    case RMAP_RULE_MISSING:
+      vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+      break;
+    case RMAP_COMPILE_ERROR:
+      vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+      break;
+    default:                          
+      vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE);
+      break;
+    }
+  return CMD_WARNING;
+}
+
+/* add "match address" */
+DEFUN (ospf6_routemap_match_address_prefixlist,
+       ospf6_routemap_match_address_prefixlist_cmd,
+       "match ipv6 address prefix-list WORD",
+       "Match values\n"
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IPv6 prefix-list name\n")
+{
+  int ret = route_map_add_match ((struct route_map_index *) vty->index,
+                                 "ipv6 address prefix-list", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "match address" */
+DEFUN (ospf6_routemap_no_match_address_prefixlist,
+       ospf6_routemap_no_match_address_prefixlist_cmd,
+       "no match ipv6 address prefix-list WORD",
+       NO_STR
+       "Match values\n"
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IPv6 prefix-list name\n")
+{
+  int ret = route_map_delete_match ((struct route_map_index *) vty->index,
+                                    "ipv6 address prefix-list", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* add "set metric-type" */
+DEFUN (ospf6_routemap_set_metric_type,
+       ospf6_routemap_set_metric_type_cmd,
+       "set metric-type (type-1|type-2)",
+       "Set value\n"
+       "Type of metric\n"
+       "OSPF6 external type 1 metric\n"
+       "OSPF6 external type 2 metric\n")
+{
+  int ret = route_map_add_set ((struct route_map_index *) vty->index,
+                               "metric-type", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric-type" */
+DEFUN (ospf6_routemap_no_set_metric_type,
+       ospf6_routemap_no_set_metric_type_cmd,
+       "no set metric-type (type-1|type-2)",
+       NO_STR
+       "Set value\n"
+       "Type of metric\n"
+       "OSPF6 external type 1 metric\n"
+       "OSPF6 external type 2 metric\n")
+{
+  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+                                  "metric-type", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* add "set metric" */
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       "Set value\n"
+       "Metric value\n"
+       "Metric value\n")
+{
+  int ret = route_map_add_set ((struct route_map_index *) vty->index,
+                               "metric", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric" */
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       "Set value\n"
+       "Metric\n"
+       "METRIC value\n")
+{
+  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+                                  "metric", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* add "set forwarding-address" */
+DEFUN (ospf6_routemap_set_forwarding,
+       ospf6_routemap_set_forwarding_cmd,
+       "set forwarding-address X:X::X:X",
+       "Set value\n"
+       "Forwarding Address\n"
+       "IPv6 Address\n")
+{
+  int ret = route_map_add_set ((struct route_map_index *) vty->index,
+                               "forwarding-address", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "set forwarding-address" */
+DEFUN (ospf6_routemap_no_set_forwarding,
+       ospf6_routemap_no_set_forwarding_cmd,
+       "no set forwarding-address X:X::X:X",
+       NO_STR
+       "Set value\n"
+       "Forwarding Address\n"
+       "IPv6 Address\n")
+{
+  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+                                  "forwarding-address", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+void
+ospf6_routemap_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+  route_map_add_hook (ospf6_asbr_routemap_update);
+  route_map_delete_hook (ospf6_asbr_routemap_update);
+
+  route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd);
+  route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd);
+  route_map_install_set (&ospf6_routemap_rule_set_metric_cmd);
+  route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd);
+
+  /* Match address prefix-list */
+  install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd);
+  install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd);
+
+  /* ASE Metric Type (e.g. Type-1/Type-2) */
+  install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
+  install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
+
+  /* ASE Metric */
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+
+  /* ASE Metric */
+  install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
+  install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
+}
+
diff --git a/ospf6d/ospf6_routemap.h b/ospf6d/ospf6_routemap.h
new file mode 100644 (file)
index 0000000..c68e0ff
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * OSPFv3 Route-Map
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_ROUTEMAP_H
+
+void ospf6_routemap_init ();
+
+#endif /* OSPF6_ROUTEMAP_H */
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
new file mode 100644 (file)
index 0000000..fd7fc77
--- /dev/null
@@ -0,0 +1,1454 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+/* Shortest Path First calculation for OSPFv3 */
+
+#include "ospf6d.h"
+
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
+#include "ospf6_spf.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+
+#include "ospf6_bintree.h"
+#include "ospf6_linklist.h"
+
+struct bintree *_candidate_list;
+struct linklist *nexthop_list;
+
+struct ospf6_spf_candidate_node
+{
+  u_int32_t cost;
+  struct linklist *list;
+};
+
+int
+ospf6_spf_candidate_node_cmp (void *a, void *b)
+{
+  struct ospf6_spf_candidate_node *ca = a;
+  struct ospf6_spf_candidate_node *cb = b;
+  return ca->cost - cb->cost;
+}
+
+int
+ospf6_spf_vertex_cmp (void *a, void *b)
+{
+  return 1;
+}
+
+void
+ospf6_spf_candidate_node_print (int indent_num, void *node)
+{
+  struct ospf6_spf_candidate_node *cn = node;
+  char format[256];
+
+  snprintf (format, sizeof (format), "%%%ds %%d (num: %%d)",
+            indent_num * 2 + 1);
+  zlog_info (format, " ", cn->cost, cn->list->count);
+}
+
+void
+ospf6_spf_candidate_init ()
+{
+  _candidate_list = bintree_create ();
+  _candidate_list->cmp = ospf6_spf_candidate_node_cmp;
+}
+
+u_int32_t
+ospf6_spf_candidate_count ()
+{
+  u_int32_t count = 0;
+  struct bintree_node node;
+  struct ospf6_spf_candidate_node *cnode;
+
+  for (bintree_head (_candidate_list, &node); ! bintree_end (&node);
+       bintree_next (&node))
+    {
+      cnode = node.data;
+      count += cnode->list->count;
+    }
+
+  return count;
+}
+
+void
+ospf6_spf_candidate_print ()
+{
+  zlog_info ("---------------------------");
+  bintree_print (ospf6_spf_candidate_node_print, _candidate_list);
+  zlog_info ("---------------------------");
+}
+
+void
+ospf6_spf_candidate_enqueue (struct ospf6_vertex *v)
+{
+  struct ospf6_spf_candidate_node req, *node;
+
+  memset (&req, 0, sizeof (req));
+  req.cost = v->distance;
+  node = bintree_lookup (&req, _candidate_list);
+
+  if (node == NULL)
+    {
+      node = malloc (sizeof (struct ospf6_spf_candidate_node));
+      node->cost = v->distance;
+      node->list = linklist_create ();
+      node->list->cmp = ospf6_spf_vertex_cmp;
+      bintree_add (node, _candidate_list);
+    }
+
+  linklist_add (v, node->list);
+
+#if 0
+  if (IS_OSPF6_DUMP_SPF)
+    ospf6_spf_candidate_print ();
+#endif
+}
+
+struct ospf6_vertex *
+ospf6_spf_candidate_dequeue ()
+{
+  struct ospf6_spf_candidate_node *node;
+  struct linklist_node lnode;
+  struct ospf6_vertex *ret;
+
+  node = bintree_lookup_min (_candidate_list);
+  if (node == NULL)
+    return NULL;
+
+  linklist_head (node->list, &lnode);
+  ret = lnode.data;
+
+  linklist_remove (ret, node->list);
+  if (node->list->count == 0)
+    {
+      linklist_delete (node->list);
+      bintree_remove (node, _candidate_list);
+    }
+
+#if 0
+  if (IS_OSPF6_DUMP_SPF)
+    ospf6_spf_candidate_print ();
+#endif
+
+  return ret;
+}
+
+void
+ospf6_spf_candidate_remove (struct ospf6_vertex *v)
+{
+  struct bintree_node node;
+  struct ospf6_spf_candidate_node *cnode = NULL;
+
+  for (bintree_head (_candidate_list, &node); ! bintree_end (&node);
+       bintree_next (&node))
+    {
+      cnode = node.data;
+      if (linklist_lookup (v, cnode->list))
+        {
+          linklist_remove (v, cnode->list);
+          break;
+        }
+    }
+
+  if (cnode->list->count == 0)
+    {
+      linklist_delete (cnode->list);
+      bintree_remove (cnode, _candidate_list);
+    }
+}
+
+\f
+#define TIMER_SEC_MICRO 1000000
+
+/* timeval calculation */
+static void
+ospf6_timeval_add (const struct timeval *t1, const struct timeval *t2,
+                   struct timeval *result)
+{
+  long moveup = 0;
+
+  result->tv_usec = t1->tv_usec + t2->tv_usec;
+  while (result->tv_usec > TIMER_SEC_MICRO)
+    {
+      result->tv_usec -= TIMER_SEC_MICRO;
+      moveup ++;
+    }
+
+  result->tv_sec = t1->tv_sec + t2->tv_sec + moveup;
+}
+
+static void
+ospf6_timeval_add_equal (const struct timeval *t, struct timeval *result)
+{
+  struct timeval tmp;
+  ospf6_timeval_add (t, result, &tmp);
+  result->tv_sec = tmp.tv_sec;
+  result->tv_usec = tmp.tv_usec;
+}
+
+/* Compare timeval a and b.  It returns an integer less than, equal
+   to, or great than zero if a is found, respectively, to be less
+   than, to match, or be greater than b.  */
+static int
+ospf6_timeval_cmp (const struct timeval t1, const struct timeval t2)
+{
+  return (t1.tv_sec == t2.tv_sec
+         ? t1.tv_usec - t2.tv_usec : t1.tv_sec - t2.tv_sec);
+}
+
+\f
+static int
+ospf6_spf_lsd_num (struct ospf6_vertex *V, struct ospf6_area *o6a)
+{
+  u_int16_t type;
+  u_int32_t id, adv_router;
+  struct ospf6_lsa *lsa;
+
+  if (V->vertex_id.id.s_addr)
+    type = htons (OSPF6_LSA_TYPE_NETWORK);
+  else
+    type = htons (OSPF6_LSA_TYPE_ROUTER);
+  id = V->vertex_id.id.s_addr;
+  adv_router = V->vertex_id.adv_router.s_addr;
+
+  lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+  if (! lsa)
+    {
+      zlog_err ("SPF: Can't find associated LSA for %s", V->string);
+      return 0;
+    }
+
+  return ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header);
+}
+
+/* RFC2328 section 16.1.1:
+   Check if there is at least one router in the path
+   from the root to this vertex. */
+static int
+ospf6_spf_is_router_to_root (struct ospf6_vertex *c,
+                             struct ospf6_spftree *spf_tree)
+{
+  listnode node;
+  struct ospf6_vertex *p;
+
+  if (spf_tree->root == c)
+    return 0;
+
+  for (node = listhead (c->parent_list); node; nextnode (node))
+    {
+      p = (struct ospf6_vertex *) getdata (node);
+
+      if (p == spf_tree->root)
+        return 0;
+
+      if (p->vertex_id.id.s_addr == 0) /* this is router */
+        continue;
+      else if (ospf6_spf_is_router_to_root (p, spf_tree))
+        continue;
+
+      return 0;
+    }
+
+  return 1;
+}
+
+static struct in6_addr *
+ospf6_spf_get_ipaddr (u_int32_t id, u_int32_t adv_router, u_int32_t ifindex)
+{
+  char buf[64], nhbuf[64];
+  struct ospf6_interface *o6i;
+  struct ospf6_neighbor *o6n;
+  struct ospf6_lsa *lsa;
+  struct ospf6_lsdb_node node;
+
+  o6i = ospf6_interface_lookup_by_index (ifindex);
+  if (! o6i)
+    {
+      zlog_err ("SPF: Can't find interface: index %d", ifindex);
+      return (struct in6_addr *) NULL;
+    }
+
+  /* Find Link-LSA of the vertex in question */
+  lsa = NULL;
+  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_LINK),
+                               adv_router, o6i->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    lsa = node.lsa;
+
+  /* return Linklocal Address field if the Link-LSA exists */
+  if (lsa && lsa->header->adv_router == adv_router)
+    {
+      struct ospf6_link_lsa *link_lsa;
+      link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1);
+      return &link_lsa->llsa_linklocal;
+    }
+
+  zlog_warn ("SPF: Can't find Link-LSA for %s",
+             inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)));
+
+  o6n = ospf6_neighbor_lookup (adv_router, o6i);
+  if (! o6n)
+    {
+      inet_ntop (AF_INET, &adv_router, buf, sizeof (buf));
+      zlog_err ("SPF: Can't find neighbor %s in %s, "
+                "unable to find his linklocal address",
+                buf, o6i->interface->name);
+      return (struct in6_addr *) NULL;
+    }
+
+  zlog_warn ("SPF: use packet's source address for %s's nexthop: %s",
+             inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)),
+             inet_ntop (AF_INET6, &o6n->hisaddr, nhbuf, sizeof (nhbuf)));
+
+  return &o6n->hisaddr;
+}
+
+static int
+ospf6_spf_nexthop_calculation (struct ospf6_vertex *W,
+                               u_int32_t ifindex,
+                               struct ospf6_vertex *V,
+                               struct ospf6_spftree *spf_tree)
+{
+  struct ospf6_nexthop *nexthop, *n;
+  u_int32_t adv_router, id;
+  struct in6_addr nexthop_ipaddr, *ipaddr;
+  unsigned int nexthop_ifindex;
+  struct linklist_node node;
+
+  /* until this, nexthop_list should be untouched */
+  assert (list_isempty (W->nexthop_list));
+
+  /* If ther is at least one intervening router from root to W */
+  if (ospf6_spf_is_router_to_root (W, spf_tree))
+    {
+      /* Create no new nexthop, Inherit from the intervening router */
+      for (linklist_head (V->nexthop_list, &node); ! linklist_end (&node);
+           linklist_next (&node))
+        linklist_add (node.data, W->nexthop_list);
+      return 0;
+    }
+
+  /* Create new nexthop */
+
+  adv_router = W->vertex_id.adv_router.s_addr;
+  id = W->vertex_id.id.s_addr;
+
+  nexthop_ifindex = 0;
+  memset (&nexthop_ipaddr, 0, sizeof (struct in6_addr));
+  if (spf_tree->root && V == spf_tree->root)
+    {
+      nexthop_ifindex = ifindex;
+      if (! id) /* xxx, if V is router */
+        {
+          ipaddr = ospf6_spf_get_ipaddr (id, adv_router, ifindex);
+          if (! ipaddr)
+            {
+              /* xxx, should trigger error and quit SPF calculation... */
+              memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr));
+              return -1;
+            }
+          else
+            memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr));
+        }
+    }
+  else
+    {
+      /* V is broadcast network, W is router */
+      assert (V->vertex_id.id.s_addr != 0);
+      assert (W->vertex_id.id.s_addr == 0);
+      linklist_head (V->nexthop_list, &node);
+      n = (struct ospf6_nexthop *) node.data;
+      nexthop_ifindex = n->ifindex;
+      ipaddr = ospf6_spf_get_ipaddr (id, adv_router, n->ifindex);
+      if (! ipaddr)
+        {
+          /* xxx, should trigger error and quit SPF calculation... */
+          memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr));
+          return -1;
+        }
+      else
+        memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr));
+    }
+
+  nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop));
+  nexthop->ifindex = nexthop_ifindex;
+  memcpy (&nexthop->address, &nexthop_ipaddr, sizeof (nexthop->address));
+
+  linklist_add (nexthop, W->nexthop_list);
+
+  /* to hold malloced memory */
+  linklist_add (nexthop, nexthop_list);
+
+  return 0;
+}
+
+static struct ospf6_vertex *
+ospf6_spf_vertex_create (int index, struct ospf6_vertex *V,
+                         struct ospf6_area *o6a)
+{
+  struct ospf6_lsa *lsa;
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsd *router_lsd;
+  struct ospf6_network_lsa *network_lsa;
+  struct ospf6_network_lsd *network_lsd;
+  u_int32_t id, adv_router;
+  u_int16_t type;
+  void *lsd;
+  struct ospf6_vertex *W;
+  u_int16_t distance;
+  u_int32_t ifindex;
+  int backreference, lsdnum, i;
+  char buf_router[16], buf_id[16];
+
+  type = id = adv_router = 0;
+
+  /* Get Linkstate description */
+  lsd = ospf6_lsa_lsd_get (index, (struct ospf6_lsa_header *) V->lsa->header);
+  if (! lsd)
+    {
+      zlog_err ("SPF: Can't find %dth Link description from %s",
+                index, V->lsa->str);
+      return (struct ospf6_vertex *) NULL;
+    }
+
+  /* Check Link state description */
+  distance = 0;
+  ifindex = 0;
+  if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+    {
+      router_lsd = lsd;
+      if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
+        {
+          type = htons (OSPF6_LSA_TYPE_ROUTER);
+          id = htonl (0);
+        }
+      else if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
+        {
+          type = htons (OSPF6_LSA_TYPE_NETWORK);
+          id = router_lsd->neighbor_interface_id;
+        }
+      adv_router = router_lsd->neighbor_router_id;
+      distance = ntohs (router_lsd->metric);
+      ifindex = ntohl (router_lsd->interface_id);
+    }
+  else if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+    {
+      network_lsd = lsd;
+      type = htons (OSPF6_LSA_TYPE_ROUTER);
+      id = htonl (0);
+      adv_router = network_lsd->adv_router;
+    }
+
+  /* Avoid creating candidate of myself */
+  if (adv_router == o6a->ospf6->router_id &&
+      type == htons (OSPF6_LSA_TYPE_ROUTER))
+    {
+      return (struct ospf6_vertex *) NULL;
+    }
+
+  /* Find Associated LSA for W */
+  lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+  if (! lsa)
+    {
+      inet_ntop (AF_INET, &adv_router, buf_router, sizeof (buf_router));
+      inet_ntop (AF_INET, &id, buf_id, sizeof (buf_id));
+
+      if (IS_OSPF6_DUMP_SPF)
+        {
+          if (type == htons (OSPF6_LSA_TYPE_ROUTER))
+            zlog_info ("SPF: Can't find LSA for W (%s *): not found",
+                      buf_router);
+          else
+            zlog_info ("SPF: Can't find LSA for W (%s %s): not found",
+                      buf_router, buf_id);
+        }
+      return (struct ospf6_vertex *) NULL;
+    }
+
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      if (IS_OSPF6_DUMP_SPF)
+        zlog_info ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
+      return (struct ospf6_vertex *) NULL;
+    }
+
+  /* Check back reference from W's lsa to V's lsa */
+  backreference = 0;
+  lsdnum = ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header);
+  for (i = 0; i < lsdnum; i++)
+    {
+      if (ospf6_lsa_lsd_is_refer_ok (i, (struct ospf6_lsa_header *) lsa->header,
+                                     index, (struct ospf6_lsa_header *) V->lsa->header))
+        backreference++;
+    }
+  if (! backreference)
+    {
+      if (IS_OSPF6_DUMP_SPF)
+        zlog_info ("SPF: Back reference failed: V: %s, W: %s",
+                   V->lsa->str, lsa->str);
+      return (struct ospf6_vertex *) NULL;
+    }
+
+  /* Allocate new ospf6_vertex for W */
+  W = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX,
+                                       sizeof (struct ospf6_vertex));
+  if (! W)
+    {
+      zlog_err ("SPF: Can't allocate memory for Vertex");
+      return (struct ospf6_vertex *) NULL;
+    }
+  memset (W, 0, sizeof (struct ospf6_vertex));
+
+  /* Initialize */
+  W->vertex_id.family = AF_UNSPEC;
+  W->vertex_id.prefixlen = 64; /* xxx */
+  W->lsa = lsa;
+  if (type == htons (OSPF6_LSA_TYPE_ROUTER))
+    W->vertex_id.id.s_addr = htonl (0); /* XXX */
+  else
+    W->vertex_id.id.s_addr = W->lsa->header->id;
+  W->vertex_id.adv_router.s_addr = W->lsa->header->adv_router;
+  W->nexthop_list = linklist_create ();
+  W->path_list = list_new ();
+  W->parent_list = list_new ();
+  W->distance = V->distance + distance;
+  W->depth = V->depth + 1;
+
+  inet_ntop (AF_INET, &W->vertex_id.adv_router.s_addr,
+             buf_router, sizeof (buf_router));
+  inet_ntop (AF_INET, &W->vertex_id.id.s_addr, buf_id, sizeof (buf_id));
+  snprintf (W->string, sizeof (W->string), "[%s-%s (%d)]",
+            buf_router, buf_id, W->distance);
+
+  /* capability bits and optional capabilities */
+  if (W->vertex_id.id.s_addr == 0)
+    {
+      router_lsa = (struct ospf6_router_lsa *) (W->lsa->header + 1);
+      W->capability_bits = router_lsa->bits;
+      memcpy (W->opt_capability, router_lsa->options,
+              sizeof (W->opt_capability));
+    }
+  else
+    {
+      network_lsa = (struct ospf6_network_lsa *) (W->lsa->header + 1);
+      W->capability_bits = network_lsa->reserved;
+      memcpy (W->opt_capability, network_lsa->options,
+              sizeof (W->opt_capability));
+    }
+
+  /* Link to Parent node */
+  listnode_add (W->parent_list, V);
+
+  /* Nexthop Calculation */
+  if (ospf6_spf_nexthop_calculation (W, ifindex, V, o6a->spf_tree) < 0)
+    return NULL;
+
+  return W;
+}
+
+static void
+ospf6_spf_vertex_delete (struct ospf6_vertex *v)
+{
+  linklist_delete (v->nexthop_list);
+  list_delete (v->path_list);
+  list_delete (v->parent_list);
+  XFREE (MTYPE_OSPF6_VERTEX, v);
+}
+
+static void
+ospf6_spf_vertex_merge (struct ospf6_vertex *w, struct ospf6_vertex *x)
+{
+  listnode node;
+  struct linklist_node lnode;
+
+  /* merge should be done on two nodes which are
+     almost the same */
+
+  /* these w and x should be both candidate.
+     candidate should not have any children */
+  assert (list_isempty (w->path_list));
+  assert (list_isempty (x->path_list));
+
+  /* merge parent list */
+  for (node = listhead (w->parent_list); node; nextnode (node))
+    {
+      if (listnode_lookup (x->parent_list, getdata (node)))
+        continue;
+      listnode_add (x->parent_list, getdata (node));
+    }
+
+  /* merge nexthop list */
+  for (linklist_head (w->nexthop_list, &lnode); ! linklist_end (&lnode);
+       linklist_next (&lnode))
+    linklist_add (lnode.data, x->nexthop_list);
+}
+
+static void
+ospf6_spf_initialize (list candidate_list, struct ospf6_area *o6a)
+{
+  listnode node;
+  struct ospf6_vertex *v;
+  struct ospf6_lsa *lsa;
+  u_int16_t type;
+  u_int32_t id, adv_router;
+  struct linklist_node lnode;
+
+  struct ospf6_nexthop *nexthop;
+  struct interface *ifp;
+  char buf_router[64], buf_id[64];
+
+  /* delete topology routing table for this area */
+  ospf6_route_remove_all (o6a->table_topology);
+
+  /* Delete previous spf tree */
+  for (node = listhead (o6a->spf_tree->list); node; nextnode (node))
+    {
+      v = (struct ospf6_vertex *) getdata (node);
+      ospf6_spf_vertex_delete (v);
+    }
+  list_delete_all_node (o6a->spf_tree->list);
+
+  for (linklist_head (nexthop_list, &lnode); ! linklist_end (&lnode);
+       linklist_next (&lnode))
+    XFREE (MTYPE_OSPF6_VERTEX, lnode.data);
+  linklist_remove_all (nexthop_list);
+
+  /* Find self originated Router-LSA */
+  type = htons (OSPF6_LSA_TYPE_ROUTER);
+  id = htonl (0);
+  adv_router = ospf6->router_id;
+
+  lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
+
+  if (! lsa)
+    {
+      if (IS_OSPF6_DUMP_SPF)
+        zlog_info ("SPF: Can't find self originated Router-LSA");
+      return;
+    }
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      zlog_err ("SPF: MaxAge self originated Router-LSA");
+      return;
+    }
+
+  /* Create root vertex */
+  v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX,
+                                       sizeof (struct ospf6_vertex));
+  if (! v)
+    {
+      zlog_err ("SPF: Can't allocate memory for root vertex");
+      return;
+    }
+  memset (v, 0, sizeof (struct ospf6_vertex));
+
+  v->vertex_id.family = AF_UNSPEC; /* XXX */
+  v->vertex_id.prefixlen = 64; /* XXX */
+  v->vertex_id.id.s_addr = htonl (0);
+  v->vertex_id.adv_router.s_addr = ospf6->router_id;
+  if (ospf6_is_asbr (ospf6))
+    OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_E);
+  OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_V6);
+  OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_R);
+  v->nexthop_list = linklist_create ();
+  v->path_list = list_new ();
+  v->parent_list = list_new ();
+  v->distance = 0;
+  v->depth = 0;
+  v->lsa = lsa;
+
+  inet_ntop (AF_INET, &v->vertex_id.adv_router.s_addr,
+             buf_router, sizeof (buf_router));
+  inet_ntop (AF_INET, &v->vertex_id.id.s_addr, buf_id, sizeof (buf_id));
+  snprintf (v->string, sizeof (v->string), "[%s-%s (%d)]",
+            buf_router, buf_id, v->distance);
+
+  nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop));
+  ifp = if_lookup_by_name ("lo0");
+  if (ifp)
+    nexthop->ifindex = ifp->ifindex;
+  inet_pton (AF_INET6, "::1", &nexthop->address);
+  linklist_add (nexthop, v->nexthop_list);
+  linklist_add (nexthop, nexthop_list);
+
+  o6a->spf_tree->root = v;
+  listnode_add (candidate_list, v);
+
+  ospf6_spf_candidate_enqueue (v);
+}
+
+static struct ospf6_vertex *
+ospf6_spf_get_closest_candidate (list candidate_list)
+{
+  listnode node;
+  struct ospf6_vertex *candidate, *closest;
+
+  closest = (struct ospf6_vertex *) NULL;
+  for (node = listhead (candidate_list); node; nextnode (node))
+    {
+      candidate = (struct ospf6_vertex *) getdata (node);
+
+      if (closest && candidate->distance > closest->distance)
+        continue;
+
+      /* always choose network vertices if those're the same cost */
+      if (closest && candidate->distance == closest->distance
+          && closest->vertex_id.id.s_addr != 0)
+        continue;
+
+      closest = candidate;
+    }
+
+  return closest;
+}
+
+static struct ospf6_vertex *
+ospf6_spf_get_same_candidate (struct ospf6_vertex *w, list candidate_list)
+{
+  listnode node;
+  struct ospf6_vertex *c, *same;
+
+  same = (struct ospf6_vertex *) NULL;
+  for (node = listhead (candidate_list); node; nextnode (node))
+    {
+      c = (struct ospf6_vertex *) getdata (node);
+      if (w->vertex_id.adv_router.s_addr != c->vertex_id.adv_router.s_addr)
+        continue;
+      if (w->vertex_id.id.s_addr != c->vertex_id.id.s_addr)
+        continue;
+
+      if (same)
+        zlog_warn ("SPF: duplicate candidates in candidate_list");
+
+      same = c;
+    }
+
+  return same;
+}
+
+static void
+ospf6_spf_install (struct ospf6_vertex *vertex, struct ospf6_area *o6a)
+{
+  listnode node;
+  struct ospf6_vertex *parent;
+  struct ospf6_nexthop *nexthop;
+  struct ospf6_route_req request;
+  struct linklist_node lnode;
+
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_network_lsa *network_lsa;
+
+  router_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header);
+  network_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header);
+
+  if (IS_OSPF6_DUMP_SPF)
+    {
+      zlog_info ("SPF: Install: %s", vertex->string);
+    }
+
+  listnode_add (o6a->spf_tree->list, vertex);
+
+  for (node = listhead (vertex->parent_list); node; nextnode (node))
+    {
+      parent = (struct ospf6_vertex *) getdata (node);
+      listnode_add (parent->path_list, vertex);
+      vertex->depth = parent->depth + 1;
+    }
+
+#if 0
+  if (vertex == o6a->spf_tree->root)
+    return;
+#endif /*0*/
+
+  /* install route to topology table */
+  memset (&request, 0, sizeof (request));
+  if (vertex->vertex_id.id.s_addr) /* xxx */
+    request.route.type = OSPF6_DEST_TYPE_NETWORK;
+  else
+    request.route.type = OSPF6_DEST_TYPE_ROUTER;
+  memcpy (&request.route.prefix, &vertex->vertex_id,
+          sizeof (struct prefix));
+
+  request.path.area_id = o6a->area_id;
+  request.path.type = OSPF6_PATH_TYPE_INTRA;
+  request.path.cost = vertex->distance;
+  request.path.cost_e2 = 0;
+  request.path.origin.type = vertex->lsa->header->type;
+  request.path.origin.id = vertex->lsa->header->id;
+  request.path.origin.adv_router = vertex->lsa->header->adv_router;
+  if (vertex->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER))
+    request.path.router_bits = router_lsa->bits;
+  memcpy (&request.path.capability, vertex->opt_capability,
+          sizeof (request.path.capability));
+
+#if 0
+  if (IS_OSPF6_DUMP_SPF)
+    zlog_info ("SPF:   install %d nexthops for %s",
+               listcount (vertex->nexthop_list), vertex->string);
+#endif
+
+  for (linklist_head (vertex->nexthop_list, &lnode); ! linklist_end (&lnode);
+       linklist_next (&lnode))
+    {
+      nexthop = lnode.data;
+
+      request.nexthop.ifindex = nexthop->ifindex;
+      memcpy (&request.nexthop.address, &nexthop->address,
+              sizeof (request.nexthop.address));
+
+      ospf6_route_add (&request, o6a->table_topology);
+    }
+}
+
+struct ospf6_vertex *
+ospf6_spf_lookup (struct ospf6_vertex *w, struct ospf6_area *o6a)
+{
+  listnode node;
+  struct ospf6_vertex *v;
+
+  for (node = listhead (o6a->spf_tree->list); node; nextnode (node))
+    {
+      v = (struct ospf6_vertex *) getdata (node);
+
+      if (w->vertex_id.adv_router.s_addr != v->vertex_id.adv_router.s_addr)
+        continue;
+      if (w->vertex_id.id.s_addr != v->vertex_id.id.s_addr)
+        continue;
+
+      return v;
+    }
+
+  return (struct ospf6_vertex *) NULL;
+}
+
+u_int32_t stat_node = 0;
+u_int32_t stat_candidate = 0;
+u_int32_t stat_candidate_max = 0;
+u_int32_t stat_spf = 0;
+
+
+/* RFC2328 section 16.1 , RFC2740 section 3.8.1 */
+static int
+ospf6_spf_calculation (struct ospf6_area *o6a)
+{
+  list candidate_list;
+  struct ospf6_vertex *V, *W, *X;
+  int ldnum, i;
+
+  if (! o6a || ! o6a->spf_tree)
+    {
+      zlog_err ("SPF: Can't calculate SPF tree: malformed area");
+      return -1;
+    }
+
+  stat_spf ++;
+  stat_node = 0;
+  stat_candidate = 0;
+  stat_candidate_max = 0;
+
+  if (IS_OSPF6_DUMP_SPF)
+    zlog_info ("SPF: Calculation for area %s", o6a->str);
+
+  ospf6_route_table_freeze (o6a->table_topology);
+  ospf6_route_remove_all (o6a->table_topology);
+
+  /* (1): Initialize the algorithm's data structures */
+  candidate_list = list_new ();
+  ospf6_spf_initialize (candidate_list, o6a);
+  stat_candidate ++;
+
+  /* (3): Install closest from candidate list; if empty, break */
+  while (listcount (candidate_list))
+    {
+      V = ospf6_spf_get_closest_candidate (candidate_list);
+      listnode_delete (candidate_list, V);
+
+      {
+        struct ospf6_vertex *V_;
+
+        if (stat_candidate_max < ospf6_spf_candidate_count ())
+          stat_candidate_max = ospf6_spf_candidate_count ();
+
+        V_ = ospf6_spf_candidate_dequeue ();
+
+#if 0
+        if (IS_OSPF6_DUMP_SPF)
+          {
+            zlog_info ("Candidate list count: %lu",
+                       (u_long)ospf6_spf_candidate_count ());
+            zlog_info ("*** Candidate %s: %p <-> %p",
+                       (V == V_ ? "same" : "*** differ ***"), V, V_);
+            zlog_info ("  %p: %s", V, V->string);
+            zlog_info ("  %p: %s", V_, V_->string);
+          }
+#endif
+
+      }
+
+      stat_node++;
+      ospf6_spf_install (V, o6a);
+
+      /* (2): Examin LSA of just added vertex */
+      ldnum = ospf6_spf_lsd_num (V, o6a);
+      for (i = 0; i < ldnum; i++)
+        {
+          /* (b): If no LSA, or MaxAge, or LinkBack fail, examin next */
+          W = ospf6_spf_vertex_create (i, V, o6a);
+          if (! W)
+            continue;
+
+          stat_candidate ++;
+
+          /* (c) */
+          if (ospf6_spf_lookup (W, o6a))
+            {
+              if (IS_OSPF6_DUMP_SPF)
+                zlog_info ("SPF:   %s: Already in SPF tree", W->string);
+              ospf6_spf_vertex_delete (W);
+              continue;
+            }
+
+          /* (d) */
+          X = ospf6_spf_get_same_candidate (W, candidate_list);
+          if (X && X->distance < W->distance)
+            {
+              if (IS_OSPF6_DUMP_SPF)
+                zlog_info ("SPF:   %s: More closer found", W->string);
+              ospf6_spf_vertex_delete (W);
+              continue;
+            }
+          if (X && X->distance == W->distance)
+            {
+              if (IS_OSPF6_DUMP_SPF)
+                zlog_info ("SPF:   %s: new ECMP candidate", W->string);
+              ospf6_spf_vertex_merge (W, X);
+              ospf6_spf_vertex_delete (W);
+              continue;
+            }
+
+          if (X)
+            {
+              if (IS_OSPF6_DUMP_SPF)
+                zlog_info ("SPF:   %s: Swap with old candidate", W->string);
+              listnode_delete (candidate_list, X);
+              ospf6_spf_candidate_remove (X);
+              ospf6_spf_vertex_delete (X);
+            }
+          else
+            {
+              if (IS_OSPF6_DUMP_SPF)
+                zlog_info ("SPF:   %s: New Candidate", W->string);
+            }
+
+          if (stat_candidate_max < ospf6_spf_candidate_count ())
+            stat_candidate_max = ospf6_spf_candidate_count ();
+
+          listnode_add (candidate_list, W);
+          ospf6_spf_candidate_enqueue (W);
+        }
+    }
+
+  assert (listcount (candidate_list) == 0);
+  list_free (candidate_list);
+  assert (ospf6_spf_candidate_count () == 0);
+
+  /* Clear thread timer */
+  o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
+
+  if (IS_OSPF6_DUMP_SPF)
+    {
+      zlog_info ("SPF: Calculation for area %s done", o6a->str);
+      zlog_info ("SPF:   Statistics: %luth", (u_long)stat_spf);
+      zlog_info ("SPF:   Node Number: %lu", (u_long)stat_node);
+      zlog_info ("SPF:   Candidate Number: %lu Max: %lu",
+                 (u_long) stat_candidate, (u_long) stat_candidate_max);
+    }
+
+  ospf6_route_table_thaw (o6a->table_topology);
+  return 0;
+}
+
+int
+ospf6_spf_calculation_thread (struct thread *t)
+{
+  struct ospf6_area *o6a;
+  struct timeval start, end, runtime, interval;
+
+  o6a = (struct ospf6_area *) THREAD_ARG (t);
+  if (! o6a)
+    {
+      zlog_err ("SPF: Thread error");
+      return -1;
+    }
+
+  if (! o6a->spf_tree)
+    {
+      zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
+      return -1;
+    }
+
+  /* execute SPF calculation */
+  gettimeofday (&start, (struct timezone *) NULL);
+  ospf6_spf_calculation (o6a);
+  gettimeofday (&end, (struct timezone *) NULL);
+
+  /* update statistics */
+  o6a->spf_tree->timerun ++;
+  ospf6_timeval_sub (&end, &start, &runtime);
+  ospf6_timeval_add_equal (&runtime, &o6a->spf_tree->runtime_total);
+
+  if (o6a->spf_tree->timerun == 1)
+    {
+      o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec;
+      o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec;
+      o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec;
+      o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec;
+    }
+  if (ospf6_timeval_cmp (o6a->spf_tree->runtime_min, runtime) > 0)
+    {
+      o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec;
+      o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec;
+    }
+  if (ospf6_timeval_cmp (runtime, o6a->spf_tree->runtime_max) > 0)
+    {
+      o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec;
+      o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec;
+    }
+
+  if (o6a->spf_tree->timerun == 1)
+    {
+      ospf6_timeval_sub (&start, &ospf6->starttime, &interval);
+      ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total);
+      o6a->spf_tree->interval_min.tv_sec = interval.tv_sec;
+      o6a->spf_tree->interval_min.tv_usec = interval.tv_usec;
+      o6a->spf_tree->interval_max.tv_sec = interval.tv_sec;
+      o6a->spf_tree->interval_max.tv_usec = interval.tv_usec;
+    }
+  else
+    {
+      ospf6_timeval_sub (&start, &o6a->spf_tree->updated_time, &interval);
+      ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total);
+      if (ospf6_timeval_cmp (o6a->spf_tree->interval_min, interval) > 0)
+        {
+          o6a->spf_tree->interval_min.tv_sec = interval.tv_sec;
+          o6a->spf_tree->interval_min.tv_usec = interval.tv_usec;
+        }
+      if (ospf6_timeval_cmp (interval, o6a->spf_tree->interval_max) > 0)
+        {
+          o6a->spf_tree->interval_max.tv_sec = interval.tv_sec;
+          o6a->spf_tree->interval_max.tv_usec = interval.tv_usec;
+        }
+    }
+  o6a->spf_tree->updated_time.tv_sec = end.tv_sec;
+  o6a->spf_tree->updated_time.tv_usec = end.tv_usec;
+
+  /* clear thread */
+  o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
+
+  return 0;
+}
+
+void
+ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+  struct ospf6_area *o6a = NULL;
+  struct ospf6_interface *o6i = NULL;
+
+  if (new->header->type == htons (OSPF6_LSA_TYPE_ROUTER) ||
+      new->header->type == htons (OSPF6_LSA_TYPE_NETWORK))
+    o6a = new->scope;
+  else if (new->header->type == htons (OSPF6_LSA_TYPE_LINK))
+    {
+      o6i = new->scope;
+      o6a = o6i->area;
+    }
+
+  if (o6a)
+    ospf6_spf_calculation_schedule (o6a->area_id);
+}
+
+void
+ospf6_spf_calculation_schedule (u_int32_t area_id)
+{
+  struct ospf6_area *o6a;
+  char buf[64];
+
+  o6a = ospf6_area_lookup (area_id, ospf6);
+  if (! o6a)
+    {
+      inet_ntop (AF_INET, &area_id, buf, sizeof (buf));
+      zlog_err ("SPF: Can't find area: %s", buf);
+      return;
+    }
+
+  if (! o6a->spf_tree)
+    {
+      zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
+      return;
+    }
+
+  if (o6a->spf_tree->t_spf_calculation)
+    return;
+
+  o6a->spf_tree->t_spf_calculation =
+    thread_add_event (master, ospf6_spf_calculation_thread, o6a, 0);
+}
+
+struct ospf6_spftree *
+ospf6_spftree_create ()
+{
+  struct ospf6_spftree *spf_tree;
+  spf_tree = (struct ospf6_spftree *) XMALLOC (MTYPE_OSPF6_SPFTREE,
+                                               sizeof (struct ospf6_spftree));
+  if (! spf_tree)
+    {
+      zlog_err ("SPF: Can't allocate memory for SPF tree");
+      return (struct ospf6_spftree *) NULL;
+    }
+  memset (spf_tree, 0, sizeof (spf_tree));
+
+  spf_tree->list = list_new ();
+
+  return spf_tree;
+}
+
+void
+ospf6_spftree_delete (struct ospf6_spftree *spf_tree)
+{
+  listnode node;
+  struct ospf6_vertex *v;
+
+  /* Delete spf tree */
+  for (node = listhead (spf_tree->list); node; nextnode (node))
+    {
+      v = (struct ospf6_vertex *) getdata (node);
+      ospf6_spf_vertex_delete (v);
+    }
+  list_delete_all_node (spf_tree->list);
+
+  XFREE (MTYPE_OSPF6_SPFTREE, spf_tree);
+}
+
+void
+ospf6_nexthop_show (struct vty *vty, struct ospf6_nexthop *nexthop)
+{
+  char buf[128], *ifname;
+  struct ospf6_interface *o6i;
+
+  ifname = NULL;
+
+  o6i = ospf6_interface_lookup_by_index (nexthop->ifindex);
+  if (! o6i)
+    {
+      zlog_err ("Spf: invalid ifindex %d in nexthop", nexthop->ifindex);
+    }
+  else
+    ifname = o6i->interface->name;
+
+  inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
+  vty_out (vty, "    %s%%%s(%d)%s", buf, ifname,
+           nexthop->ifindex, VTY_NEWLINE);
+}
+
+void
+ospf6_vertex_show (struct vty *vty, struct ospf6_vertex *vertex)
+{
+  listnode node;
+  struct ospf6_vertex *v;
+  struct linklist_node lnode;
+
+  vty_out (vty, "SPF node %s%s", vertex->string, VTY_NEWLINE);
+  vty_out (vty, "  cost to this node: %d%s", vertex->distance, VTY_NEWLINE);
+  vty_out (vty, "  hops to this node: %d%s", vertex->depth, VTY_NEWLINE);
+
+  vty_out (vty, "  nexthops reachable to this node:%s", VTY_NEWLINE);
+  for (linklist_head (vertex->nexthop_list, &lnode);
+       ! linklist_end (&lnode);
+       linklist_next (&lnode))
+    ospf6_nexthop_show (vty, (struct ospf6_nexthop *) lnode.data);
+
+  vty_out (vty, "  parent nodes to this node:%s", VTY_NEWLINE);
+  if (! list_isempty (vertex->parent_list))
+    vty_out (vty, "    ");
+  for (node = listhead (vertex->parent_list); node; nextnode (node))
+    {
+      v = (struct ospf6_vertex *) getdata (node);
+      vty_out (vty, "%s ", v->string);
+    }
+  if (! list_isempty (vertex->parent_list))
+    vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "  child nodes to this node:%s", VTY_NEWLINE);
+  if (! list_isempty (vertex->path_list))
+    vty_out (vty, "    ");
+  for (node = listhead (vertex->path_list); node; nextnode (node))
+    {
+      v = (struct ospf6_vertex *) getdata (node);
+      vty_out (vty, "%s ", v->string);
+    }
+  if (! list_isempty (vertex->path_list))
+    vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree)
+{
+  listnode node;
+  struct ospf6_vertex *vertex;
+  u_int router_count, network_count, maxdepth;
+  struct timeval runtime_avg, interval_avg, last_updated, now;
+  char rmin[64], rmax[64], ravg[64];
+  char imin[64], imax[64], iavg[64];
+  char last_updated_string[64];
+
+  maxdepth = router_count = network_count = 0;
+  for (node = listhead (spf_tree->list); node; nextnode (node))
+    {
+      vertex = (struct ospf6_vertex *) getdata (node);
+      if (vertex->vertex_id.id.s_addr)
+        network_count++;
+      else
+        router_count++;
+      if (maxdepth < vertex->depth)
+        maxdepth = vertex->depth;
+    }
+
+  ospf6_timeval_div (&spf_tree->runtime_total, spf_tree->timerun,
+                     &runtime_avg);
+  ospf6_timeval_string (&spf_tree->runtime_min, rmin, sizeof (rmin));
+  ospf6_timeval_string (&spf_tree->runtime_max, rmax, sizeof (rmax));
+  ospf6_timeval_string (&runtime_avg, ravg, sizeof (ravg));
+
+  ospf6_timeval_div (&spf_tree->interval_total, spf_tree->timerun,
+                     &interval_avg);
+  ospf6_timeval_string (&spf_tree->interval_min, imin, sizeof (imin));
+  ospf6_timeval_string (&spf_tree->interval_max, imax, sizeof (imax));
+  ospf6_timeval_string (&interval_avg, iavg, sizeof (iavg));
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  ospf6_timeval_sub (&now, &spf_tree->updated_time, &last_updated);
+  ospf6_timeval_string (&last_updated, last_updated_string,
+                        sizeof (last_updated_string));
+
+  vty_out (vty, "     SPF algorithm executed %d times%s", 
+           spf_tree->timerun, VTY_NEWLINE);
+  vty_out (vty, "     Average time to run SPF: %s%s",
+           ravg, VTY_NEWLINE);
+  vty_out (vty, "     Maximum time to run SPF: %s%s",
+           rmax, VTY_NEWLINE);
+  vty_out (vty, "     Average interval of SPF: %s%s",
+           iavg, VTY_NEWLINE);
+  vty_out (vty, "     SPF last updated: %s ago%s",
+           last_updated_string, VTY_NEWLINE);
+  vty_out (vty, "     Current SPF node count: %d%s",
+           listcount (spf_tree->list), VTY_NEWLINE);
+  vty_out (vty, "       Router: %d Network: %d%s",
+           router_count, network_count, VTY_NEWLINE);
+  vty_out (vty, "       Maximum of Hop count to nodes: %d%s",
+           maxdepth, VTY_NEWLINE);
+}
+
+DEFUN (show_ipv6_ospf6_area_spf_node,
+       show_ipv6_ospf6_area_spf_node_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf node",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "vertex infomation\n"
+       )
+{
+  listnode i;
+  u_int32_t area_id;
+  struct ospf6_area *o6a;
+  struct ospf6_vertex *vertex;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  inet_pton (AF_INET, argv[0], &area_id);
+  o6a = ospf6_area_lookup (area_id, ospf6);
+  if (! o6a)
+    return CMD_SUCCESS;
+
+  for (i = listhead (o6a->spf_tree->list); i; nextnode (i))
+    {
+      vertex = (struct ospf6_vertex *) getdata (i);
+      ospf6_vertex_show (vty, vertex);
+    }
+
+  return CMD_SUCCESS;
+}
+
+static void
+ospf6_spftree_show (struct vty *vty, char *prefix, int current_rest,
+                    struct ospf6_vertex *v)
+{
+  char *p;
+  int psize;
+  int restnum;
+  listnode node;
+
+  vty_out (vty, "%s+-%s%s", prefix, v->string, VTY_NEWLINE);
+
+  if (listcount (v->path_list) == 0)
+    return;
+
+  psize = strlen (prefix) + 3;
+  p = malloc (psize);
+  if (!p)
+    {
+      vty_out (vty, "depth too long ...%s", VTY_NEWLINE);
+      return;
+    }
+
+  restnum = listcount (v->path_list);
+  for (node = listhead (v->path_list); node; nextnode (node))
+    {
+      --restnum;
+      snprintf (p, psize, "%s%s", prefix, (current_rest ? "| " : "  "));
+      ospf6_spftree_show (vty, p, restnum,
+                          (struct ospf6_vertex *) getdata (node));
+    }
+
+  free (p);
+}
+
+DEFUN (show_ipv6_ospf6_area_spf_tree,
+       show_ipv6_ospf6_area_spf_tree_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf tree",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "Displays spf tree\n")
+{
+  u_int32_t area_id;
+  struct ospf6_area *o6a;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  inet_pton (AF_INET, argv[0], &area_id);
+  o6a = ospf6_area_lookup (area_id, ospf6);
+  if (! o6a)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "%s        SPF tree for Area %s%s%s",
+           VTY_NEWLINE, o6a->str, VTY_NEWLINE, VTY_NEWLINE);
+
+  if (! o6a->spf_tree->root)
+    return CMD_SUCCESS;
+
+  ospf6_spftree_show (vty, "", 0, o6a->spf_tree->root);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_area_topology,
+       show_ipv6_ospf6_area_topology_cmd,
+       "show ipv6 ospf6 area A.B.C.D topology",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       OSPF6_SPF_STR
+       "Displays SPF topology table\n")
+{
+  struct ospf6_area *o6a;
+  u_int32_t area_id;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  inet_pton (AF_INET, argv[0], &area_id);
+  o6a = ospf6_area_lookup (area_id, ospf6);
+
+  if (! o6a)
+    return CMD_SUCCESS;
+
+  argc -= 1;
+  argv += 1;
+
+  return ospf6_route_table_show (vty, argc, argv, o6a->table_topology);
+}
+
+ALIAS (show_ipv6_ospf6_area_topology,
+       show_ipv6_ospf6_area_topology_router_cmd,
+       "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       OSPF6_SPF_STR
+       "Displays SPF topology table\n"
+       OSPF6_ROUTER_ID_STR
+       OSPF6_ROUTER_ID_STR
+       )
+
+ALIAS (show_ipv6_ospf6_area_topology,
+       show_ipv6_ospf6_area_topology_router_lsid_cmd,
+       "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       OSPF6_SPF_STR
+       "Displays SPF topology table\n"
+       OSPF6_ROUTER_ID_STR
+       OSPF6_ROUTER_ID_STR
+       OSPF6_LS_ID_STR
+       OSPF6_LS_ID_STR
+       )
+
+void
+ospf6_spf_init ()
+{
+  nexthop_list = linklist_create ();
+  ospf6_spf_candidate_init ();
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_node_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_node_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd);
+}
+
diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h
new file mode 100644 (file)
index 0000000..de50e94
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_SPF_H
+#define OSPF6_SPF_H
+
+#include "prefix.h"
+
+/* Transit Vertex */
+struct ospf6_vertex
+{
+  /* type of this vertex */
+  u_int8_t type;
+
+  /* Vertex Identifier */
+  struct prefix_ls vertex_id;
+
+  /* Identifier String */
+  char string[128];
+
+  /* Associated LSA */
+  struct ospf6_lsa *lsa;
+
+  /* Distance from Root (Cost) */
+  u_int16_t distance;
+
+  /* Depth of this node */
+  u_char depth;
+
+  /* nexthops to this node */
+  struct linklist *nexthop_list;
+
+  /* upper nodes in spf tree */
+  list parent_list;
+
+  /* lower nodes in spf tree */
+  list path_list;
+
+  /* capability bits */
+  u_char capability_bits;
+
+  /* Optional capabilities */
+  u_char opt_capability[3];
+};
+
+#define OSPF6_VERTEX_TYPE_ROUTER  0x01
+#define OSPF6_VERTEX_TYPE_NETWORK 0x02
+
+struct ospf6_spftree
+{
+  /* calculation thread */
+  struct thread *t_spf_calculation;
+
+  /* root of this tree */
+  struct ospf6_vertex *root;
+
+  /* list for search */
+  list list;
+
+  /* statistics */
+  u_int32_t timerun;
+
+  struct timeval runtime_total;
+  struct timeval runtime_min;
+  struct timeval runtime_max;
+
+  struct timeval updated_time;
+  struct timeval interval_total;
+  struct timeval interval_min;
+  struct timeval interval_max;
+};
+
+int ospf6_spf_calculate_route (void *);
+
+void
+ospf6_spf_calculation_schedule (u_int32_t area_id);
+struct ospf6_spftree *ospf6_spftree_create ();
+void
+ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree);
+void ospf6_spftree_delete (struct ospf6_spftree *spf_tree);
+
+void ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new);
+
+void ospf6_spf_init ();
+
+#endif /* OSPF6_SPF_H */
+
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
new file mode 100644 (file)
index 0000000..a8a058f
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * OSPFv3 Top Level Data Structure
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "vty.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "command.h"
+
+#include "ospf6_hook.h"
+#include "ospf6_proto.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_interface.h"
+#include "ospf6_area.h"
+#include "ospf6_top.h"
+
+#include "ospf6_route.h"
+#include "ospf6_zebra.h"
+
+#include "ospf6_nsm.h"
+#include "ospf6_asbr.h"
+#include "ospf6_abr.h"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* global ospf6d variable */
+struct ospf6 *ospf6;
+
+static void
+ospf6_top_foreach_area (struct ospf6 *o6, void *arg, int val,
+                        void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_area *o6a;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      (*func) (arg, val, o6a);
+    }
+}
+
+static void
+ospf6_top_foreach_interface (struct ospf6 *o6, void *arg, int val,
+                             void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_area *o6a;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      (*o6a->foreach_if) (o6a, arg, val, func);
+    }
+}
+
+static void
+ospf6_top_foreach_neighbor (struct ospf6 *o6, void *arg, int val,
+                            void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_area *o6a;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      (*o6a->foreach_nei) (o6a, arg, val, func);
+    }
+}
+
+static int
+ospf6_top_maxage_remover (struct thread *t)
+{
+  int count;
+  struct ospf6 *o6 = (struct ospf6 *) THREAD_ARG (t);
+
+  o6->maxage_remover = (struct thread *) NULL;
+
+  count = 0;
+  o6->foreach_nei (o6, &count, NBS_EXCHANGE, ospf6_count_state);
+  o6->foreach_nei (o6, &count, NBS_LOADING, ospf6_count_state);
+  if (count != 0)
+    return 0;
+
+  ospf6_lsdb_remove_maxage (o6->lsdb);
+  return 0;
+}
+
+void
+ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6)
+{
+  if (o6->maxage_remover != NULL)
+    return;
+
+  o6->maxage_remover =
+    thread_add_event (master, ospf6_top_maxage_remover, o6, 0);
+}
+
+void
+ospf6_show (struct vty *vty)
+{
+  listnode n;
+  struct ospf6_area *area;
+  char id_string[32];
+  unsigned long day, hour, min, sec;
+  struct timeval now, running;
+
+  /* process id, router id */
+  inet_ntop (AF_INET, &ospf6->router_id, id_string, sizeof (id_string));
+  vty_out (vty, " Routing Process (%lu) with ID %s%s",
+           ospf6->process_id, id_string, VTY_NEWLINE);
+
+  /* running time */
+  gettimeofday (&now, (struct timezone *)NULL);
+  ospf6_timeval_sub (&now, &ospf6->starttime, &running);
+  ospf6_timeval_decode (&running, &day, &hour, &min, &sec, NULL, NULL);
+  vty_out (vty, " Running %ld days %ld hours %ld minutes %ld seconds%s",
+           day, hour, min, sec, VTY_NEWLINE);
+
+  vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
+
+  /* Redistribute config */
+  ospf6_redistribute_show_config (vty);
+
+  /* LSAs */
+  vty_out (vty, " Number of AS scoped LSAs is %u%s",
+           ospf6->lsdb->count, VTY_NEWLINE);
+  vty_out (vty, " Route calculation executed %d times%s",
+           ospf6->stat_route_calculation_execed, VTY_NEWLINE);
+
+  /* Route Statistics */
+#if 0
+  ospf6_route_statistics_show (vty, ospf6->route_table);
+#endif
+
+  /* Areas */
+  vty_out (vty, " Number of areas in this router is %u%s",
+           listcount (ospf6->area_list), VTY_NEWLINE);
+  for (n = listhead (ospf6->area_list); n; nextnode (n))
+    {
+      area = (struct ospf6_area *) getdata (n);
+      ospf6_area_show (vty, area);
+    }
+}
+
+void
+ospf6_statistics_show (struct vty *vty, struct ospf6 *o6)
+{
+  listnode node;
+  struct ospf6_area *o6a;
+  char running_time[128];
+  struct timeval now, running;
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  ospf6_timeval_sub (&now, &o6->starttime, &running);
+  ospf6_timeval_string (&running, running_time, sizeof (running_time));
+
+  vty_out (vty, "Statistics of OSPF process %ld%s",
+           o6->process_id, VTY_NEWLINE);
+  vty_out (vty, "  Running: %s%s", running_time, VTY_NEWLINE);
+
+#if 0
+  ospf6_route_statistics_show (vty, o6->route_table);
+#endif
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      ospf6_area_statistics_show (vty, o6a);
+    }
+}
+
+static struct ospf6 *
+ospf6_new ()
+{
+  struct ospf6 *new;
+  new = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
+  if (new)
+    memset (new, 0, sizeof (struct ospf6));
+  return new;
+}
+
+void
+ospf6_free (struct ospf6 *ospf6)
+{
+  XFREE (MTYPE_OSPF6_TOP, ospf6);
+}
+
+void
+ospf6_top_topology_add (struct ospf6_route_req *request)
+{
+  assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
+  if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
+    ospf6_asbr_asbr_entry_add (request);
+}
+
+void
+ospf6_top_topology_remove (struct ospf6_route_req *request)
+{
+  assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
+  if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
+    ospf6_asbr_asbr_entry_remove (request);
+}
+
+struct ospf6 *
+ospf6_create (unsigned long process_id)
+{
+  struct ospf6 *o6;
+  char namebuf[64];
+
+  o6 = ospf6_new ();
+
+  /* initialize */
+  gettimeofday (&o6->starttime, (struct timezone *)NULL);
+  o6->process_id = process_id;
+  o6->version = OSPF6_VERSION;
+  o6->area_list = list_new ();
+
+  o6->lsdb = ospf6_lsdb_create ();
+
+  o6->foreach_area = ospf6_top_foreach_area;
+  o6->foreach_if = ospf6_top_foreach_interface;
+  o6->foreach_nei = ospf6_top_foreach_neighbor;
+
+  snprintf (namebuf, sizeof (namebuf), "InterTopology table");
+  o6->topology_table = ospf6_route_table_create (namebuf);
+  ospf6_route_hook_register (ospf6_top_topology_add,
+                             ospf6_top_topology_add,
+                             ospf6_top_topology_remove,
+                             o6->topology_table);
+
+#if 0
+  snprintf (namebuf, sizeof (namebuf), "External table");
+  o6->external_table = ospf6_route_table_create (namebuf);
+  ospf6_route_hook_register (ospf6_asbr_external_route_add,
+                             ospf6_asbr_external_route_add,
+                             ospf6_asbr_external_route_remove,
+                             o6->external_table);
+#endif /*0*/
+
+  snprintf (namebuf, sizeof (namebuf), "Top route table");
+  o6->route_table = ospf6_route_table_create (namebuf);
+  ospf6_route_hook_register (ospf6_zebra_route_update_add,
+                             ospf6_zebra_route_update_add,
+                             ospf6_zebra_route_update_remove,
+                             o6->route_table);
+  ospf6_route_hook_register (ospf6_abr_route_add,
+                             ospf6_abr_route_add,
+                             ospf6_abr_route_remove,
+                             o6->route_table);
+
+  return o6;
+}
+
+void
+ospf6_delete (struct ospf6 *ospf6)
+{
+  ospf6_route_remove_all (ospf6->route_table);
+  ospf6_free (ospf6);
+}
+
+struct ospf6 *
+ospf6_start ()
+{
+  if (ospf6)
+    return ospf6;
+
+  ospf6 = ospf6_create (0);
+  return ospf6;
+}
+
+void
+ospf6_stop ()
+{
+  if (!ospf6)
+    return;
+
+  ospf6_delete (ospf6);
+  ospf6 = NULL;
+}
+
+int
+ospf6_is_asbr (struct ospf6 *o6)
+{
+  int i = 0;
+  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_SYSTEM);
+  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_CONNECT);
+  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_STATIC);
+  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_KERNEL);
+  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_RIPNG);
+  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_BGP);
+  return (i);
+}
+
+DEFUN (show_ipv6_ospf6_route,
+       show_ipv6_ospf6_route_cmd,
+       "show ipv6 ospf6 route",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Routing table\n"
+       )
+{
+  OSPF6_CMD_CHECK_RUNNING ();
+  return ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
+}
+
+ALIAS (show_ipv6_ospf6_route,
+       show_ipv6_ospf6_route_prefix_cmd,
+       "show ipv6 ospf6 route (X::X|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Routing table\n"
+       "match IPv6 prefix\n"
+       )
+
+DEFUN (show_ipv6_ospf6_topology,
+       show_ipv6_ospf6_topology_cmd,
+       "show ipv6 ospf6 topology",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Inter Area topology information\n"
+       )
+{
+  OSPF6_CMD_CHECK_RUNNING ();
+  return ospf6_route_table_show (vty, argc, argv, ospf6->topology_table);
+}
+
+ALIAS (show_ipv6_ospf6_topology,
+       show_ipv6_ospf6_topology_router_cmd,
+       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Inter Area topology information\n"
+       OSPF6_ROUTER_ID_STR
+       OSPF6_ROUTER_ID_STR
+       "Detailed information\n"
+       )
+
+ALIAS (show_ipv6_ospf6_topology,
+       show_ipv6_ospf6_topology_router_lsid_cmd,
+       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Inter Area topology information\n"
+       OSPF6_ROUTER_ID_STR
+       OSPF6_ROUTER_ID_STR
+       OSPF6_LS_ID_STR
+       OSPF6_LS_ID_STR
+       )
+
+void
+ospf6_top_init ()
+{
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+}
+
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
new file mode 100644 (file)
index 0000000..4c68756
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * OSPFv3 Top Level Data Structure
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_TOP_H
+#define OSPF6_TOP_H
+
+#include "routemap.h"
+
+/* ospfv3 top level data structure */
+struct ospf6
+{
+  /* process id */
+  u_long process_id;
+
+  /* start time */
+  struct timeval starttime;
+
+  /* ospf version must be 3 */
+  unsigned char version;
+
+  /* my router id */
+  u_int32_t router_id;
+
+  /* list of areas */
+  list area_list;
+
+  /* AS scope link state database */
+  struct ospf6_lsdb *lsdb;
+
+  /* redistribute route-map */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } rmap[ZEBRA_ROUTE_MAX];
+
+  struct thread *t_route_calculation;
+  u_int stat_route_calculation_execed;
+
+  struct ospf6_route_table *route_table;
+  struct ospf6_route_table *topology_table;
+  struct ospf6_route_table *external_table;
+
+  void (*foreach_area) (struct ospf6 *, void *arg, int val,
+                        void (*func) (void *, int, void *));
+  void (*foreach_if)   (struct ospf6 *, void *arg, int val,
+                        void (*func) (void *, int, void *));
+  void (*foreach_nei)  (struct ospf6 *, void *arg, int val,
+                        void (*func) (void *, int, void *));
+
+  struct thread *maxage_remover;
+
+  list nexthop_list;
+};
+extern struct ospf6 *ospf6;
+
+/* prototypes */
+int
+ospf6_top_count_neighbor_in_state (u_char state, struct ospf6 *o6);
+
+void
+ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6);
+
+void ospf6_show (struct vty *);
+void ospf6_statistics_show (struct vty *vty, struct ospf6 *o6);
+
+struct ospf6 *ospf6_start ();
+void ospf6_stop ();
+
+void ospf6_delete (struct ospf6 *);
+int ospf6_is_asbr (struct ospf6 *);
+
+void ospf6_top_init ();
+
+#endif /* OSPF6_TOP_H */
+
diff --git a/ospf6d/ospf6_types.h b/ospf6d/ospf6_types.h
new file mode 100644 (file)
index 0000000..574e2f3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_TYPES_H
+#define OSPF6_TYPES_H
+
+typedef unsigned char  msgtype_t;
+typedef unsigned char  instance_id_t;
+typedef unsigned char  state_t;
+typedef unsigned char  vers_t;
+typedef unsigned char  opt_t;
+typedef unsigned char  rtr_pri_t;
+typedef unsigned char  prefixlen_t;
+typedef unsigned char  ddbits_t;
+typedef unsigned long  ddseqnum_t;
+typedef unsigned long  rtr_id_t;
+typedef unsigned long  ifid_t;
+typedef unsigned long  cost_t;
+typedef unsigned long  rxmt_int_t;
+typedef unsigned short hello_int_t;
+typedef unsigned short rtr_dead_int_t;
+typedef unsigned long  area_id_t;
+
+#endif /* OSPF6_TYPES_H */
+
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
new file mode 100644 (file)
index 0000000..7b8a8dc
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_interface.h"
+#include "ospf6_asbr.h"
+
+#include "ospf6_linklist.h"
+
+/* information about zebra. */
+struct zclient *zclient = NULL;
+
+/* redistribute function */
+void
+ospf6_zebra_redistribute (int type)
+{
+  int top_change = 0;
+
+  if (zclient->redist[type])
+    return;
+
+  if (! ospf6_is_asbr (ospf6))
+    top_change = 1;
+
+  zclient->redist[type] = 1;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+
+  if (top_change)
+    CALL_CHANGE_HOOK (&top_hook, ospf6);
+}
+
+void
+ospf6_zebra_no_redistribute (int type)
+{
+  int top_change = 0;
+
+  if (!zclient->redist[type])
+    return;
+
+  if (ospf6_is_asbr (ospf6))
+    top_change = 1;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+
+  if (top_change)
+    CALL_CHANGE_HOOK (&top_hook, ospf6);
+}
+
+int
+ospf6_zebra_is_redistribute (int type)
+{
+  return zclient->redist[type];
+}
+
+
+/* Inteface addition message from zebra. */
+int
+ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F add: %s index %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->mtu);
+
+  ospf6_interface_if_add (ifp);
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
+{
+#if 0
+  struct interface *ifp = NULL;
+
+  ifp = zebra_interface_delete_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->mtu);
+
+  ospf6_interface_if_del (ifp);
+#endif
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_state_update (int command, struct zclient *zclient,
+                             zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_state_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s state change: index %d flags %ld metric %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  ospf6_interface_state_update (ifp);
+  return 0;
+}
+
+int
+ospf6_zebra_if_address_update_add (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *c;
+  char buf[128];
+
+  c = zebra_interface_address_add_read (zclient->ibuf);
+  if (c == NULL)
+    return 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s address add: %5s %s/%d",
+               c->ifp->name, prefix_family_str (c->address),
+               inet_ntop (c->address->family, &c->address->u.prefix,
+                          buf, sizeof (buf)), c->address->prefixlen);
+
+  if (c->address->family == AF_INET6)
+    ospf6_interface_address_update (c->ifp);
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *c;
+  char buf[128];
+
+  c = zebra_interface_address_delete_read (zclient->ibuf);
+  if (c == NULL)
+    return 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s address del: %5s %s/%d",
+               c->ifp->name, prefix_family_str (c->address),
+               inet_ntop (c->address->family, &c->address->u.prefix,
+                          buf, sizeof (buf)), c->address->prefixlen);
+
+  if (c->address->family == AF_INET6)
+    ospf6_interface_address_update (c->ifp);
+
+  return 0;
+}
+
+
+\f
+const char *zebra_route_name[ZEBRA_ROUTE_MAX] =
+{
+  "System",
+  "Kernel",
+  "Connect",
+  "Static",
+  "RIP",
+  "RIPng",
+  "OSPF",
+  "OSPF6",
+  "BGP",
+};
+
+const char *zebra_route_abname[ZEBRA_ROUTE_MAX] =
+  { "X", "K", "C", "S", "r", "R", "o", "O", "B" };
+
+int
+ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
+                       zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv6 api;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  struct in6_addr *nexthop;
+  char prefixstr[128], nexthopstr[128];
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop = NULL;
+  memset (&api, 0, sizeof (api));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv6 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop = (struct in6_addr *)
+        malloc (api.nexthop_num * sizeof (struct in6_addr));
+      stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr));
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    {
+      prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr));
+      inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr));
+
+      if (command == ZEBRA_IPV6_ROUTE_ADD)
+       zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld",
+                  zebra_route_name [api.type], prefixstr,
+                  nexthopstr, ifindex);
+      else
+       zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld",
+                  zebra_route_name [api.type], prefixstr,
+                  nexthopstr, ifindex);
+    }
+  if (command == ZEBRA_IPV6_ROUTE_ADD)
+    ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p,
+                          api.nexthop_num, nexthop);
+  else
+    ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    free (nexthop);
+
+  return 0;
+}
+
+\f
+DEFUN (show_zebra,
+       show_zebra_cmd,
+       "show zebra",
+       SHOW_STR
+       "Zebra information\n")
+{
+  int i;
+  if (!zclient)
+    vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE);
+
+  vty_out (vty, "Zebra Infomation%s", VTY_NEWLINE);
+  vty_out (vty, "  enable: %d%s", zclient->enable, VTY_NEWLINE);
+  vty_out (vty, "  fail: %d%s", zclient->fail, VTY_NEWLINE);
+  vty_out (vty, "  redistribute default: %d%s", zclient->redist_default,
+           VTY_NEWLINE);
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    vty_out (vty, "    RouteType: %s - %s%s", zebra_route_name[i],
+             zclient->redist[i] ? "redistributed" : "not redistributed",
+             VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (router_zebra,
+       router_zebra_cmd,
+       "router zebra",
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: router zebra");
+
+  vty->node = ZEBRA_NODE;
+  zclient->enable = 1;
+  zclient_start (zclient);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+       no_router_zebra_cmd,
+       "no router zebra",
+       NO_STR
+       "Configure routing process\n"
+       "Disable connection to zebra daemon\n")
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("no router zebra");
+
+  zclient->enable = 0;
+  zclient_stop (zclient);
+  return CMD_SUCCESS;
+}
+
+/* Zebra configuration write function. */
+int
+ospf6_zebra_config_write (struct vty *vty)
+{
+  if (! zclient->enable)
+    {
+      vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+      return 1;
+    }
+  else if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
+    {
+      vty_out (vty, "router zebra%s", VTY_NEWLINE);
+      vty_out (vty, " no redistribute ospf6%s", VTY_NEWLINE);
+      return 1;
+    }
+  return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-zebra)# ",
+};
+
+#define ADD    0
+#define CHANGE 1
+#define REMOVE 2
+
+static void
+ospf6_zebra_route_update (int type, struct ospf6_route_req *request)
+{
+  char buf[96], ifname[IFNAMSIZ];
+
+  struct zapi_ipv6 api;
+  struct ospf6_route_req route;
+  struct linklist *nexthop_list;
+  struct linklist_node node;
+  struct ospf6_nexthop *nexthop = NULL;
+  struct in6_addr **nexthops;
+  unsigned int *ifindexes;
+  struct prefix_ipv6 *p;
+  int i, ret = 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    {
+      prefix2str (&request->route.prefix, buf, sizeof (buf));
+      if (type == REMOVE)
+        zlog_info ("ZEBRA: Send remove route: %s", buf);
+      else
+        zlog_info ("ZEBRA: Send add route: %s", buf);
+    }
+
+  if (zclient->sock < 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   failed: not connected to zebra");
+      return;
+    }
+
+  if (request->path.origin.adv_router == ospf6->router_id &&
+      (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
+       request->path.type == OSPF6_PATH_TYPE_EXTERNAL2))
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   self originated external route, ignore");
+      return;
+    }
+
+  /* Only the best path (i.e. the first path of the path-list
+     in 'struct ospf6_route') will be sent to zebra. */
+  ospf6_route_lookup (&route, &request->route.prefix, request->table);
+  if (memcmp (&route.path, &request->path, sizeof (route.path)))
+    {
+      /* this is not preferred best route, ignore */
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   not best path, ignore");
+      return;
+    }
+
+  nexthop_list = linklist_create ();
+
+  /* for each nexthop */
+  for (ospf6_route_lookup (&route, &request->route.prefix, request->table);
+       ! ospf6_route_end (&route); ospf6_route_next (&route))
+    {
+      if (memcmp (&route.path, &request->path, sizeof (route.path)))
+        break;
+
+      #define IN6_IS_ILLEGAL_NEXTHOP(a)\
+        ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffffffff) &&\
+        (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffffffff) &&\
+        (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffffffff) &&\
+        (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffffffff))
+      if (IN6_IS_ILLEGAL_NEXTHOP (&route.nexthop.address))
+        {
+          zlog_warn ("ZEBRA: Illegal nexthop");
+          continue;
+        }
+
+      if (type == REMOVE && ! memcmp (&route.nexthop, &request->nexthop,
+                                      sizeof (struct ospf6_nexthop)))
+        continue;
+
+      nexthop = XCALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_nexthop));
+      if (! nexthop)
+        {
+          zlog_warn ("ZEBRA: Can't update nexthop: malloc failed");
+          continue;
+        }
+
+      memcpy (nexthop, &route.nexthop, sizeof (struct ospf6_nexthop));
+      linklist_add (nexthop, nexthop_list);
+    }
+
+  if (type == REMOVE && nexthop_list->count != 0)
+    type = ADD;
+  else if (type == REMOVE && nexthop_list->count == 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   all nexthop with the selected path has gone");
+
+      if (! memcmp (&request->route, &route.route,
+                    sizeof (struct ospf6_route)))
+        {
+          /* send 'add' of alternative route */
+          struct ospf6_path seconde_path;
+
+          if (IS_OSPF6_DUMP_ZEBRA)
+            zlog_info ("ZEBRA:   found alternative path to add");
+
+          memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path));
+          type = ADD;
+
+          while (! memcmp (&seconde_path, &route.path,
+                           sizeof (struct ospf6_path)))
+            {
+              nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
+                                 sizeof (struct ospf6_nexthop));
+              if (! nexthop)
+                zlog_warn ("ZEBRA:   Can't update nexthop: malloc failed");
+              else
+                {
+                  memcpy (nexthop, &route.nexthop,
+                          sizeof (struct ospf6_nexthop));
+                  linklist_add (nexthop, nexthop_list);
+                }
+
+              ospf6_route_next (&route);
+            }
+        }
+      else
+        {
+          /* there is no alternative route. send 'remove' to zebra for
+             requested route */
+          if (IS_OSPF6_DUMP_ZEBRA)
+            zlog_info ("ZEBRA:   can't find alternative path, remove");
+
+          if (IS_OSPF6_DUMP_ZEBRA)
+            {
+              zlog_info ("ZEBRA:   Debug: walk over the route ?");
+              ospf6_route_log_request ("Debug route", "***", &route);
+              ospf6_route_log_request ("Debug request", "***", request);
+            }
+
+          nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
+                             sizeof (struct ospf6_nexthop));
+          if (! nexthop)
+            zlog_warn ("ZEBRA:   Can't update nexthop: malloc failed");
+          else
+            {
+              memcpy (nexthop, &request->nexthop,
+                      sizeof (struct ospf6_nexthop));
+              linklist_add (nexthop, nexthop_list);
+            }
+        }
+    }
+
+  if (nexthop_list->count == 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   no nexthop, ignore");
+      linklist_delete (nexthop_list);
+      return;
+    }
+
+  /* allocate memory for nexthop_list */
+  nexthops = XCALLOC (MTYPE_OSPF6_OTHER,
+                      nexthop_list->count * sizeof (struct in6_addr *));
+  if (! nexthops)
+    {
+      zlog_warn ("ZEBRA:   Can't update zebra route: malloc failed");
+      for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+           linklist_next (&node))
+        XFREE (MTYPE_OSPF6_OTHER, node.data);
+      linklist_delete (nexthop_list);
+      return;
+    }
+
+  /* allocate memory for ifindex_list */
+  ifindexes = XCALLOC (MTYPE_OSPF6_OTHER,
+                       nexthop_list->count * sizeof (unsigned int));
+  if (! ifindexes)
+    {
+      zlog_warn ("ZEBRA: Can't update zebra route: malloc failed");
+      for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+           linklist_next (&node))
+        XFREE (MTYPE_OSPF6_OTHER, node.data);
+      linklist_delete (nexthop_list);
+      XFREE (MTYPE_OSPF6_OTHER, nexthops);
+      return;
+    }
+
+  i = 0;
+  for (linklist_head (nexthop_list, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      nexthop = node.data;
+      if (IS_OSPF6_DUMP_ZEBRA)
+        {
+          inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
+          if_indextoname (nexthop->ifindex, ifname);
+          zlog_info ("ZEBRA:   nexthop: %s%%%s(%d)",
+                     buf, ifname, nexthop->ifindex);
+        }
+      nexthops[i] = &nexthop->address;
+      ifindexes[i] = nexthop->ifindex;
+      i++;
+    }
+
+  api.type = ZEBRA_ROUTE_OSPF6;
+  api.flags = 0;
+  api.message = 0;
+  SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+  SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+  api.nexthop_num = nexthop_list->count;
+  api.nexthop = nexthops;
+  api.ifindex_num = nexthop_list->count;
+  api.ifindex = ifindexes;
+
+  p = (struct prefix_ipv6 *) &request->route.prefix;
+  if (type == REMOVE && nexthop_list->count == 1)
+    ret = zapi_ipv6_delete (zclient, p, &api);
+  else
+    ret = zapi_ipv6_add (zclient, p, &api);
+
+  if (ret < 0)
+    zlog_err ("ZEBRA: zapi_ipv6_add () failed: %s", strerror (errno));
+
+  for (linklist_head (nexthop_list, &node); !linklist_end (&node);
+       linklist_next (&node))
+    XFREE (MTYPE_OSPF6_OTHER, node.data);
+  linklist_delete (nexthop_list);
+  XFREE (MTYPE_OSPF6_OTHER, nexthops);
+  XFREE (MTYPE_OSPF6_OTHER, ifindexes);
+
+  return;
+}
+
+void
+ospf6_zebra_route_update_add (struct ospf6_route_req *request)
+{
+  ospf6_zebra_route_update (ADD, request);
+}
+
+void
+ospf6_zebra_route_update_remove (struct ospf6_route_req *request)
+{
+  ospf6_zebra_route_update (REMOVE, request);
+}
+
+static void
+ospf6_zebra_redistribute_ospf6 ()
+{
+  struct route_node *node;
+
+  for (node = route_top (ospf6->route_table->table); node;
+       node = route_next (node))
+    {
+      if (! node || ! node->info)
+        continue;
+      ospf6_zebra_route_update_add (node->info);
+    }
+}
+
+static void
+ospf6_zebra_no_redistribute_ospf6 ()
+{
+  struct route_node *node;
+
+  if (! ospf6)
+    return;
+
+  for (node = route_top (ospf6->route_table->table); node;
+       node = route_next (node))
+    {
+      if (! node || ! node->info)
+        continue;
+
+      ospf6_zebra_route_update_remove (node->info);
+    }
+}
+
+
+DEFUN (redistribute_ospf6,
+       redistribute_ospf6_cmd,
+       "redistribute ospf6",
+       "Redistribute control\n"
+       "OSPF6 route\n")
+{
+  /* log */
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: redistribute ospf6");
+
+  zclient->redist[ZEBRA_ROUTE_OSPF6] = 1;
+
+  /* set zebra route table */
+  ospf6_zebra_redistribute_ospf6 ();
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_redistribute_ospf6,
+       no_redistribute_ospf6_cmd,
+       "no redistribute ospf6",
+       NO_STR
+       "Redistribute control\n"
+       "OSPF6 route\n")
+{
+  /* log */
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: no redistribute ospf6");
+
+  zclient->redist[ZEBRA_ROUTE_OSPF6] = 0;
+
+  if (! ospf6)
+    return CMD_SUCCESS;
+
+  /* clean up zebra route table */
+  ospf6_zebra_no_redistribute_ospf6 ();
+
+  ospf6_route_hook_unregister (ospf6_zebra_route_update_add,
+                               ospf6_zebra_route_update_add,
+                               ospf6_zebra_route_update_remove,
+                               ospf6->route_table);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_zebra_init ()
+{
+  /* Allocate zebra structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_OSPF6);
+  zclient->interface_add = ospf6_zebra_if_add;
+  zclient->interface_delete = ospf6_zebra_if_del;
+  zclient->interface_up = ospf6_zebra_if_state_update;
+  zclient->interface_down = ospf6_zebra_if_state_update;
+  zclient->interface_address_add = ospf6_zebra_if_address_update_add;
+  zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
+  zclient->ipv4_route_add = NULL;
+  zclient->ipv4_route_delete = NULL;
+  zclient->ipv6_route_add = ospf6_zebra_read_ipv6;
+  zclient->ipv6_route_delete = ospf6_zebra_read_ipv6;
+
+  /* redistribute connected route by default */
+  /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
+
+  /* Install zebra node. */
+  install_node (&zebra_node, ospf6_zebra_config_write);
+
+  /* Install command element for zebra node. */
+  install_element (VIEW_NODE, &show_zebra_cmd);
+  install_element (ENABLE_NODE, &show_zebra_cmd);
+  install_element (CONFIG_NODE, &router_zebra_cmd);
+  install_element (CONFIG_NODE, &no_router_zebra_cmd);
+  install_default (ZEBRA_NODE);
+  install_element (ZEBRA_NODE, &redistribute_ospf6_cmd);
+  install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd);
+
+#if 0
+  hook.name = "ZebraRouteUpdate";
+  hook.hook_add = ospf6_zebra_route_update_add;
+  hook.hook_change = ospf6_zebra_route_update_add;
+  hook.hook_remove = ospf6_zebra_route_update_remove;
+  ospf6_hook_register (&hook, &route_hook);
+#endif
+
+  return;
+}
+
+void
+ospf6_zebra_finish ()
+{
+  zclient_stop (zclient);
+  zclient_free (zclient);
+  zclient = (struct zclient *) NULL;
+}
+
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
new file mode 100644 (file)
index 0000000..d86b2db
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6_ZEBRA_H
+#define OSPF6_ZEBRA_H
+
+extern struct zclient *zclient;
+
+void ospf6_zebra_redistribute (int);
+void ospf6_zebra_no_redistribute (int);
+int ospf6_zebra_is_redistribute (int);
+
+int ospf6_zebra_get_interface (int, struct zclient *, zebra_size_t);
+int ospf6_zebra_read (struct thread *); 
+void ospf6_zebra_init ();
+void ospf6_zebra_finish ();
+void ospf6_zebra_start ();
+
+int ospf6_zebra_read_ipv6 (int, struct zclient *, zebra_size_t);
+
+extern const char *zebra_route_name[ZEBRA_ROUTE_MAX];
+extern const char *zebra_route_abname[ZEBRA_ROUTE_MAX];
+
+void ospf6_zebra_route_update_add (struct ospf6_route_req *request);
+void ospf6_zebra_route_update_remove (struct ospf6_route_req *request);
+
+#endif /*OSPF6_ZEBRA_H*/
+
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
new file mode 100644 (file)
index 0000000..dbe7a88
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include "ospf6d.h"
+
+#include "ospf6_damp.h"
+
+/* global ospf6d variable */
+int  ospf6_sock;
+list iflist;
+list nexthoplist = NULL;
+struct sockaddr_in6 allspfrouters6;
+struct sockaddr_in6 alldrouters6;
+char *recent_reason; /* set by ospf6_lsa_check_recent () */
+int proctitle_mode = 0;
+
+char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION;
+
+\f
+#define TIMER_SEC_MICRO 1000000
+
+void
+ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2,
+                   struct timeval *result)
+{
+  long usec, movedown = 0;
+
+  if (t1->tv_sec < t2->tv_sec ||
+      (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec))
+    {
+      result->tv_sec = 0;
+      result->tv_usec = 0;
+      return;
+    }
+
+  if (t1->tv_usec < t2->tv_usec)
+    {
+      usec = t1->tv_usec + TIMER_SEC_MICRO;
+      movedown++;
+    }
+  else
+    usec = t1->tv_usec;
+  result->tv_usec = usec - t2->tv_usec;
+
+  result->tv_sec = t1->tv_sec - t2->tv_sec - movedown;
+}
+
+void
+ospf6_timeval_div (const struct timeval *t1, u_int by,
+                   struct timeval *result)
+{
+  long movedown;
+
+  if (by == 0)
+    {
+      result->tv_sec = 0;
+      result->tv_usec = 0;
+      return;
+    }
+
+  movedown = t1->tv_sec % by;
+  result->tv_sec = t1->tv_sec / by;
+  result->tv_usec = (t1->tv_usec + movedown * TIMER_SEC_MICRO) / by;
+}
+
+void
+ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
+                      long *minp, long *secp, long *msecp, long *usecp)
+{
+  long day, hour, min, sec, msec, usec, left;
+
+  left = t->tv_sec;
+  day = left / 86400; left -= day * 86400;
+  hour = left / 3600; left -= hour * 3600;
+  min = left / 60; left -= min * 60;
+  sec = left;
+  left = t->tv_usec;
+  msec = left / 1000; left -= msec * 1000;
+  usec = left;
+
+  if (dayp) *dayp = day;
+  if (hourp) *hourp = hour;
+  if (minp) *minp = min;
+  if (secp) *secp = sec;
+  if (msecp) *msecp = msec;
+  if (usecp) *usecp = usec;
+}
+
+void
+ospf6_timeval_string (struct timeval *tv, char *buf, int size)
+{
+  char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16];
+  long day, hour, min, sec, msec, usec;
+
+  ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec);
+  snprintf (days, sizeof (days), "%ld days ", day);
+  snprintf (hours, sizeof (hours), "%ld hours ", hour);
+  snprintf (mins, sizeof (mins), "%ld mins ", min);
+  snprintf (secs, sizeof (secs), "%ld secs ", sec);
+  snprintf (msecs, sizeof (msecs), "%ld msecs ", msec);
+  snprintf (usecs, sizeof (usecs), "%ld usecs ", usec);
+
+  snprintf (buf, size, "%s%s%s%s%s%s",
+            (day ? days : ""), (hour ? hours : ""),
+            (min ? mins : ""), (sec ? secs : ""),
+            (msec ? msecs : ""), (usec ? usecs : ""));
+}
+
+void
+ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size)
+{
+  char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16];
+  long day, hour, min, sec, msec, usec;
+
+  ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec);
+  snprintf (days, sizeof (days), "%02ldd", day);
+  snprintf (hours, sizeof (hours), "%ldh", hour);
+  snprintf (mins, sizeof (mins), "%ldm", min);
+  snprintf (secs, sizeof (secs), "%lds", sec);
+  snprintf (msecs, sizeof (msecs), "%ldms", msec);
+  snprintf (usecs, sizeof (usecs), "%ldus", usec);
+
+  snprintf (buf, size, "%s%02ld:%02ld:%02ld",
+            (day ? days : ""), hour, min, sec);
+}
+
+/* foreach function */
+void
+ospf6_count_state (void *arg, int val, void *obj)
+{
+  int *count = (int *) arg;
+  u_char state = val;
+  struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
+
+  if (nei->state == state)
+    (*count)++;
+}
+\f
+/* VTY commands.  */
+DEFUN (reload,
+       reload_cmd,
+       "reload",
+       "Reloads\n")
+{
+  extern void _reload ();
+  _reload ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (garbage_collection,
+       garbage_collection_cmd,
+       "ipv6 ospf6 garbage collect",
+       IPV6_STR
+       OSPF6_STR
+       "garbage collection by hand\n"
+       "Remove Maxages if possible and recalculate routes\n")
+{
+  ospf6_maxage_remover ();
+#if 0
+  ospf6_route_calculation_schedule ();
+#endif
+  return CMD_SUCCESS;
+}
+
+/* Show version. */
+DEFUN (show_version_ospf6,
+       show_version_ospf6_cmd,
+       "show version ospf6",
+       SHOW_STR
+       "Displays ospf6d version\n")
+{
+  vty_out (vty, "Zebra OSPF6d Version: %s%s",
+           ospf6_daemon_version, VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+/* start ospf6 */
+DEFUN (router_ospf6,
+       router_ospf6_cmd,
+       "router ospf6",
+       OSPF6_ROUTER_STR
+       OSPF6_STR)
+{
+  if (ospf6 == NULL)
+    ospf6_start ();
+
+  /* set current ospf point. */
+  vty->node = OSPF6_NODE;
+  vty->index = ospf6;
+
+  return CMD_SUCCESS;
+}
+
+/* stop ospf6 */
+DEFUN (no_router_ospf6,
+       no_router_ospf6_cmd,
+       "no router ospf6",
+       NO_STR
+       OSPF6_ROUTER_STR)
+{
+  if (!ospf6)
+    vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE);
+  else
+    ospf6_stop ();
+
+  /* return to config node . */
+  vty->node = CONFIG_NODE;
+  vty->index = NULL;
+
+  return CMD_SUCCESS;
+}
+
+/* show top level structures */
+DEFUN (show_ipv6_ospf6,
+       show_ipv6_ospf6_cmd,
+       "show ipv6 ospf6",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR)
+{
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  ospf6_show (vty);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_nexthoplist,
+       show_ipv6_ospf6_nexthoplist_cmd,
+       "show ipv6 ospf6 nexthop-list",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "List of nexthop\n")
+{
+#if 0
+  listnode i;
+  struct ospf6_nexthop *nh;
+  char buf[128];
+  for (i = listhead (nexthoplist); i; nextnode (i))
+    {
+      nh = (struct ospf6_nexthop *) getdata (i);
+      nexthop_str (nh, buf, sizeof (buf));
+      vty_out (vty, "%s%s", buf,
+              VTY_NEWLINE);
+    }
+#endif
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_statistics,
+       show_ipv6_ospf6_statistics_cmd,
+       "show ipv6 ospf6 statistics",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Statistics\n")
+{
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  ospf6_statistics_show (vty, ospf6);
+  return CMD_SUCCESS;
+}
+
+/* change Router_ID commands. */
+DEFUN (router_id,
+       router_id_cmd,
+       "router-id ROUTER_ID",
+       "Configure ospf Router-ID.\n"
+       V4NOTATION_STR)
+{
+  int ret;
+  u_int32_t router_id;
+
+  ret = inet_pton (AF_INET, argv[0], &router_id);
+  if (!ret)
+    {
+      vty_out (vty, "malformed ospf router identifier%s", VTY_NEWLINE);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("CONFIG: router-id %s", argv[0]);
+  ospf6->router_id = router_id;
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_interface_bind_area (struct vty *vty,
+                           char *if_name, char *area_name,
+                           char *plist_name, int passive)
+{
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+  struct ospf6_area *o6a;
+  u_int32_t area_id;
+
+  /* find/create ospf6 interface */
+  ifp = if_get_by_name (if_name);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    o6i = ospf6_interface_create (ifp);
+
+  /* parse Area-ID */
+  if (inet_pton (AF_INET, area_name, &area_id) != 1)
+    {
+      vty_out (vty, "Invalid Area-ID: %s%s", area_name, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  /* find/create ospf6 area */
+  o6a = ospf6_area_lookup (area_id, ospf6);
+  if (!o6a)
+    {
+      o6a = ospf6_area_create (area_id);
+      o6a->ospf6 = ospf6;
+      listnode_add (ospf6->area_list, o6a);
+    }
+
+  if (o6i->area)
+    {
+      if (o6i->area != o6a)
+        {
+          vty_out (vty, "Aready attached to area %s%s",
+                   o6i->area->str, VTY_NEWLINE);
+          return CMD_ERR_NOTHING_TODO;
+        }
+    }
+  else
+    {
+      listnode_add (o6a->if_list, o6i);
+      o6i->area = o6a;
+    }
+
+  /* prefix-list name */
+  if (plist_name)
+    {
+      if (o6i->plist_name)
+        XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+      o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, plist_name);
+    }
+  else
+    {
+      if (o6i->plist_name)
+        XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+      o6i->plist_name = NULL;
+    }
+
+  if (passive)
+    {
+      listnode node;
+      struct ospf6_neighbor *o6n;
+
+      SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+      if (o6i->thread_send_hello)
+        {
+          thread_cancel (o6i->thread_send_hello);
+          o6i->thread_send_hello = (struct thread *) NULL;
+        }
+
+      for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+        {
+          o6n = getdata (node);
+          if (o6n->inactivity_timer)
+            thread_cancel (o6n->inactivity_timer);
+          thread_execute (master, inactivity_timer, o6n, 0);
+        }
+    }
+  else
+    {
+      UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+      if (o6i->thread_send_hello == NULL)
+        thread_add_event (master, ospf6_send_hello, o6i, 0);
+    }
+
+  /* enable I/F if it's not enabled still */
+  if (! ospf6_interface_is_enabled (o6i->interface->ifindex))
+    thread_add_event (master, interface_up, o6i, 0);
+  else
+    CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  return CMD_SUCCESS;
+}
+
+DEFUN (interface_area_plist,
+       interface_area_plist_cmd,
+       "interface IFNAME area A.B.C.D prefix-list WORD",
+       "Enable routing on an IPv6 interface\n"
+       IFNAME_STR
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       OSPF6_PREFIX_LIST_STR
+       "IPv6 prefix-list name\n"
+      )
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("CONFIG: interface %s area %s prefix-list %s",
+               argv[0], argv[1], argv[2]);
+
+  return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 0);
+}
+
+DEFUN (interface_area_plist_passive,
+       interface_area_plist_passive_cmd,
+       "interface IFNAME area A.B.C.D prefix-list WORD passive",
+       "Enable routing on an IPv6 interface\n"
+       IFNAME_STR
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       OSPF6_PREFIX_LIST_STR
+       "IPv6 prefix-list name\n"
+       "IPv6 prefix-list name\n"
+       OSPF6_PASSIVE_STR
+      )
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("CONFIG: interface %s area %s prefix-list %s passive",
+               argv[0], argv[1], argv[2]);
+
+  return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 1);
+}
+
+DEFUN (interface_area,
+       interface_area_cmd,
+       "interface IFNAME area A.B.C.D",
+       "Enable routing on an IPv6 interface\n"
+       IFNAME_STR
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+      )
+{
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+  int passive;
+  char *plist_name;
+
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("CONFIG: interface %s area %s",
+               argv[0], argv[1]);
+
+  ifp = if_get_by_name (argv[0]);
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (o6i)
+    {
+      passive = CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+      plist_name = o6i->plist_name;
+    }
+  else
+    {
+      passive = 0;
+      plist_name = NULL;
+    }
+
+  return ospf6_interface_bind_area (vty, argv[0], argv[1],
+                                    plist_name, passive);
+}
+
+DEFUN (interface_area_passive,
+       interface_area_passive_cmd,
+       "interface IFNAME area A.B.C.D passive",
+       "Enable routing on an IPv6 interface\n"
+       IFNAME_STR
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       OSPF6_PASSIVE_STR
+      )
+{
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("CONFIG: interface %s area %s passive",
+               argv[0], argv[1]);
+
+  return ospf6_interface_bind_area (vty, argv[0], argv[1], NULL, 1);
+}
+
+DEFUN (no_interface_area,
+       no_interface_area_cmd,
+       "no interface IFNAME area A.B.C.D",
+       NO_STR
+       "Disable routing on an IPv6 interface\n"
+       IFNAME_STR)
+{
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+  struct ospf6 *o6;
+  u_int32_t area_id;
+
+  o6 = (struct ospf6 *) vty->index;
+
+  ifp = if_lookup_by_name (argv[0]);
+  if (!ifp)
+    return CMD_ERR_NO_MATCH;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (!o6i)
+    return CMD_SUCCESS;
+
+  /* parse Area-ID */
+  if (inet_pton (AF_INET, argv[1], &area_id) != 1)
+    {
+      vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (o6i->area->area_id != area_id)
+    {
+      vty_out (vty, "Wrong Area-ID: %s aready attached to area %s%s",
+               o6i->interface->name, o6i->area->str, VTY_NEWLINE);
+      return CMD_ERR_NOTHING_TODO;
+    }
+
+  if (o6i->area)
+    thread_execute (master, interface_down, o6i, 0);
+
+  listnode_delete (o6i->area->if_list, o6i);
+  o6i->area = (struct ospf6_area *) NULL;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (area_range,
+       area_range_cmd,
+       "area A.B.C.D range X:X::X:X/M",
+       "OSPFv3 area parameters\n"
+       "OSPFv3 area ID in IPv4 address format\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "IPv6 address range\n")
+{
+  struct ospf6 *o6;
+  struct ospf6_area *o6a;
+  u_int32_t area_id;
+  int ret;
+
+  o6 = (struct ospf6 *) vty->index;
+  inet_pton (AF_INET, argv[0], &area_id);
+  o6a = ospf6_area_lookup (area_id, o6);
+  if (! o6a)
+    {
+      vty_out (vty, "No such area%s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  ret = str2prefix_ipv6 (argv[1], &o6a->area_range);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (passive_interface,
+       passive_interface_cmd,
+       "passive-interface IFNAME",
+       OSPF6_PASSIVE_STR
+       IFNAME_STR)
+{
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+
+  ifp = if_get_by_name (argv[0]);
+  if (ifp->info)
+    o6i = (struct ospf6_interface *) ifp->info;
+  else
+    o6i = ospf6_interface_create (ifp);
+
+  SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+
+  if (o6i->thread_send_hello)
+    {
+      thread_cancel (o6i->thread_send_hello);
+      o6i->thread_send_hello = (struct thread *) NULL;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_passive_interface,
+       no_passive_interface_cmd,
+       "no passive-interface IFNAME",
+       NO_STR
+       OSPF6_PASSIVE_STR
+       IFNAME_STR)
+{
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+
+  ifp = if_lookup_by_name (argv[0]);
+  if (! ifp)
+    return CMD_ERR_NO_MATCH;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
+  if (o6i->thread_send_hello == NULL)
+    thread_add_event (master, ospf6_send_hello, o6i, 0);
+
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_SETPROCTITLE
+extern int _argc;
+extern char **_argv;
+
+DEFUN (set_proctitle,
+       set_proctitle_cmd,
+       "set proctitle (version|normal|none)",
+       "Set command\n"
+       "Process title\n"
+       "Version information\n"
+       "Normal command-line options\n"
+       "Just program name\n")
+{
+  int i;
+  char buf[64], tmp[64];
+
+  if (strncmp (argv[0], "v", 1) == 0)
+    {
+      proctitle_mode = 1;
+      setproctitle ("%s Zebra: %s", OSPF6_DAEMON_VERSION, ZEBRA_VERSION);
+    }
+  else if (strncmp (argv[0], "nor", 3) == 0)
+    {
+      proctitle_mode = 0;
+      memset (tmp, 0, sizeof (tmp));
+      memset (buf, 0, sizeof (buf));
+      for (i = 0; i < _argc; i++)
+        {
+          snprintf (buf, sizeof (buf), "%s%s ", tmp, _argv[i]);
+          memcpy (&tmp, &buf, sizeof (tmp));
+        }
+      setproctitle (buf);
+    }
+  else if (strncmp (argv[0], "non", 3) == 0)
+    {
+      proctitle_mode = -1;
+      setproctitle (NULL);
+    }
+  else
+    return CMD_ERR_NO_MATCH;
+
+  return CMD_SUCCESS;
+}
+#endif /* HAVE_SETPROCTITLE */
+
+/* OSPF configuration write function. */
+int
+ospf6_config_write (struct vty *vty)
+{
+  listnode j, k;
+  char buf[64];
+  struct ospf6_area *area;
+  struct ospf6_interface *o6i;
+
+  if (proctitle_mode == 1)
+    vty_out (vty, "set proctitle version%s", VTY_NEWLINE);
+  else if (proctitle_mode == -1)
+    vty_out (vty, "set proctitle none%s", VTY_NEWLINE);
+
+  vty_out (vty, "!%s", VTY_NEWLINE);
+
+  if (! ospf6)
+    return 0;
+
+  /* OSPFv6 configuration. */
+  if (!ospf6)
+    return CMD_SUCCESS;
+
+  inet_ntop (AF_INET, &ospf6->router_id, buf, sizeof (buf));
+  vty_out (vty, "router ospf6%s", VTY_NEWLINE);
+  vty_out (vty, " router-id %s%s", buf, VTY_NEWLINE);
+
+  ospf6_redistribute_config_write (vty);
+  ospf6_damp_config_write (vty);
+
+  for (j = listhead (ospf6->area_list); j; nextnode (j))
+    {
+      area = (struct ospf6_area *)getdata (j);
+      for (k = listhead (area->if_list); k; nextnode (k))
+        {
+          o6i = (struct ospf6_interface *) getdata (k);
+          vty_out (vty, " interface %s area %s%s",
+                   o6i->interface->name, area->str, VTY_NEWLINE);
+        }
+    }
+  vty_out (vty, "!%s", VTY_NEWLINE);
+  return 0;
+}
+
+/* OSPF6 node structure. */
+struct cmd_node ospf6_node =
+{
+  OSPF6_NODE,
+  "%s(config-ospf6)# ",
+};
+
+/* Install ospf related commands. */
+void
+ospf6_init ()
+{
+  /* Install ospf6 top node. */
+  install_node (&ospf6_node, ospf6_config_write);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_cmd);
+  install_element (VIEW_NODE, &show_version_ospf6_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd);
+  install_element (ENABLE_NODE, &show_version_ospf6_cmd);
+  install_element (ENABLE_NODE, &reload_cmd);
+  install_element (CONFIG_NODE, &router_ospf6_cmd);
+  install_element (CONFIG_NODE, &interface_cmd);
+#ifdef OSPF6_STATISTICS
+  install_element (VIEW_NODE, &show_ipv6_ospf6_statistics_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_statistics_cmd);
+#endif /* OSPF6_STATISTICS */
+#ifdef OSPF6_GARBAGE_COLLECT
+  install_element (ENABLE_NODE, &garbage_collection_cmd);
+#endif /* OSPF6_GARBAGE_COLLECT */
+#ifdef HAVE_SETPROCTITLE
+  install_element (CONFIG_NODE, &set_proctitle_cmd);
+#endif /* HAVE_SETPROCTITLE */
+
+  install_default (OSPF6_NODE);
+  install_element (OSPF6_NODE, &router_id_cmd);
+  install_element (OSPF6_NODE, &interface_area_cmd);
+  install_element (OSPF6_NODE, &interface_area_passive_cmd);
+  install_element (OSPF6_NODE, &interface_area_plist_cmd);
+  install_element (OSPF6_NODE, &interface_area_plist_passive_cmd);
+  install_element (OSPF6_NODE, &no_interface_area_cmd);
+  install_element (OSPF6_NODE, &passive_interface_cmd);
+  install_element (OSPF6_NODE, &no_passive_interface_cmd);
+  install_element (OSPF6_NODE, &area_range_cmd);
+
+  /* Make empty list of top list. */
+  if_init ();
+
+  /* Install access list */
+  access_list_init ();
+
+  /* Install prefix list */
+  prefix_list_init ();
+
+  ospf6_dump_init ();
+
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_init ();
+#endif /*HAVE_OSPF6_DAMP*/
+
+  ospf6_hook_init ();
+  ospf6_lsa_init ();
+
+  ospf6_top_init ();
+  ospf6_area_init ();
+  ospf6_interface_init ();
+  ospf6_neighbor_init ();
+  ospf6_zebra_init ();
+
+  ospf6_routemap_init ();
+  ospf6_lsdb_init ();
+
+  ospf6_spf_init ();
+
+  ospf6_intra_init ();
+  ospf6_abr_init ();
+  ospf6_asbr_init ();
+}
+
+void
+ospf6_terminate ()
+{
+  /* stop ospf6 */
+  ospf6_stop ();
+
+  /* log */
+  zlog (NULL, LOG_INFO, "OSPF6d terminated");
+}
+
+void
+ospf6_maxage_remover ()
+{
+#if 0
+  if (IS_OSPF6_DUMP_LSDB)
+    zlog_info ("MaxAge Remover");
+#endif
+
+  ospf6_top_schedule_maxage_remover (NULL, 0, ospf6);
+  (*ospf6->foreach_area) (ospf6, NULL, 0,
+                          ospf6_area_schedule_maxage_remover);
+  (*ospf6->foreach_if) (ospf6, NULL, 0,
+                        ospf6_interface_schedule_maxage_remover);
+}
+
+
+
+void *
+ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i)
+{
+  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (type)))
+    return o6i;
+  else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (type)))
+    return o6i->area;
+  else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (type)))
+    return o6i->area->ospf6;
+  else
+    return NULL;
+}
+
diff --git a/ospf6d/ospf6d.conf.sample b/ospf6d/ospf6d.conf.sample
new file mode 100644 (file)
index 0000000..71972f5
--- /dev/null
@@ -0,0 +1,54 @@
+!
+! Zebra configuration saved from vty
+!   2000/05/11 02:09:37
+!
+hostname ospf6d@yasu3380
+password zebra
+log file /var/log/zebra-ospf6d.log
+log stdout
+!
+debug ospf6 message dbdesc
+debug ospf6 message lsreq
+debug ospf6 message lsupdate
+debug ospf6 message lsack
+debug ospf6 neighbor
+debug ospf6 spf
+debug ospf6 interface
+debug ospf6 area
+debug ospf6 lsa
+debug ospf6 zebra
+debug ospf6 config
+debug ospf6 dbex
+debug ospf6 route
+!
+interface ed0
+ ipv6 ospf6 cost 1
+ ipv6 ospf6 hello-interval 10
+ ipv6 ospf6 dead-interval 40
+ ipv6 ospf6 retransmit-interval 5
+ ipv6 ospf6 priority 1
+ ipv6 ospf6 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+!
+interface lo0
+ ipv6 ospf6 cost 1
+ ipv6 ospf6 hello-interval 10
+ ipv6 ospf6 dead-interval 40
+ ipv6 ospf6 retransmit-interval 5
+ ipv6 ospf6 priority 1
+ ipv6 ospf6 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+!
+router ospf6
+ router-id 0.0.0.1
+ redistribute static route-map static-ospf6
+ interface ed0 area 0.0.0.0
+ interface lo0 area 0.0.0.0
+!
+ipv6 prefix-list hostroute seq 10 permit 3ffe:501:100c:4380::/60 le 128 ge 128
+!
+route-map static-ospf6 permit 50
+ match ipv6 address prefix-list hostroute
+ set metric-type type-2
+ set metric 30
+!
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
new file mode 100644 (file)
index 0000000..e0d310a
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 1999 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef OSPF6D_H
+#define OSPF6D_H
+
+#include <zebra.h>
+#include "linklist.h"
+
+#ifndef HEADER_DEPENDENCY
+/* Include other stuffs */
+#include "version.h"
+#include "log.h"
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "sockunion.h"
+#include "if.h"
+#include "prefix.h"
+#include "stream.h"
+#include "thread.h"
+#include "filter.h"
+#include "zclient.h"
+#include "table.h"
+#include "plist.h"
+
+/* OSPF stuffs */
+#include "ospf6_hook.h"
+#include "ospf6_types.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+#include "ospf6_message.h"
+#include "ospf6_proto.h"
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_ism.h"
+#include "ospf6_nsm.h"
+#include "ospf6_route.h"
+#include "ospf6_dbex.h"
+#include "ospf6_network.h"
+#include "ospf6_zebra.h"
+#include "ospf6_dump.h"
+#include "ospf6_routemap.h"
+#include "ospf6_asbr.h"
+#include "ospf6_abr.h"
+#include "ospf6_intra.h"
+#endif /*HEADER_DEPENDENCY*/
+
+#define HASHVAL 64
+#define MAXIOVLIST 1024
+
+#define OSPF6_DAEMON_VERSION    "0.9.6o"
+
+#define AF_LINKSTATE  0xff
+
+/* global variables */
+extern char *progname;
+extern int errno;
+extern int daemon_mode;
+extern struct thread_master *master;
+extern list iflist;
+extern list nexthoplist;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern char *recent_reason;
+
+/* Default configuration file name for ospfd. */
+#define OSPF6_DEFAULT_CONFIG       "ospf6d.conf"
+
+/* Default port values. */
+#define OSPF6_VTY_PORT             2606
+#define OSPF6_VTYSH_PATH           "/tmp/.ospf6d"
+
+#ifdef INRIA_IPV6
+#ifndef IPV6_PKTINFO
+#define IPV6_PKTINFO IPV6_RECVPKTINFO
+#endif /* IPV6_PKTINFO */
+#endif /* INRIA_IPV6 */
+
+/* Historycal for KAME.  */
+#ifndef IPV6_JOIN_GROUP
+#ifdef IPV6_ADD_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif /* IPV6_ADD_MEMBERSHIP. */
+#ifdef IPV6_JOIN_MEMBERSHIP
+#define IPV6_JOIN_GROUP  IPV6_JOIN_MEMBERSHIP
+#endif /* IPV6_JOIN_MEMBERSHIP. */
+#endif /* ! IPV6_JOIN_GROUP*/
+
+#ifndef IPV6_LEAVE_GROUP
+#ifdef IPV6_DROP_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif /* IPV6_DROP_MEMBERSHIP */
+#endif /* ! IPV6_LEAVE_GROUP */
+
+#define OSPF6_CMD_CHECK_RUNNING() \
+  if (ospf6 == NULL) \
+    { \
+      vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \
+      return CMD_SUCCESS; \
+    }
+
+#define OSPF6_LEVEL_NONE      0
+#define OSPF6_LEVEL_NEIGHBOR  1
+#define OSPF6_LEVEL_INTERFACE 2
+#define OSPF6_LEVEL_AREA      3
+#define OSPF6_LEVEL_TOP       4
+#define OSPF6_LEVEL_MAX       5
+
+#define OSPF6_PASSIVE_STR \
+  "Suppress routing updates on an interface\n"
+#define OSPF6_PREFIX_LIST_STR \
+  "Advertise I/F Address only match entries of prefix-list\n"
+
+#define OSPF6_AREA_STR      "Area information\n"
+#define OSPF6_AREA_ID_STR   "Area ID (as an IPv4 notation)\n"
+#define OSPF6_SPF_STR       "Shortest Path First tree information\n"
+#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
+#define OSPF6_LS_ID_STR     "Specify Link State ID\n"
+
+\f
+/* Function Prototypes */
+void
+ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2,
+                   struct timeval *result);
+void
+ospf6_timeval_div (const struct timeval *t1, u_int by,
+                   struct timeval *result);
+void
+ospf6_timeval_sub_equal (const struct timeval *t, struct timeval *result);
+void
+ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
+                      long *minp, long *secp, long *msecp, long *usecp);
+void
+ospf6_timeval_string (struct timeval *tv, char *buf, int size);
+void
+ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size);
+
+void
+ospf6_count_state (void *arg, int val, void *obj);
+
+void ospf6_init ();
+void ospf6_terminate ();
+
+void ospf6_maxage_remover ();
+
+void *ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i);
+
+#endif /* OSPF6D_H */
+
diff --git a/ospfd/.cvsignore b/ospfd/.cvsignore
new file mode 100644 (file)
index 0000000..d7e3a7e
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile
+*.o
+ospfd
+ospfd.conf
+tags
+TAGS
+.deps
diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog
new file mode 100644 (file)
index 0000000..31c5b0f
--- /dev/null
@@ -0,0 +1,2970 @@
+2002-10-23  endo@suri.co.jp (Masahiko Endo)
+
+       * ospf_opaque.c: Update Opaque LSA patch.
+
+2002-10-23  Ralph Keller <keller@tik.ee.ethz.ch>
+
+       * ospf_vty.c (show_ip_ospf_database): Fix CLI parse.
+
+2002-10-23  Juris Kalnins <juris@mt.lv>
+
+       * ospf_interface.c (ospf_if_stream_unset): When write queue
+       becomes empty stop write timer.
+
+2002-10-10  Greg Troxel <gdt@ir.bbn.com>
+
+       * ospf_packet.c (ospf_check_md5_digest): Change >= to > to make it
+       conform to RFC.
+
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2002-06-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf_spf.c (ospf_nexthop_calculation): Add NULL set to oi and
+       check of l2.  Reported by: Daniel Drown <dan-zebra@drown.org>
+       (ospf_lsa_has_link): LSA Length calculation fix.  Reported by:
+       Paul Jakma <paulj@alphyra.ie>.
+
+       * ospfd.c (ospf_if_update): Fix nextnode reference bug.  Reported
+       by: juris@mt.lv.
+
+2002-01-21  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospfd.c: Merge [zebra 11445] Masahiko ENDO's Opaque-LSA support.
+
+2001-08-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_interface.c (ospf_add_to_if): Use /32 address to register
+       OSPF interface information.
+       (ospf_delete_from_if): Likewise.
+
+       * ospf_zebra.c (ospf_interface_address_delete): Likewise.
+
+2001-08-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf_zebra.c (ospf_redistribute_unset): When redistribute type
+       is OSPF, do not unset redistribute flag.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-08-12  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospfd.c (ospf_config_write): auto-cost reference-bandwidth
+       configuration display.
+
+2001-07-24  David Watson <dwatson@eecs.umich.edu>
+
+       * ospf_spf.c (ospf_spf_next): Modify ospf_vertex_add_parent to
+       check for an existing link before connecting the parent and child.
+       ospf_nexthop_calculation is also modified to check for duplicate
+       entries when copying from the parent.  Finally, ospf_spf_next
+       removes duplicates when it merges two equal cost candidates.
+
+2001-07-23  itojun@iijlab.net
+
+       * ospfd.c (show_ip_ospf_neighbor): Check ospf_top before use it
+       [zebra 8549].
+
+2001-07-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf_packet.c (ospf_write): Remove defined(__OpenBSD__) to make
+       it work on OpenBSD.
+
+2001-06-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_zebra.c (config_write_ospf_default_metric): Display
+       default-metric configuration.
+
+2001-06-18  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf_ia.h (OSPF_EXAMINE_SUMMARIES_ALL): Remove old macros.
+
+2001-05-28  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ospf_snmp.c (ospfIfEntry): Fix interface lookup bug to avoid
+       crush.
+       (ospfIfMetricEntry): Likewise.
+
+2001-03-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_read): Fix typo.  Reported by: "Jen B
+       Lin'Kova" <jen@stack.net>.
+
+2001-03-15  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_interface.c (ip_ospf_network): Set interface parameter.
+       (interface_config_write): Add check for OSPF_IFTYPE_LOOPBACK.
+
+       * ospf_zebra.c (ospf_interface_add): Set interface parameter.
+
+2001-02-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_recv_packet): Solaris also need to add
+       (iph.ip_hl << 2) to iph.ip_len.
+
+2001-02-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.h (OSPF_LS_REFRESH_TIME): Fix OSPF_LS_REFRESH_TIME value.
+       Suggested by: David Watson <dwatson@eecs.umich.edu>.
+
+       * ospf_zebra.c (zebra_init): Remove zebra node.
+
+       * ospfd.c (ospf_area_range_set): Function name is changed from
+       ospf_ara_range_cmd.
+       (ospf_area_range_unset): New function which separated from DEFUN.
+       New commands are added:
+       "no area A.B.C.D range A.B.C.D/M advertise"
+       "no area <0-4294967295> range A.B.C.D/M advertise"
+       "no area A.B.C.D range A.B.C.D/M not-advertise"
+       "no area <0-4294967295> range A.B.C.D/M not-advertise"
+       
+       * ospf_lsa.c (ospf_lsa_more_recent): Fix previous change.
+
+2001-02-08  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * ospf_network.c (ospf_if_add_allspfrouters): Use
+       setsockopt_multicast_ipv4.
+       (ospf_if_drop_allspfrouters): Likewise.
+
+       * ospf_lsa.c (ospf_router_lsa_install): Add rt_recalc flag.
+       (ospf_network_lsa_install): Likewise.
+       (ospf_summary_lsa_install): Likewise.
+       (ospf_summary_asbr_lsa_install): Likewise.
+       (ospf_external_lsa_install): Likewise.
+       (ospf_lsa_install): Call ospf_lsa_different to check this LSA is
+       new one or not.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_zebra.c (ospf_interface_delete): Do not free interface
+       structure when ospfd receive interface delete message to support
+       pseudo interface.
+
+2001-02-01  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospfd.c (area_range_notadvertise): Change area range "suppress"
+       command to "not-advertise".
+
+       * ospfd.h (OSPF_LS_REFRESH_TIME): Change OSPF_LS_REFRESH_TIME from
+       1800 to 60.
+
+       * ospf_abr.c (ospf_abr_update_aggregate): When update_aggregate is
+       updating the area-range, the lowest cost is now saved.
+
+       * ospf_lsa.c (ospf_lsa_more_recent): Routing to compare sequence
+       numbers rather than creating overflow during calculation.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_db_desc_proc): Do not continue process when
+       NSM_SeqNumberMismatch is scheduled.
+       (ospf_ls_req): Free ls_upd when return from this function.
+       (ospf_ls_upd_timer): When update list is empty do not call
+       ospf_ls_upd_send().  Suggested by: endo@suri.co.jp (Masahiko
+       Endo).
+
+2001-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_lsa.c (ospf_maxage_flood): Flood LSA when it reaches
+       MaxAge.  RFC2328 Section 14.
+       (ospf_maxage_lsa_remover): Call above function during removing
+       MaxAge LSA.
+
+2001-01-26  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospf_flood.c (ospf_flood_through_as): Function is updated for
+       NSSA Translations now done at ospf_abr.c with no change in P-bit.
+
+       * ospf_lsa.c (ospf_get_nssa_ip): Get 1st IP connection for Forward
+       Addr.
+       (ospf_install_flood_nssa):  Leave Type-7 LSA at Lock Count = 2. 
+
+       * ospf_ase.c (ospf_ase_calculate_route): Add debug codes.
+
+       * ospf_abr.c (ospf_abr_translate_nssa): Recalculate LSA checksum.
+
+       * ospf_packet.h (OSPF_SEND_PACKET_LOOP): Added for test packet.
+
+       * ospf_dump.c (ospf_lsa_type_msg): Add OSPF_GROUP_MEMBER_LSA and
+       OSPF_AS_NSSA_LSA.
+
+       * ospfd.c (data_injection): Function to inject LSA.  This is
+       debugging command.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_route.c (ospf_route_match_same): Remove function.
+       (ospf_route_match_same_new): Renamed to ospf_route_match_same.
+
+       * ospf_zebra.c (ospf_interface_address_delete): Add check for
+       oi->address.  Suggested by Matthew Grant
+       <grantma@anathoth.gen.nz>.
+       (ospf_zebra_add): Remove function.
+       (ospf_zebra_add_multipath): Rename to ospf_zebra_add.
+
+       * ospf_interface.c: Remove HAVE_IF_PSEUDO part.
+
+       * ospf_zebra.c: Likewise.
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_ase.c: Remove OLD_RIB part.
+
+       * ospf_route.c: Likewise.
+
+       * zebra-0.90 is released.
+
+       * ospf_packet.c (ospf_recv_packet): Use ip_len adjestment code to
+       NetBSD.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_route.c (ospf_route_delete): Use
+       ospf_zebra_delete_multipath.
+
+2001-01-09  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * ospf_interface.c (ospf_if_cleanup): Function name is renamed
+       from ospf_if_free().  Rewrite whole procudure to support primary
+       address deletion.
+
+       * ospf_zebra.c (ospf_interface_address_delete): Add primary
+       address deletion process.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_recv_packet): OpenBSD has same ip_len
+       treatment like FreeBSD.
+
+2001-01-09  endo@suri.co.jp (Masahiko Endo)
+
+       * ospf_packet.c (ospf_recv_packet): FreeBSD kernel network code
+       strips IP header size from receiving IP Packet.  So we adjust
+       ip_len to whole IP packet size by adding IP header size.
+
+2001-01-08  endo@suri.co.jp (Masahiko Endo)
+
+       * ospf_network.c (ospf_serv_sock): When socket() is failed return
+       immediately.
+       (ospf_serv_sock): Close socket when it is not used.
+
+       * ospf_packet.c (ospf_write): Set sin_len when HAVE_SIN_LEN is
+       defined.
+       (ospf_write): When bind is fined, close sock.
+
+2001-01-07  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_zebra.c (ospf_interface_state_up): Fixes coredump that
+       appears when you try to configure bandwidth on the ppp interface
+       that is not yet configured in ospfd.
+
+2001-01-07  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospf_route.c (show_ip_ospf_route_external): "show ip ospf route"
+       will print nexthops for AS-external routes.
+
+       * ospf_ase.c (ospf_ase_route_match_same): New function to compare
+       ASE route under multipath environment.
+       (ospf_ase_compare_tables): Likewise.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.h (OSPF_VTYSH_PATH): Change "/tmp/ospfd" to "/tmp/.ospfd".
+
+2000-12-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_route.c (ospf_route_install): Install multipath information
+       to zebra daemon.
+
+       * ospf_zebra.c (ospf_zebra_add_multipath): Function for passing
+       multipath information to zebra daemon.
+
+2000-12-25  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospf_packet.c (ospf_write): Call ospf_packet_delete when sendto
+       fail.
+       (DISCARD_LSA): Add argument N for logging point of DISCARD_LSA is
+       called.
+
+       * ospf_lsa.c (ospf_external_lsa_refresh): NSSA install_flood will
+       leave Type-7 LSA at Lock Count = 2.
+
+       * ospf_flood.c (ospf_flood_through): Flood_though_as updated for
+       NSSA no P-bit off during Area flooding, but P-bit is turned off
+       for mulitple NSSA AS flooding.
+
+       * ospf_ase.c (ospf_ase_calculate_timer): Added calculations for
+       Type-7 LSDB.
+
+       * ospf_abr.c (ospf_abr_translate_nssa): Removed one unlock call.
+       (ospf_abr_announce_nssa_defaults): Corrected Debug from EVENT to
+       NSSA.
+
+2000-12-25  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospf_zebra.c (ospf_zebra_read_ipv4): Checking the age of the
+       found LSA and if the LSA is MAXAGE we should call refresh instead
+       of originate.
+
+2000-12-18  Dick Glasspool <dick@ipinfusion.com>
+                  
+       * ospf_abr.c: Removed redundant "...flood" in
+       announce_network_to_area().  Repaired nssa Unlock by using
+       discard.
+
+       * ospf_packet.c: Removed old NSSA translate during mk_ls_update.
+       
+       * ospfd.c: Free up all data bases including NSSA.
+
+       * ospf_lsa.c: Now allow removal of XLATE LSA's Check in
+       discard_callback. Added routine to get ip addr from within the
+       ifp.
+
+       * ospf_flood.c: Now set Forward Address for outgoing Type-7.
+
+       * ospf_lsa.h: Added prototype for the below. struct in_addr
+       ospf_get_ip_from_ifp (struct interface *ifp).
+
+2000-12-14  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_packet.c (ospf_recv_packet): New OSPF pakcet read method.
+       Now maximum packet length may be 65535 bytes (maximum IP packet
+       length).
+
+       * ospf_interface.c (ospf_if_stream_set): Don't make input buffer.
+
+       * ospfd.c (config_write_network_area): Remove unnecessary area
+       lookup code.
+
+2000-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_read): Accept packet bigger than MTU value.
+
+2000-12-13  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospfd.c (config_write_network_area): Fix bug in
+       config_write_network_area function.
+
+2000-12-12  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_abr.c (ospf_abr_announce_network_to_area): Make Summary
+       LSA's origination and refreshment as same as other type of LSA.
+
+       * ospf_lsa.c (ospf_summary_lsa_refresh): Return struct ospf_lsa *.
+
+       * ospf_lsa.c (ospf_summary_asbr_lsa_refresh): Likewise.
+
+2000-12-08  Dick Glasspool <dick@ipinfusion.com>
+
+       The bulk of NSSA changes are contained herein; This version will
+       require manual setting of "always" for NSSA Translator, and will
+       not perform aggregation yet.
+
+       * ospf_dump.c: "debug ospf nssa" is added.
+
+       * ospf_dump.h: Likewise.
+
+       * ospf_packet.c (ospf_hello): Display router ID on Bad NSSA Hello.
+
+       * ospfd.c: Discard_LSA to stay away from LOCAL_XLT Process NSSA
+       'never, candidate, always'.  Change "suppress" to "not-advertise".
+
+       * ospfd.h: Add TranslatorRole to struct ospf_area.  Add anyNSSA to
+       struct ospf.
+
+       * ospf_ase.c (ospf_ase_calculate_route): External to stay away
+       from LOCAL_XLT
+
+       * ospf_nsm.c (ospf_db_summary_add): External to stay away from
+       LOCAL_XLT
+
+       * ospf_abr.c: Major logic added for abr_nssa_task().  If ABR, and
+       NSSA translator, then do it.  Approve the global list, and flush
+       any unapproved.
+       
+       * ospf_lsa.h: New LSA flag OSPF_LSA_LOCAL_XLT to indicate that the
+       Type-5 resulted from a Local Type-7 translation; not used for
+       flooding, but used for flushing.
+
+       * ospf_flood.c: New NSSA flooding.
+
+2000-12-08  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospfd.c (ospf_find_vl_data): New function for looking up virtual
+       link data.
+       (ospf_vl_set_security): Virtual link configuration with
+       authentication.
+       (ospf_vl_set_timers): Set timers for virtual link.
+
+       * New commands are added.
+       "area A.B.C.D virtual-link A.B.C.D"
+       "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>"
+       "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY"
+       "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY"
+       "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY"
+       "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY"
+
+       * ospf_packet.c (ospf_check_md5_digest): Add neighbor's
+       cryptographic sequence number treatment.
+       (ospf_check_auth): OSPF input buffer is added to argument.
+       (ospf_read): Save neighbor's cryptographic sequence number.
+
+       * ospf_nsm.c (nsm_change_status): Clear cryptographic sequence
+       number when neighbor status is changed to NSM down.
+
+       * ospf_neighbor.c (ospf_nbr_new): Set zero to crypt_seqnum.
+
+       * ospf_neighbor.h (struct ospf_neighbor): Add cryptographic
+       sequence number to neighbor structure.
+
+2000-11-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_snmp.c (ospfIfLookup): OSPF MIB updates.
+       (ospfExtLsdbEntry): Add OspfExtLsdbTable treatment.
+
+2000-11-28  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospfd.c (ospf_interface_down): Clear a ls_upd_queue queue of the
+       interface.
+       (ospf_ls_upd_queue_empty): New function to empty ls update queue
+       of the OSPF interface.
+       (no_router_ospf): 'no router ospf' unregister redistribution
+       requests from zebra.
+
+2000-11-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_ism.c (ism_change_status): Increment status change number.
+
+       * ospf_interface.h (struct ospf_interface): Add new member for
+       status change statistics.
+
+       * Makefile.am: Update dependencies.
+
+       * ospf_zebra.c (ospf_interface_add): OSPF SNMP interface update.
+       (ospf_interface_delete): OSPF SNMP interface delete.
+
+       * ospf_snmp.h: New file is added.
+
+2000-11-23  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospfd.h: Add new ospf_area structure member for
+       NSSATranslatorRole and NSSATranslator state.
+
+       * ospfd.c: Provided for eventual commands to specify NSSA
+       elections for "translator- ALWAYS/NEVER/CANDIDATE". Provided for
+       decimal integer version of area-suppress.
+
+       * ospf_flood.c: Flood Type-7's only into NSSA (not AS).
+
+       * ospf_lsa.c: Undo some previous changes for NSSA.  If NSSA
+       translator, advertise Nt bit.
+
+       * ospf_route.c: 1st version of "sh ip os border-routers".
+
+2000-11-23  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospfd.c (area_vlink): Virtual link can not configured in stub
+       area.
+
+2000-11-23  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_packet.c (ospf_db_desc): In states Loading and Full the
+       slave must resend its last Database Description packet in response
+       to duplicate Database Description packets received from the
+       master.  For this reason the slave must wait RouterDeadInterval
+       seconds before freeing the last Database Description packet.
+       Reception of a Database Description packet from the master after
+       this interval will generate a SeqNumberMismatch neighbor
+       event. RFC2328 Section 10.8
+       (ospf_make_db_desc): DD Master flag treatment.
+
+       * ospf_nsm.c (nsm_twoway_received): Move DD related procedure to
+       nsm_change_status().
+       (nsm_bad_ls_req): Likewise.
+       (nsm_adj_ok): Likewise.
+       (nsm_seq_number_mismatch): Likewise.
+       (nsm_oneway_received): Likewise.
+
+       * ospf_neighbor.h (struct ospf_neighbor): New structure member
+       last_send_ts for timestemp when last Database Description packet
+       was sent.
+
+       * ospf_nsm.c (ospf_db_desc_timer): Make it sure nbr->last_send is
+       there.  Call ospf_db_desc_resend() in any case.
+
+2000-11-16  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospf_lsa.c (lsa_link_broadcast_set): When there is no DR on
+       network (suppose you have only one router with interface priority
+       0). It's router LSA does not contain the link information about
+       this network.
+
+       * ospf_nsm.c (nsm_timer_set): When you change a priority of
+       interface from/to 0 ISM_NeighborChange event should be scheduled
+       in order to elect new DR/BDR on the network.
+
+       * ospf_interface.c (ip_ospf_priority): Likewise.
+
+       * ospf_flood.c (ospf_ls_retransmit_add): When we add some LSA into
+       retransmit list we need to check whether the present old LSA in
+       retransmit list is not more recent than the new
+       one.
+
+2000-11-09  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospf_packet.c: Allows for NSSA Type-7 LSA's throughout the NSSA
+       area.  Any that exit the NSSA area are translated to type-5 LSA's.
+       The instantiated image is restored after translation.
+       (ospf_ls_upd_send_list): Renamed to ospf_ls_upd_queu_send().
+       (ospf_ls_upd_send): Old function which enclosed by #ifdef 0 is
+       removed.
+       (ospf_ls_ack_send): Likewise.
+
+       * ospf_flood.c: NSSA-LSA's without P-bit will be restricted to
+       local area.  Otherwise they are allowed out the area to be
+       translated by ospf_packet.c.
+
+       * ospf_lsa.c: Undo some previous changes for NSSA.
+
+       * ospf_lsdb.h: New access for type 7.
+
+2000-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_route.c (ospf_path_exist): New function to check nexthop
+       and interface are in current OSPF path or not.
+       (ospf_route_copy_nexthops_from_vertex): Add nexthop to OSPF path
+       when it is not there.  Reported by Michael Rozhavsky
+       <mrozhavsky@opticalaccess.com>
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_dump.c (config_write_debug): Add seventh string "detail" is
+       added for flag is OSPF_DEBUG_SEND | OSPF_DEBUG_RECV |
+       OSPF_DEBUG_DETAIL.
+
+2000-11-06   Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * ospf_lsa.c (router_lsa_flags): ASBR can't exit in stub area.
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_lsa.c (ospf_router_lsa_originate): Reduce unconditional
+       logging.
+
+2000-11-06  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospfd.h: Add ait_ntoa function prototype.
+
+       * ospfd.c (ait_ntoa): New function for displaying area ID and
+       Stub/NSSA status.
+       (show_ip_ospf_interface_sub): Use ait_ntoa.
+       (show_ip_ospf_nbr_static_detail_sub): Likewise.
+       (show_ip_ospf_neighbor_detail_sub): Likewise.
+
+       * ospf_route.c (ospf_intra_route_add): Set external routing type
+       to ospf route.
+       (ospf_intra_add_router): Likewise.
+       (ospf_intra_add_transit): Likewise.
+       (ospf_intra_add_stub): Likewise.
+       (ospf_add_discard_route): Likewise.
+       (show_ip_ospf_route_network): Use ait_ntoa.
+       (show_ip_ospf_route_network): Likewise.
+       (show_ip_ospf_route_router): Likewise.
+
+       * ospf_lsa.c (show_lsa_detail): Use ait_ntoa.
+       (show_lsa_detail_adv_router): Likewise.
+       (show_ip_ospf_database_summary): Likewise.
+
+       * ospf_route.h (struct route_standard): Add new member
+       external_routing.
+
+       * ospf_ia.c (process_summary_lsa): Set external routing tyep to ospf
+       route.
+       (ospf_update_network_route): Likewise.
+       (ospf_update_router_route): Likewise.
+
+2000-11-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_flood.c (ospf_process_self_originated_lsa): Enclose
+       OSPF_AS_NSSA_LSA treatment with #ifdef HAVE_NSSA.
+
+2000-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Unconditional logging is enclosed with if (IS_DEBUG_OSPF_EVENT).
+       Please specify "debug ospf event" for enable logging.
+
+       * ospf_ism.c: Do not extern debug flag varible.  It is done by
+       ospf_debug.h
+       * ospf_asbr.c: Likewise.
+       * ospf_lsa.c: Likewise.
+       * ospf_nsm.c: Likewise.
+       * ospf_zebra.c: Likewise.
+
+       * ospf_dump.c (debug_ospf_event): New command "debug ospf event"
+       is added.
+
+       * ospfd.c (router_ospf): Change logging from vty_out() to
+       zlog_info().
+       (ospf_area_stub_cmd): Likewise.
+
+       * ospf_dump.h: Extern term_debug flags.
+       (OSPF_DEBUG_EVENT): Add new flag.
+       (IS_DEBUG_OSPF_EVENT): Add new macro.
+
+2000-11-03  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospf_flood.c (ospf_process_self_originated_lsa):
+       OSPF_AS_NSSA_LSA is treated as same as OSPF_AS_EXTERNAL_LSA.
+       (ospf_flood): Type-5's have no change.  Type-7's can be received,
+       and will Flood the AS as Type-5's They will also flood the local
+       NSSA Area as Type-7's.  The LSDB will be updated as Type-5's, and
+       during re-fresh will be converted back to Type-7's (if within an
+       NSSA).
+       (ospf_flood_through): Incoming Type-7's were allowed here if our
+       neighbor was an NSSA.  So Flood our area with the Type-7 and also
+       if we are an ABR, flood thru AS as Type-5.
+
+       * ospf_lsa.c (ospf_external_lsa_refresh): Flood NSSA both NSSA
+       area and other area.
+
+       * ospf_packet.c (ospf_db_desc_proc): When AS External LSA is
+       exists in DD packet, make it sure that this area is not stub.
+       (ospf_ls_upd_list_lsa): When LSA type is NSSA then set lsa's area
+       to NULL.
+       (ospf_ls_upd): If the LSA is AS External LSA and the area is stub
+       then discard the lsa.  If the LSA is NSSA LSA and the area is not
+       NSSA then discard the lsa.
+
+2000-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.c (ospf_interface_run): Fix bug of Hello packet's option
+       is not properly set when interface comes up.
+
+2000-11-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.h (OSPF_OPTION_O): Add new hello header option.
+
+2000-11-01  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospf_lsa.h: Define OSPF_MAX_LSA to 8 when HAVE_NSSA is enabled.
+       (OSPF_GROUP_MEMBER_LSA): Define OSPF_GROUP_MEMBER_LSA.
+
+       * ospf_lsa.c (show_database_desc): Add "Group Membership LSA"
+       string.
+
+2000-10-31  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospf_lsa.h (OSPF_AS_NSSA_LSA): Define OSPF_AS_NSSA_LSA.
+       
+       * ospf_lsa.c (show_ip_ospf_database): NSSA database display
+       function is added.  ALIASES which have "show ip ospf database
+       nssa-external" is added.
+       (show_ip_ospf_border_routers): New command "show ip ospf
+       border-routers" is added.
+
+2000-10-30  Dick Glasspool <dick@ipinfusion.com>
+
+       * ospfd.c (router_ospf): NSSA Enabled message is added for
+       testing.
+       (ospf_area_type_set): Are type set for NSSA area.
+       (ospf_area_stub_cmd): Special translation of no_summary into NSSA
+       and summary information. If NSSA is enabled pass the information
+       to ospf_area_type_set().
+       (area_nssa): New commands are added:
+       "area A.B.C.D nssa"
+       "area <0-4294967295> nssa"
+       "area A.B.C.D nssa no-summary"
+       "area <0-4294967295> nssa no-summary"
+       (ospf_no_area_stub_cmd): Special translation of no_summary into
+       NSSA and summary information.  If external_routing is
+       OSPF_AREA_NSSA unset area with ospf_area_type_set (area,
+       OSPF_AREA_DEFAULT).
+       (show_ip_ospf_area): Display NSSA status.
+       (config_write_ospf_area): Show NSSA configuration.
+
+       * ospf_packet.c (ospf_hello): For NSSA support, ensure that NP is
+       on and E is off.
+
+2000-10-26  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_lsa.c (ospf_network_lsa_body_set): The network-LSA lists
+       those routers that are fully adjacent to the Designated Router;
+       each fully adjacent router is identified by its OSPF Router ID.
+       The Designated Router includes itself in this list. RFC2328,
+       Section 12.4.2.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+       * ospf_snmp.c: ospf_oid and ospfd_oid are used in smux_open after
+       it is registered.  So those variables must be static.
+
+2000-10-18  K N Sridhar <sridhar@euler.ece.iisc.ernet.in>
+
+       * ospfd.c: Add area_default_cost_decimal_cmd and
+       no_area_default_cost_decimal_cmd alias.
+
+2000-10-05  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospfd.c (ospf_network_new): Fix setting area format.
+       (no_router_ospf): Check area existance when calling
+       ospf_interface_down().
+
+       * ospf_flood.c (ospf_external_info_check): Fix bug of refreshing
+       default route.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-09-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_snmp.c (ospfHostEntry): OSPF Host MIB is implemented.
+
+       * ospfd.c (ospf_nbr_static_cmp): OSPF neighbor is sorted by it's
+       address.
+
+2000-09-28  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_interface.c (ospf_if_free):  Fix deleting self neighbor twice.
+
+2000-09-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_read): Solaris on x86 has ip_len with host
+       byte order.
+
+2000-09-25  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (ospf_compatible_rfc1583), (no_ospf_compatible_rfc1583):
+       Add CISCO compatible command.
+
+2000-09-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_abr.c (ospf_area_range_lookup): New function is added for
+       area range lookup in OSPF-MIB.
+       (ospf_area_range_lookup_next): Likewise.
+
+2000-09-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.c (no_router_ospf): Delete virtual link before deleting
+       area structure.
+
+       * ospf_lsa.c (ospf_external_lsa_refresh_type): Check
+       EXTERNAL_INFO(type).
+
+       * ospfd.c (no_router_ospf): Call ospf_vl_delete() instead of
+       ospf_vl_data_free().
+
+       * ospf_interface.c (ospf_vl_shutdown): Execute ISM_InterfaceDown
+       when ospf_vl_shutdown is called.
+       (ospf_vl_delete): Call ospf_vl_shutdown() to delete virtual link
+       interface's thread.
+
+2000-09-21  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_lsa.c: New implementation of OSPF refresh.
+
+2000-09-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_snmp.c (ospfLsdbLookup): Add LSDB MIB implementation.
+
+2000-09-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_snmp.c (ospfStubAreaEntry): Add OSPF stub area MIB.
+
+2000-09-18  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_route.h (route_standard):  Change member from `struct area'
+       to area_id.
+
+       * ospf_abr.c (ospf_abr_announce_network), (ospf_abr_should_announce),
+       (ospf_abr_process_network_rt), (ospf_abr_announce_rtr), 
+       (ospf_abr_process_router_rt):
+       * ospf_ase.c (ospf_find_asbr_route),
+       (ospf_find_asbr_router_through_area),
+       * ospf_ia.c (ospf_find_abr_route), (ospf_ia_router_route),
+       (process_summary_lsa), (ospf_update_network_route),
+       (ospf_update_router_route):
+       * ospf_route.c (ospf_intra_route_add), (ospf_intra_add_router),
+       (ospf_intra_add_transit), (ospf_intra_add_stub),
+       (ospf_route_table_dump), (show_ip_ospf_route_network),
+       (show_ip_ospf_route_router), (ospf_asbr_route_cmp),
+       (ospf_prune_unreachable_routers):
+       * ospf_spf.c (ospf_rtrs_print):
+       * ospfd.c (ospf_rtrs_free):  Fix the struct change above.
+
+2000-09-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_network.c (ospf_serv_sock_init): Enclose SO_BINDTODEVICE
+       with ifdef.
+
+2000-09-13  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_ism.c (ospf_elect_dr), (ospf_elect_bdr):  Fix DR election.
+
+       * ospf_network.c (ospf_serv_sock_init):  Add socket option
+       SO_BINDTODEVICE on read socket.
+
+       * ospf_packet.c (ospf_hello):  Ignore Hello packet if E-bit does
+       not match.
+
+       * ospfd.c (ospf_area_check_free), (ospf_area_get),
+       (ospf_area_add_if):  New function added.
+       
+2000-09-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_route.c (ospf_intra_add_router): Update ABR and ASBR router
+       count.
+
+       * ospf_spf.c (ospf_spf_init): Rest ABR and ASBR router count
+       starting SPF calculation.
+
+       * ospfd.h (struct ospf_area): Add ABR and ASBR router count.
+
+2000-09-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.c (ospf_area_id_cmp): New area structure is sorted by area
+       ID.
+
+       * ospf_lsa.c (ospf_router_lsa_originate): For OSPF MIB update
+       lsa_originate_count.
+       (ospf_network_lsa_originate): Likewise.
+       (ospf_summary_lsa_originate): Likewise.
+       (ospf_summary_asbr_lsa_originate): Likewise.
+       (ospf_external_lsa_originate): Likewise.
+
+2000-09-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_snmp.c (ospf_variables): ospfRouterID's type RouterID
+       syntax is IpAddress.
+       (ospf_admin_stat): New function for OSPF administrative status
+       check.
+
+2000-09-10  Jochen Friedrich <jochen@scram.de>
+
+       * ospf_snmp.c: Implement OSPF MIB skeleton.
+
+2000-09-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_snmp.c: New file is added.
+
+2000-09-07  David Lipovkov <davidl@nbase.co.il>
+
+       * ospf_zebra.c (ospf_interface_delete): Add pseudo interface
+       treatment.
+
+       * ospf_interface.c (interface_config_write): Likewise.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+2000-08-17  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospfd.c (ospf_area_free):  Remove virtual link configuration only
+       when Area is removed.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.c (network_area): Revert check for EXTERNAL_INFO
+       (ZEBRA_ROUTE_CONNECT).
+       (no_network_area): Likewise.
+
+2000-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospfd.h (struct ospf): Add distance_table and
+       distance_{all,intra,inter,external}.
+
+       * ospf_zebra.c: Add OSPF distance related functions.
+
+2000-08-15  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_asbr.c (ospf_external_info_find_lsa):  New function added.
+
+       * ospf_lsa.c (ospf_default_external_info),
+       (ospf_default_originate_timer), (ospf_external_lsa_refresh_default):
+       New function added.
+
+       * ospf_zebra.c
+       (ospf_default_information_originate_metric_type_routemap),
+       (ospf_default_information_originate_always_metric_type_routemap):
+       Change name and add route-map function.
+       (ospf_default_information_originate_metric_routemap),
+       (ospf_default_information_originate_routemap),
+       (ospf_default_information_originate_type_metric_routemap):
+       New DEFUN added.
+
+2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_zebra.c (zebra_interface_if_set_value): Change ifindex
+       restore size from two octet to four.
+
+2000-08-14  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_ase.c (ospf_ase_incremental_update):  Implement incremental
+       AS-external-LSA in 16.6 of RFC2328.
+
+2000-08-14  Matthew Grant  <grantma@anathoth.gen.nz>
+
+       * ospf_interface.c (ospf_if_get_output_cost):  Change cost
+       calculation algorithm.
+
+       * ospf_packet (ospf_ls_upd):  Fix problem of LSA retransmitting.
+
+2000-08-11  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_lsa.c (ospf_maxage_lsa_remover):  Fix maxage remover for
+       AS-external-LSAs.
+
+2000-08-10  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (auto_cost_reference_bandwidth):  New DEFUN added.
+       `auto-cost reference-bandwidth' OSPF router command added.
+
+2000-08-08  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_routemap.c (ospf_route_map_update):  New function added.
+       Add route-map event hook.
+
+2000-08-08  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_zebra.c (ospf_distribute_check_connected):  If redistribute
+       prefix is connected route on OSPF enabled interface, suppress to
+       announce it.
+
+2000-08-08  Matthew Grant  <grantma@anathoth.gen.nz>
+
+       * ospf_interface.c (ospf_if_get_output_cost):
+       New function added.  Handle bandwidth parameter for cost
+       calculation.
+
+2000-08-08  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_interface.c (interface_config_write):  Show interface
+       configuration regardless interface is down.
+
+       * ospf_ase.c (ospf_ase_caocluate_route):  Whole rewritten external
+       route calculate function.
+
+2000-08-08  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_routemap.c:  New file added.
+
+       * ospf_asbr.c (ospf_reset_route_map_set_values),
+       (ospf_route_map_set_compare):  New function added.
+
+       * ospf_lsa.c (ospf_external_lsa_body_set):  Set routemap metric
+       with AS-external-LSA.
+
+2000-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_ase.c (ospf_ase_calculate_route_add): Pass new->cost to
+       ospf_zebra_add as metric.
+       (ospf_ase_calculate_route_add): Likewise.
+
+       * ospf_route.c (ospf_route_install): Pass or->cost to
+       ospf_zebra_add as metric.
+
+       * ospf_zebra.c (ospf_zebra_add): Add metric arguemnt.
+       (ospf_zebra_delete): Likewise.
+
+2000-08-03  Matthew Grant  <grantma@anathoth.gen.nz>
+
+       * ospf_flood.c (ospf_flood_delayed_lsa_ack):  New function added.
+       Dispatch delayed-ACK with flooding AS-external-LSA across virtual
+       link.
+
+2000-07-31  Matthew Grant  <grantma@anathoth.gen.nz>
+
+       * ospfd.c (show_ip_ospf_area):  Fix lack of VTY_NEWLINE when
+       `show ip ospf'.
+
+       * ospf_interface.c (ospf_if_free):  Fix bug of crash with
+       Point-to-Point interface.
+
+2000-07-27  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_flood.c (ospf_process_self_originated_lsa):
+       Make sure to clear LSA->param (redistributed external information)
+       before refreshment.
+
+2000-07-27  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospfd.c (refresh_group_limit), (refresh_per_slice),
+       (refresh_age_diff):  New defun added.  Refresher related parameter
+       can be configurable.
+
+2000-07-27  Akihiro Mizutani  <mizutani@dml.com>
+
+       * ospf_interface.c (interface_config_write):  Print `description'
+       config directive to work.
+
+2000-07-24  Akihiro Mizutani  <mizutani@dml.com>
+
+       * ospf_interface.c (ospf_if_init): Use install_default for
+       INTERFACE_NODE.
+
+2000-07-24  Gleb Natapov  <gleb@nbase.co.il>
+       
+       * ospf_packet.c (ospf_ls_upd_send_list), (ospf_ls_upd_send_event),
+       (ospf_ls_ack_send_list), (ospf_ls_ack_send_event): New function added.
+       This make sending always as many LS update/Ack combined in one ospf
+       packet.
+
+2000-07-24  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_packet.c (ospf_ls_upd_list_lsa):  Set NULL to lsa->area if 
+       LSA is AS-external-LSA.
+
+       * ospf_nsm.c (nsm_reset_nbr):  Do not cancel Inactivity timer.
+
+2000-07-21  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_zebra.c (ospf_default_originate_timer):  Set timer for
+       `default-information originate'.  Fix some default originate
+       related functions.
+
+2000-07-12  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (stream_put_ospf_metric):  New function added.
+
+2000-07-12  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (show_ip_ospf_database_router),
+       (show_ip_ospf_database_network), (show_ip_ospf_database_summary),
+       (show_ip_ospf_database_summary_asbr), (show_ip_ospf_database_externel),
+       (show_router_lsa), (show_any_lsa), (show_router_lsa_self),
+       (show_any_lsa_self):  Functions removed.
+
+       (show_lsa_prefix_set), (show_lsa_detail_proc), (show_lsa_detail),
+       (show_lsa_detail_adv_router_proc), (show_lsa_detail_adv_router):
+       New functions added.  Replace above functions.
+
+       (show_ip_ospf_database_all), (show_ip_ospf_database_self_originated):
+       Functions removed.
+       (show_ip_ospf_database_summary):  New functions added.  Replace
+       above functions.
+
+       (show_ip_ospf_database_cmd):  DEFUN rearranged.
+       (show_ip_ospf_database_type_id_cmd),
+       (show_ip_ospf_database_type_id_adv_router_cmd),
+       (show_ip_ospf_database_type_is_self_cmd):  New ALIASes added.
+       (show_ip_ospf_database_type_adv_rotuer_cmd):  New DEFUN added.
+       (show_ip_ospf_database_type_self_cmd):  New ALIAS added.
+
+2000-07-11  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_asbr.c (ospf_external_info_new),
+       (ospf_external_info_free):  New functions added.
+
+       * ospf_lsa.h (ospf_lsa):  Add new member `void *param' to set
+       origination parameter for external-LSA.
+       Remove member `redistribute'.
+
+       * ospf_zebra.c (ospf_redistirbute_set):  When `redistribute'
+       command executed, metric and metric-type values are overridden.
+       If one of those is changed refresh AS-external-LSAs for appropriate
+       type.
+
+2000-07-11  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_lsa.c (ospf_summary_lsa_refresh),
+       (ospf_summary_asbr_lsa_refresh):  Make sure to refresh summary-LSAs.
+
+       * ospf_abr.c (set_metric):  New function added.
+
+2000-07-07  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_zebra.c (ospf_default_information_originate_metric_type),
+       (ospf_default_information_originate_type_metric):  New defun added.
+       Metic and Metric type can be set to default route.
+       (ospf_default_information_originate_always_metric_type):
+       (ospf_default_information_originate_always_type_metric):
+       New defun added.  Metric and Metric type can be set to default
+       always route.
+       
+       * ospf_zebra.c (ospf_default_metric), (no_ospf_default_metric):
+       New defun added.
+
+2000-07-06  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_flood.c (ospf_flood_through_area):  Fix bug of considering
+       on the same interface the LSA was received from.
+
+2000-07-06  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospfd.c (ospf_config_write):  Fix bug of printing `area stub'
+       command with `write mem'.
+
+       * ospfd.c (no_router_ospf):  Remove installed routes from zebra.
+
+       * ospf_zebra.c (ospf_interface_delete):  Fix function to handle
+       zebra interface delete event.
+
+2000-07-06  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_zebra.c (ospf_default_information_originate),
+       (ospf_default_information_originate_always):  New DEFUN added.
+
+2000-07-05  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_route.c (ospf_terminate):  Make sure to remove external route
+       when SIGINT received.
+
+2000-07-03  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_flood.c, ospf_ism.c, ospf_lsa,c, ospfd.c:  Make sure to free
+       many structure with `no router ospf'.
+
+2000-06-30  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_neighbor.c (ospf_nbr_new),
+       ospf_nsm.c (nsm_timer_set):  Start LS update timer only
+       when neighbor enters Exchange state.
+
+2000-06-29  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_nsm.c (nsm_timer_set), (nsm_exchange_done),
+       ospf_packet.c (ospf_db_desc_proc):
+       Do not cancel DD retransmit timer when Master.
+
+2000-06-29  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_abr.c (ospf_abr_announce_network_to_area),
+       (ospf_abr_announce_rtr_to_area)
+       ospf_ase.c (ospf_ase_rtrs_register_lsa),
+       ospf_flood.c (ospf_process_self_originated_lsa),
+       (ospf_flood_through_area), (ospf_ls_request_delete),
+       ospf_interface.c (ospf_if_free),
+       ospf_ism.c (ism_change_status),
+       ospf_lsa.c (ospf_router_lsa_update_timer),
+       (ospf_router_lsa_install), (ospf_network_lsa_install),
+       (ospf_lsa_maxage_delete), (ospf_lsa_action),
+       (ospf_schedule_lsa_flood_area),
+       ospf_nsm.c (nsm_change_status),
+       ospf_packet.c (ospf_make_ls_req_func), (ospf_make_ls_ack):
+       Use ospf_lsa_{lock,unlock} for all looking-up of LSA.
+
+       * ospf_flood.c (ospf_ls_request_free):  Function deleted.
+
+       * ospf_lsa.c (ospf_discard_from_db):  New function added.
+
+2000-06-26  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.h (ospf): struct member `external_lsa' name changed to
+       `lsdb'.
+
+2000-06-26  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_lsa_install), (ospf_router_lsa_install),
+       (ospf_network_lsa_install), (ospf_summary_lsa_install),
+       (ospf_summary_asbr_lsa_install), (ospf_external_lsa_install):
+       Functions re-arranged.
+
+       * ospf_lsa.c (IS_LSA_MAXAGE), (IS_LSA_SELF):  Macro added.
+       
+2000-06-20  Michael Rozhavsky <mike@nbase.co.il>
+
+       * ospf_packet.c (ospf_ls_req), (ospf_ls_upd), (ospf_ls_ack):  Add
+       verification of LS type.
+
+2000-06-20  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_ase.c (ospf_ase_calculate_timer):  Add more sanity check
+       whether rn->info is NULL.
+
+2000-06-20  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (show_ip_ospf_interface_sub):  Show Router-ID of both
+       DR and Backup correctly with `show ip ospf interface' command.
+
+2000-06-20  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_lsa_lock), (ospf_lsa_unlock),
+       (ospf_lsa_discard):  These functions are used for avoiding
+       unexpected reference to freed LSAs.
+
+2000-06-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_packet.c (ospf_ls_upd): Initialize lsa by NULL to avoid
+       warning.
+
+2000-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_ase.h (ospf_ase_rtrs_register_lsa): Add prototype.
+
+2000-06-12  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_external_lsa_install):  Make sure to register
+       LSA to rtrs_external when replacing AS-external-LSAs in LSDB.
+       Fix core dump.
+
+2000-06-10  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsdb.c (id_to_prefix), (ospf_lsdb_hash_key),
+       (ospf_lsdb_hash_cmp), (ospf_lsdb_new), (ospf_lsdb_iterator),
+       (lsdb_free), (ospf_lsdb_free), (ospf_lsdb_add), (ospf_lsdb_delete),
+       (find_lsa), (ospf_lsdb_lookup), (find_by_id),
+       (ospf_lsdb_lookup_by_id), (ospf_lsdb_lookup_by_header):  Functinos
+       removed for migration to new_lsdb.
+
+       * ospf_lsa.c (ospf_summary_lsa_install),
+       (ospf_summary_asbr_lsa_install), (ospf_maxage_lsa_remover),
+       (ospf_lsa_maxage_walker), (ospf_lsa_lookup),
+       (ospf_lsa_lookup_by_id):  Use new_lsdb instead of ospf_lsdb.
+       (count_lsa), (ospf_lsa_count_table), (ospf_lsa_count),
+       (ospf_get_free_id_for_prefix):  Funcitions removed.
+       
+2000-06-09  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_ism.c (ism_interface_down):  Prevent some unneeded DR changes.
+
+       * ospf_packet.c (ospf_db_desc_proc):  Fix memory leak.
+       (ospf_hello):  Always copy router-ID when hello is received.
+
+2000-06-08  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_lsa.h (struct ospf_lsa): Add member of pointer to struct
+       ospf_area.
+
+2000-06-08  Michael Rozhavsky <mike@nbase.co.il>
+
+       * ospf_ase.c (ospf_asbr_route_same):  New function added.
+       This function makes sure external route calculation more 
+       precisely.
+
+2000-06-07  Michael Rozhavsky <mike@nbase.co.il>
+
+       * ospf_ism.c (ism_change_status):  Use ospf_lsa_flush_area for
+       network-LSA deletion instead of using ospf_lsdb_delete.
+       Also cancel network-LSA origination timer.
+
+2000-06-07  Levi Harper  <lharper@kennedytech.com>
+
+       * ospf_interface.c (ospf_if_down): Close read fd when an interface
+       goes down.
+
+2000-06-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_asbr.c (ospf_external_info_lookup): Add explicit brace for
+       avoid ambiguous else.
+
+       * ospf_flood.c (ospf_external_info_check): Likewise.
+
+2000-06-05  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_nsm.c (nsm_adj_ok):  Fix bug of DR election.
+
+2000-06-04  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_zebra.c (ospf_default_information_originate),
+       (no_ospf_default_information_originate):  New DEFUN added.
+
+2000-06-03  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.h, ospf_asbr.h (external_info):  Struct moved from
+       ospf_lsa.h to ospf_asbr.h.
+
+       * ospf_lsa.c, ospf_asbr.c (ospf_external_info_add),
+       (ospf_external_info_delete):  Function moved from ospf_lsa.c
+       to ospf_asbr.c.
+
+2000-06-03  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_flood.c (ospf_external_info_check):  New function added.
+       (ospf_process_self_orignated_lsa):  Make sure to flush
+       self-originated AS-external-LSA, when router reboot and no longer
+       originate those AS-external-LSA.
+
+2000-06-02  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_network.c (ospf_serv_sock):  Remove SO_DONTROUTE
+       socket option.
+
+       * ospf_packet.c (ospf_write):  Set MSG_DONTROUTE flag for
+       unicast destination packets.
+
+2000-06-02  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsdb.c (new_lsdb_delete):  Delete entry from LSDB only when
+       specified LSA matches.
+
+2000-06-02  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_network.c (ospf_serv_sock):  Set SO_DONTROUTE
+       socket option.
+
+2000-06-01  Akihiro Mizutani  <mizutani@dml.com>
+
+       * ospf_dump.c:  Replace string `Debugging functions\n' with DEBUG_STR.
+       Replace string `OSPF information\n' with OSPF_STR.
+
+2000-06-01  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsdb.[ch]:  Use new_lsdb struct for network-LSA instead of
+       ospf_lsdb.
+
+2000-06-01  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_dump.c (config_debug_ospf_packet), (config_debug_ospf_event),
+       (config_debug_ospf_ism), (config_debug_ospf_nsm),
+       (config_debug_ospf_lsa), (config_debug_ospf_zebra),
+       (term_debug_ospf_packet), (term_debug_ospf_event),
+       (term_debug_ospf_ism), (term_debug_ospf_nsm),
+       (term_debug_ospf_lsa), (term_debug_ospf_zebra):  Repalce debug_ospf_*
+       variable to use for debug option flags.
+       
+       (debug_ospf_packet), (debug_ospf_ism), (debug_ospf_nsm),
+       (debug_ospf_lsa), (debug_ospf_zebra):  Set {config,term}_debug_*
+       flags when vty->node is CONFIG_NODE, otherwise set only term_debug_*
+       flags.
+
+       * ospf_dump.h (CONF_DEBUG_PACKET_ON), (CONF_DEBUG_PACKET_OFF),
+       (TERM_DEBUG_PACKET_ON), (TERM_DEBUG_PACKET_OFF),
+       (CONF_DEBUG_ON), (CONF_DEBUG_OFF), (IS_CONF_DEBUG_OSPF_PACKET),
+       (IS_CONF_DEBUG_OSPF):  New Macro added.
+       
+2000-05-31  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (clear_ip_ospf_neighbor):  New DEFUN added.
+       Currently this command is used for only debugging.
+
+       * ospf_nsm.c (nsm_change_status):  Make sure thread cancellation
+       for network-LSA when DR has no full neighbors.
+       
+       * ospf_nsm.c (ospf_db_summary_clear):  New function added.
+
+2000-05-30  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsdb.c (new_lsdb_insert):  LSAs are always freed by
+       maxage_lsa_remover when LSA is replaced.
+
+2000-05-25  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all):  Add argument
+       `struct ospf_area' to remove LSA from Link State retransmission list
+       of neighbor from only one Area.
+
+2000-05-24  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_lsdb.c (ospf_lsdb_add):  Preserve flags field when
+       overriting old LSA with new LSA.
+
+2000-05-24  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_lsa.c (ospf_router_lsa_body_set):  Fix bug of router-LSA
+       size calculation.
+
+2000-05-22  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_route.c (ospf_intra_add_stub):
+       * ospf_spf.h (struct vertex):  Use u_int32_t for distance (cost)
+       value instead of u_int16_t.
+
+2000-05-22  Axel Gerlach <agerlach@datus.datus.com>
+
+       * ospf_ia.c (ospf_ia_network_route):  Fix bug of Inter-area route
+       equal cost path calculation.
+
+2000-05-21  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_ase.c (ospf_ase_calculate_route_delete):  New function added.
+       Make sure, when rotuer route is deleted, related external routes
+       are also deleted.
+
+2000-05-20  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (ospf_interface_down):  Make sure interface flag is disable
+       and set fd to -1.
+
+2000-05-16  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_asbr.c (ospf_asbr_should_announce), (ospf_asbr_route_remove):
+       Functions removed.
+
+       * ospfd.h (EXTERNAL_INFO):  Macro added.
+       Substitute `ospf_top->external_info[type]' with it.
+
+2000-05-16  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_rtrs_external_remove):  New function added.
+
+2000-05-14  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all)
+       * ospf_lsdb.c (new_lsdb_insert)
+       * ospf_packet.c (ospf_ls_ack):  Fix database synchonization problem.
+
+2000-05-14  Gleb Natapov <gleb@nbase.co.il>
+
+       * ospf_lsa.h (tv_adjust), (tv_ceil), (tv_floor), (int2tv),
+       (tv_add), (tv_sub), (tv_cmp):  Prototype definition added.
+
+       * ospf_nsm.h (ospf_db_summary_delete_all):  Prototype definition added.
+
+2000-05-13  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.[ch] (ospf_lsa):  struct timestamp type is changed from
+       time_t to struct timeval.
+       (tv_adjust), (tv_ceil), (tv_floor), (int2tv), (tv_add),
+       (tv_sub), (tv_cmp):  timeval utillity functions added.
+
+2000-05-12  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.[ch] (ospf_schedule_update_router_lsas):  Delete function.
+       Change to use macro OSPF_LSA_UPDATE_TIMER instead of using
+       this function.
+       router-LSA refresh timer related stuff is re-organized.
+
+2000-05-10  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_interface.c (ospf_vl_set_params):
+       * ospf_packet.c (ospf_check_network_mask):
+       * ospf_spf.[ch] (ospf_spf_next):
+       Remove field address from `struct vertex', and search for peer
+       address of virtual link in function `ospf_vl_set_params' instead.
+
+2000-05-10  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_packet.c (ospf_ls_upd):  Fix some memory leak related LSA.
+
+2000-05-08  Thomas Molkenbur  <tmo@datus.com>
+
+       * ospf_packet.c (ospf_packet_dup):  Replace ospf_steram_copy()
+       with ospf_stream_dup() to fix memory leak.
+
+2000-05-08  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_flood.c (ospf_flood_through_area):  Fix the problem of
+       LSA update without DROther.
+
+2000-05-04  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_spf.c (ospf_vertex_free):  Fix memory leak of SPF calculation.
+
+2000-05-03  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_neighbor.c (ospf_db_summary_add):  Use new_lsdb struct
+       instead linked-list.
+       (ospf_db_summary_count), (ospf_db_summary_isempty):
+       New function added.
+
+       * ospf_lsa.c (ospf_rotuer_lsa):  Re-arrange and divide functions.
+
+2000-05-02  Gleb Natapov  <gleb@nbase.co.il>
+
+       * ospf_lsdb.c (new_lsdb_cleanup):  Fix memory leak.  When LSDB are
+       not needed any more, then free them.
+
+2000-05-02  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (timers_spf), (no_timers_spf):  New defun added.
+       SPF calculation timers related stuff is rearranged.
+
+       * ospf_spf.c (ospf_spf_calculate_timer_add):  Function removed.
+       SPF timer is scheduled by SPF calculation delay and holdtime
+       configuration variable.
+
+       * ospf_lsa.c (ospf_external_lsa_nexthop_get):  Set AS-external-LSA's
+       forwarding address when nexthop learned by other protocols is
+       in the OSPF domain. 
+
+       * ospf_zebra.c (ospf_redistribute_source_metric_type),
+       (ospf_redistribute_source_type_metric):  Re-arrange DEFUNs and
+       ALIASes.
+
+2000-05-01  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_flood.c (ospf_ls_retransmit_count),
+       (ospf_ls_retransmit_isempty):  New function added.
+
+       (ospf_ls_retransmit_add), (ospf_ls_retransmit_delete),
+       (ospf_ls_retransmit_clear), (ospf_ls_retransmit_lookup),
+       (ospf_ls_retransmit_delete_all), (ospf_ls_retransmit_delete_nbr_all),
+       (ospf_ls_retransmit_add_nbr_all):  Replace these functions to use
+       new_lsdb.
+
+2000-04-29  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (no_network_area):  Add check Area-ID whether specified
+       Area-ID with prefix matches config.
+
+2000-04-27  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_maxage_lsa_remover): Fix problem of
+       remaining withdrawn routes on zebra.
+
+2000-04-25  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_nsm.c (nsm_kill_nbr), (nsm_ll_down), (nsm_change_status),
+       (ospf_nsm_event):  Fix network-LSA re-origination problem.
+
+2000-04-24  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_nsm.c (ospf_db_desc_timer): Fix bug of segmentation fault
+       with DD retransmission.
+
+       * ospf_nsm.c (nsm_kill_nbr): Fix bug of re-origination when
+       a neighbor disappears.
+
+2000-04-23  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_abr.c (ospf_abr_announce_network_to_area):  Fix bug of
+       summary-LSAs reorigination.  Correctly copy OSPF_LSA_APPROVED
+       flag to new LSA. when summary-LSA is reoriginatd.
+
+       * ospf_flood.c (ospf_flood_through_area):  Fix bug of flooding
+       procedure.  Change the condition of interface selection.
+
+2000-04-21  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_refresher_register_lsa): Fix bug of refresh never
+       occurs.
+
+       * ospfd.c (show_ip_ospf_neighbor_id): New defun added.
+       `show ip ospf neighbor' related commands are re-arranged.
+
+2000-04-20  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_dump.c (debug_ospf_zebra): New defun added.
+       Suppress zebra related debug information.
+
+2000-04-19  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_zebra.c (ospf_distribute_list_update_timer),
+       (ospf_distribute_list_update), (ospf_filter_update):
+       New function added.  Re-organize `distribute-list' router ospf
+       command.
+
+2000-04-13  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_packet.c (ospf_make_ls_upd): Add check for MAX_AGE.
+
+2000-04-14  Michael Rozhavsky  <mike@nbase.co.il>
+
+       * ospf_packet.c (ospf_make_ls_upd): Increment LS age by configured 
+       interface transmit_delay.
+
+2000-04-14  Sira Panduranga Rao  <pandu@euler.ece.iisc.ernet.in>
+
+       * ospf_interface.c (ip_ospf_cost), (no_ip_ospf_cost):
+       Add to schedule router_lsa origination when the interface cost changes.
+
+2000-04-12  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_refresher_register_lsa),
+       (ospf_refresher_unregister_lsa): Fix bug of core dumped.
+
+       * ospfd.c (no_router_ospf): Fix bug of core dumped.
+
+2000-03-29  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_nsm.c (nsm_oneway_received): Fix bug of MS flag unset.
+
+2000-03-29  Michael Rozhavsky <mike@nbase.co.il>
+
+       * ospf_lsa.c (ospf_network_lsa):
+       * ospf_nsm.c (ospf_nsm_event): Fix bug of Network-LSA originated
+       in stub network.
+
+2000-03-28  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_nsm.c (nsm_bad_ls_req), (nsm_seq_number_mismatch),
+       (nsm_oneway_received): Fix bug of NSM state flapping between
+       ExStart and Exchange.
+
+2000-03-28  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_packet.h (strcut ospf_header): Fix the size of ospf_header,
+       change u_int8_t to u_char.
+
+2000-03-27  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_lsa.c (ospf_lsa_checksum): Take care of BIGENDIAN architecture.
+
+2000-03-27  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (ospf_interface_run): Make sure Address family matches.
+
+2000-03-26  Love <lha@s3.kth.se>
+
+       * ospf_packet.c (ospf_write): Chack result of sendto().
+
+2000-03-26  Sira Panduranga Rao  <pandu@euler.ece.iisc.ernet.in>
+
+       * ospf_nsm.c (nsm_oneway_received): Fix bug of 1-WayReceived in NSM.
+
+2000-03-23  Libor Pechacek  <farco@clnet.cz>
+
+       * ospf_lsa.c (ospf_network_lsa)
+       * ospf_lsdb.c (new_lsdb_insert): Fix bug of accessing to
+       unallocated memory.
+
+2000-03-23  Toshiaki Takada  <takada@zebra.org>
+
+       * ospfd.c (ospf_config_write): Fix bug of duplicate line for
+       `area A.B.C.D authentication'.
+
+2000-03-22  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_debug.c (debug_ospf_lsa), (no_debug_ospf_lsa): Defun added.
+       Suppress all zlog related to LSAs with this config option.
+
+2000-03-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ospf_nsm.c (ospf_nsm_event): Add check for NSM_InactivityTimer.
+
+2000-03-21  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_packet.c (ospf_ls_upd_timer), (ospf_ls_req):
+       Fix bug of memory leak about linklist.
+
+       * ospf_flood.c (ospf_flood_through_area): Likewise.
+
+2000-03-18  Sira Panduranga Rao  <pandu@euler.ece.iisc.ernet.in>
+
+       * ospf_flood.c (ospf_ls_retransmit_lookup): Add checksum comparison
+       to identify LSA uniquely.  This fix routes lost.
+
+2000-03-18  Toshiaki Takada  <takada@zebra.org>
+
+       * ospf_ase.c (ospf_find_asbr_route): Add sanity check with router
+       routing table.
+
+2000-03-17  Alex Zinin  <zinin@amt.ru>
+       
+        * ospf_spf.[ch]: Bug fix.
+        The 2nd stage of Dijkstra could consider one vertex
+        more than once if there is more than one link
+        between the routers, thus adding extra CPU overhead
+        and extra next-hops.
+        Fixed.
+
+2000-03-15  Sira Panduranga Rao  <pandu@euler.ece.iisc.ernet.in>
+
+        * ospf_nsm.c (nsm_inactivity_timer): Changed to call nsm_kill_nbr().
+
+2000-03-14  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_route.c (ospf_route_copy_nexthops): Fix bug of memory leak of
+        ospf_path.  Actually ignore merging ospf_route with completely same 
+        paths.
+
+2000-03-12  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (show_as_external_lsa_detail): fix bug of 
+        external route tag byte order.
+
+2000-03-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsdb.c (ospf_lsdb_insert): New function added.
+
+2000-03-09  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (ospf_external_lsa_install),
+        (ospf_lsa_lookup), (show_ip_ospf_database_all),
+        (show_ip_ospf_database_self_originate): Use struct new_lsdb for
+        LSDB of AS-external-LSAs instead of ospf_lsdb.
+
+        * ospf_lsa.c (ospf_lsa_unique_id): New function added.
+        Use for assigning Unique Link State ID instead of
+        ospf_get_free_id_for_prefix().
+
+2000-03-09  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ase.c (ospf_ase_calculate_timer): Fix bug of segmentation
+        fault reported by George Bonser <george@siteROCK.com>.
+
+2000-03-07  Libor Pechacek  <farco@clnet.cz>
+
+        * ospfd.c (ospf_interface_down): Fix bug of segmentation fault.
+
+2000-03-06  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_route.c (ospf_route_cmp): Change meaning of return values.
+
+2000-03-02  Alex Zinin <zinin@amt.ru>
+        * ospfd.h, ospf_ia.h
+        New Shortcut ABR code. Now area's flag can be configured
+        with Default, Enable, and Disable values.
+        More info will be in the new ver of I-D soon (see IETF web).
+
+2000-02-25  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (ospf_lsa_header_set), (ospf_external_lsa_body_set),
+        (osfp_external_lsa_originate), (ospf_external_lsa_queue),
+        (ospf_external_lsa_originate_from_queue): New function added.
+        (ospf_external_lsa): Function removed.
+
+        * ospf_zebra.c (ospf_zebra_read_ipv4): Originate AS-external-LSA
+        when listen a route from Zebra, instead creating external route.
+
+        * ospf_asbr.c (ospf_asbr_route_add_flood_lsa),
+        (ospf_asbr_route_add_queue_lsa),
+        (ospf_asbr_route_install_lsa), (ospf_asbr_route_add):
+        Functions removed.
+
+        * ospf_ase.c (process_ase_lsa): Function will not be used.
+        (ospf_ase_calculate), (ospf_ase_calculate_route_add),
+        (ospf_ase_calculate_new_route), (ospf_ase_caluculate_asbr_route):
+        process_ase_lsa () is separated to these functions.
+
+        OSPF AS-external-LSA origination is whole re-organized.
+
+2000-02-18  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_ls_upd): Fix bug of OSPF LSA memory leak.
+
+        * ospf_asbr.c (ospf_asbr_route_add_flood_lsa),
+        (ospf_asbr_route_add_queue_lsa): Fix bug of OSPF external route
+        memory leak.
+
+2000-02-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_asbr.c (ospf_asbr_route_install_lsa): Re-calculate LSA
+        checksum after change Advertised Router field.
+
+2000-02-09  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_asbr.c (ospf_external_route_lookup): Add new function.
+
+2000-02-08  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (ospf_router_id_get), (ospf_router_id_update),
+        (ospf_router_id_update_timer): Router ID decision algorithm is changed.
+        Router ID is chosen from all of eligible interface addresses even if
+        it is not enable to OSPF.
+
+2000-02-08  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_asbr.c (ospf_asbr_route_add): Function divided to
+        ospf_asbr_route_add_flood_lsa, ospf_asbr_route_add_queue_lsa and
+        ospf_asbr_route_install_lsa.  If Router-ID is not set, then LSA is
+        waited to install to LSDB.
+        `0.0.0.0 adv_router' AS-external-LSA origination bug was fixed.
+
+2000-02-01  Sira Panduranga Rao  <pandu@euler.ece.iisc.ernet.in>
+
+        * ospf_flood.c (ospf_ls_retransmit_lookup): Compare LS seqnum
+        in the ACK before deleting.
+
+        * ospf_packet.c (ospf_hello): Reset the flags after a shutdown
+        and no shutdown of the interface.
+
+2000-01-31  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_ls_req): Send multiple Link State Update
+        packets respond to a Link State Request packet.
+
+        * ospfd.c (show_ip_ospf_neighbor_detail_sub): Show thread state.
+
+        * ospf_interface.c (ospf_vl_new): Crash when backbone area
+        is not configured and set virtual-link to no-backbone area,
+        bug fixed.
+
+2000-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_neighbor.h (struct ospf_neighbor): Add pointer to last send
+        LS Request LSA.
+
+        * ospf_packet.c (ospf_ls_upd): Comment out LS request list
+        treatment.  That should be done in OSPF flooding procedure.
+
+        * ospf_flood.c (ospf_flood_through_area): Enclose
+        ospf_check_nbr_loding inside if-else close.
+
+2000-01-31  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_make_ls_upd): Fix bug of #LSAs counting.
+
+2000-01-29  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_make_md5_digest): Fix bug of md5 authentication.
+
+2000-01-28  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (show_ip_ospf): Show Number of ASE-LSAs.
+
+2000-01-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_packet.c (ospf_make_db_desc): Don't use rm_list for
+        removing LSA from nbr->db_summary.
+
+2000-01-27  Sira Panduranga Rao <pandu@euler.ece.iisc.ernet.in>
+
+        * ospf_packet.c (ospf_ls_upd_send): Set AllSPFRouters to
+        destination when the link is point-to-point.
+        (ospf_ls_ack_send_delayed): Likewise.
+
+2000-01-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_flood.c (ospf_ls_request_delete_all): Fix bug of next
+        pointer lookup after the node is freed.
+
+2000-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_asbr.c (ospf_asbr_route_add): Instead of scanning all AS
+        external route, use ospf_top->external_self.
+
+2000-01-27  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (ospf_forward_address_get): New function added.
+
+        * ospf_asbr.c (ospf_asbr_check_lsas): Originate AS-external-LSA
+        only when it should be replaced.
+
+2000-01-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_flood.c (ospf_ls_retransmit_clear): Delete list node.
+
+        * ospf_lsa.c (ospf_lsa_free): Reduce logging message using
+        ospf_zlog value.
+
+        * ospf_ism.c (ism_change_status): Fix bug of DR -> non DR status
+        change.  Self originated LSA is freed but not deleted from lsdb.
+
+2000-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_ism.c (ism_interface_down): Don't use router_id for
+        detecting self neighbor structure.  Instead of that compare
+        pointer itself.
+
+        * ospf_neighbor.c (ospf_nbr_free): Cancel all timer when neighbor
+        is deleted.
+        (ospf_nbr_free): Free last send packet.
+
+        * ospf_neighbor.h (struct ospf_neighbor): Remove host strucutre.
+        Instead of that src is introduced.
+
+        * ospf_nsm.h: Enclose macro defenition with do {} while (0).
+
+2000-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospfd.c: Change part of passive interface implementation.  For
+        passive interface just disabling sending/receiving Hello on the
+        interface.
+
+2000-01-16  Kai Bankett <kai.bankett@vew-telnet.net>
+
+        * ospf_interface.h (OSPF_IF_PASSIVE): Add passive flag.
+        * ospf_interface.c (ospf_if_lookup_by_name): Add new function.
+        * ospf_lsa.c (ospf_router_lsa): Skip passive interface.
+        * ospfd.c (passive_interface): New command passive-interface is
+        added.
+        (ospf_config_write): Print passive interface.
+
+2000-01-15  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.h (crypt_key): New struct added to store
+        multiple cryptographic autheitication keys.
+        (ospf_interface): struct changed.
+
+        * ospf_interface.c: ospf_crypt_key_new, ospf_crypt_key_add,
+        ospf_crypt_key_lookup, ospf_crypt_key_delete: new functions added.
+
+        * ospf_packet.c (ip_ospf_message_digest_key): Changed to store
+        multiple cryptographic authentication keys.
+
+2000-01-14  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.c: DEFUN (if_ospf_*) commands changed name to
+        ip_ospf_* ().
+        Old notation `ospf *' still remains backward compatibility.
+
+1999-12-29  Alex Zinin  <zinin@amt.ru>
+        * ospf_lsa.c: ospf_lsa_more_recent() bug fix
+        * ospf_nsm.c, ospf_packet.c: remove nbr data struct when
+          int goes down, also check DD flags correctly (bug fix)
+
+1999-12-28  Alex Zinin  <zinin@amt.ru>
+        * "redistribute <source> metric-type (1|2) metric <XXX>" added
+
+1999-12-23  Alex Zinin  <zinin@amt.ru>
+        * added RFC1583Compatibility flag
+        * added dynamic interface up/down functionality
+
+1999-11-19  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_neighbor.h (struct ospf_neighbor): Add member state_change
+        for NSM state change statistics.
+
+1999-11-19  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (show_ip_ospf_neighbor_detail),
+        (show_ip_ospf_neighbor_int_detail): DEFUN Added.
+
+1999-11-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_asbr.c (ospf_asbr_check_lsas): Add check of
+        lsa->refresh_list.
+
+1999-11-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ia.[ch] (OSPF_EXAMINE_SUMMARIES_ALL): Macro added.
+        This macro is expanded to ospf_examine_summaries ()
+        for SUMMARY_LSA and SUMMARY_LSA_ASBR.
+        (OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL): Macro added.
+        This macro is expanded to ospf_examine_transit_summaries ()
+        for SUMMARY_LSA and SUMMARY_LSA_ASBR.
+
+1999-11-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.[ch] (ospf_find_self_summary_lsa_by_prefix): Changed to
+        macro OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX.
+        (ospf_find_self_summary_asbr_lsa_by_prefix): Changed to
+        macro OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX.
+        (ospf_find_self_external_lsa_by_prefix): Changed to
+        macro OSPF_EXTERNAL_LSA_SELF_FIND_BY_PREFIX.
+
+1999-11-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (ospf_abr_type): ospf_abr_type_cisco, ospf_abr_type_ibm,
+        ospf_abr_type_shortcut and ospf_abr_type_standard DEFUNs are
+        combined.
+        * ospfd.c (no_ospf_abr_type): no_ospf_abr_type_cisco,
+        no_ospf_abr_type_ibm and no_ospf_abr_type_shortcut DEFUNS are
+        combined.
+
+1999-11-10  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_route.c (ospf_lookup_int_by_prefix): Move function to
+        ospf_interface.c and change name to ospf_if_lookup_by_prefix ().
+
+1999-11-01  Alex Zinin <zinin@amt.ru>
+        * ospf_packet.c 
+        some correction to LSU processing
+
+        * ospf_lsa.c ospfd.h 
+        randomize initial LSA refreshment interval
+        and limit the size of LSA-group to 10
+        to let randomization work more effectively.
+
+1999-10-31  Alex Zinin <zinin@amt.ru>
+        * ospf_interface.c 
+        cancel t_network_lsa_self
+        when freeing int structure
+
+        *  ospf_abr.c ospf_asbr.c ospf_flood.c ospf_lsa.c 
+           ospf_lsa.h ospf_lsdb.h ospfd.c ospfd.h
+
+        Summary and ASE LSA refreshment functions
+        added---LSA refreshment is paced to 70 LSAs
+        per sec to avoid link overflow. Refreshment events
+        are further randomized within a 10 sec interval
+        to avoid syncing.
+        
+        Also the sigfault of memcmp() in ospf_lsa_is_different()
+        is fixed.
+
+1999-10-30  Alex Zinin <zinin@amt.ru>
+        * ospf_nsm.c 
+        Fix the bug where MAX_AGE LSAs
+        are included into the DB summary.
+
+        * ospf_interface.c 
+        allocate 2*MTU input buffer instead of just MTU
+        for the cases when the other router mistakenly
+        sends larger packets thus causing fragmentation, etc.
+
+        * ospf_nsm.c
+        in nsm_reset_nbr() lists should be freed
+        not when they are empty.
+
+1999-10-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_zebra.c (ospf_acl_hook): Move OSPF_IS_ASBR and OSPF_IS_ABR
+        check inside of if (ospf_top).
+
+1999-10-29  Alex Zinin <zinin@amt.ru>
+        * ospf_lsa.c ospf_lsdb.c :
+        add assertion in lsa and lsa->data alloc functions,
+        as well as in lsdb_add for new->data
+
+        * ospf_lsdb.c: free hash table correctly
+
+1999-10-28  John Capo <jc@irbs.com>
+
+        * ospf_packet.h (OSPF_PACKET_MAX): Correct MAX packet length
+        calculation
+
+1999-10-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * OSPF-TRAP-MIB.txt: New file added. Edited version of RFC1850.
+
+        * OSPF-MIB.txt: New file added.  Edited version of RFC1850.
+
+1999-10-27  Alex Zinin  <zinin@amt.ru>
+        * ospfd, ospf_zebra, ospf_abr
+        "area import-list" command is added.
+        This command allows to filter the inter-area routes
+        injected into an area. Access list hook function
+        extended to invalidate area exp/imp lists.
+
+1999-10-25  Yoshinobu Inoue  <shin@nd.net.fujitsu.co.jp>
+
+        * ospfd.c (ospf_interface_run): Enable to detect P2P network
+        on an OSPF interface.
+
+1999-10-19  Jordan Mendelson  <jordy@wserv.com>
+
+        * ospf_lsdb.c (ospf_lsdb_add): Fix bug of crash
+        in ospf_ls_retransmit_lookup ().
+
+1999-10-19  Vladimir B. Grebenschikov <vova@express.ru>
+
+        * ospf_route.c: Workaround about installation of OSPF routes into
+        the zebra daemon.  Add checking of existance routes.  Free
+        ospf_top->old_table if it exists.
+
+1999-10-15  Jordan Mendelson <jordy@wserv.com>
+
+        * Add support for MD5 authentication.
+
+1999-10-12  Alex Zinin  <zinin@amt.ru>
+        * ospfd.c, ospfd.h, ospf_abr.c:
+          a new command "area export-list" was added, it allows
+          the admin. to control which intra-area routes are
+          announced to other areas by the ABR
+
+1999-10-12  Alex Zinin  <zinin@amt.ru>
+        * ospf_asbr.c (ospf_asbr_check_lsas): Fix bug of coredump
+          when "no redistribute" is used after a distribute list
+          denying some networks was used
+
+1999-10-05  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_route.c (ospf_path_dup): New function added.
+
+1999-10-05  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.[ch]: Some of VL related funciton name changed.
+
+1999-09-27  Alex Zinin  <zinin@amt.ru>
+
+        * ospf_zebra.c: Distribute-list functionality added
+
+1999-09-27  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (show_ip_ospf): Fix bug of segmentation fault when no ospf
+        instance exists.
+
+1999-09-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospfd.c (ospf_interface_down): Fix bug of misusing nextnode()
+        instead of node->next.  Reported by Hiroki Ishibashi
+        <ishibasi@dcd.abk.nec.co.jp>.
+
+        * ospf_route.c (show_ip_ospf_route): Add check for ospf is enabled
+        or not.
+
+1999-09-23  Alex Zinin  <zinin@amt.ru>
+
+        * stub area support added
+
+1999-09-23  Alex Zinin  <zinin@amt.ru>
+
+        * fwd_addr in ASE-LSAs is now set correctly
+        * ASE routing changed to check the fwd_addr
+        and skip the route if the addr points to one
+        of our interfaces to avoid loops.
+
+1999-09-22  Alex Zinin  <zinin@amt.ru>
+
+        * ospf_interface:
+        ospf_vls_in_area() added, it returns 
+        the number of VLs configured through the area
+
+        * ospf_interface.c ospf_lsa.c ospf_lsdb.c ospfd.c 
+        honor correct mem alloc
+
+1999-09-22  Alex Zinin  <zinin@amt.ru>
+
+        * memory.[ch]:
+        Some OSPF mem types added,
+        plus more info in "show mem"
+
+1999-09-21  Alex Zinin  <zinin@amt.ru>
+
+        * ospfd.c:
+        "area range substitute" added.
+        It can be used on NAT-enabled (IP-masquarade)
+        routers to announce private networks
+        from an area as public ones into the outside
+        world (not in the RFC, btw :)
+
+1999-09-21  Alex Zinin  <zinin@amt.ru>
+
+        * ospfd.c:
+        "area range suppress" added.
+        This command allows to instruct the router
+        to be silent about specific ranges, i.e.,
+        it is a method of route filtering on area
+        borders
+
+1999-09-21  Alex Zinin  <zinin@amt.ru>
+
+        * ospfd.c VLs removed when "no network area" executed
+
+1999-09-20  Alex Zinin  <zinin@amt.ru>
+
+        * ospf_ase.c bug fix for not-zero fwd_addr 
+        and directly connected routes.
+
+1999-09-20  Yon Uriarte <yon@plannet.de>
+
+        * ospf_packet.c (ospf_make_ls_req): Introduce delta value for
+        checking the length of OSPF packet exceeds MTU or not.
+
+        * ospf_lsa.c (ospf_lsa_different): Apply ntohs for checking
+        l1->data->length.
+
+1999-09-18  Alex Zinin  <zinin@amt.ru>
+
+        * ospf_lsa.c bug fix for ospf_network_lsa() to
+        include itself into the RID list
+
+1999-09-10  Alex Zinin  <zinin@amt.ru>
+
+        * Alternative ABR behaviors IBM/Cisco/Shortcut
+        implemented
+
+1999-09-10  Alex Zinin  <zinin@amt.ru>
+
+        * router and network-LSA origination
+        changed to honor MinLSInterval
+
+1999-09-08  Alex Zinin  <zinin@amt.ru>
+
+        * modified ABR behavior to honor VLs and transit
+          areas
+
+1999-09-07  Alex Zinin  <zinin@amt.ru>
+
+        * completed VL functionality
+
+1999-09-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_asbr.c: New file.
+        ospf_asbr.h: New file.
+
+        * ospf_zebra.c (ospf_redistribute_connected): Add redistribute
+        related stuff.
+
+1999-09-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospfd.h (OSPF_FLAG_VIRTUAL_LINK): Change OSPF_FLAG_VEND to
+        OSPF_FLAG_VIRTUAL_LINK for comprehensiveness.
+
+1999-09-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_spf.c (ospf_spf_register): Change name from
+        ospf_spf_route_add() to ospf_spf_register().
+        Include "ospfd/ospf_abr.h" for ospf_abr_task() prototype.
+
+1999-09-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_lsa.c (ospf_external_lsa_install): Change to update
+        lsa->data rather than install new one, when same id lsa is already
+        installed.
+
+1999-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_lsa.c (ospf_router_lsa_install): Return lsa value.
+        (ospf_network_lsa_install): Likewise.
+        (ospf_summary_lsa_install): Likewise.
+        (ospf_summary_asbr_lsa_install): Likewise.
+        (ospf_external_lsa_install): Likewise.
+
+        * ospf_spf.c (ospf_spf_calculate): Comment out debug function
+        ospf_rtrs_print().
+
+1999-08-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_spf.c (ospf_rtrs_free): Add ospf_spf_calculate() for
+        freeing rtrs.
+
+1999-08-31  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (show_ip_ospf_database_summary),
+        (show_ip_ospf_database_summary_asbr),
+        (show_ip_ospf_database_external): New function added.
+        `show ip ospf database summary',
+        `show ip ospf database asbr-summary'
+        `show ip ospf database external' command can be used.
+
+        * ospf_lsa.c (ospf_lsa_count_table): New function added.
+        (show_ip_ospf_database_all): show nothing if a type of LSA
+        does not exist.
+        
+1999-08-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_lsa.c (ospf_maxage_lsa_remover): Preserve next pointer when
+        the node is deleted.
+
+1999-08-31  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_flood.c (ospf_ls_retransmit_lookup): change to return
+        struct ospf_lsa *.
+        (ospf_ls_request_new), (ospf_ls_request_free),
+        (ospf_ls_request_add), (ospf_ls_request_delete),
+        (ospf_ls_request_delete_all), (ospf_ls_request_lookup):
+        New function added.
+
+        * ospf_packet.c (ospf_ls_upd_send_lsa): New function added.
+
+        * ospf_lsa.h (LS_AGE): Slightly change macro definition.
+
+        * ospf_lsa.c (ospf_lsa_more_recent), (ospf_lsa_diffrent):
+        Use LS_AGE macro.
+
+1999-08-30  Alex Zinin <zinin@amt.ru>
+        
+        * ospfd.c
+        fix a bug with area range config write
+        added "show ip ospf" command, it will be enhanced later on
+
+1999-08-30  Alex Zinin <zinin@amt.ru>
+
+        * ospf_lsa.c
+        updated ospf_router_lsa() to honor flags (B-bit)
+
+1999-08-30  Alex Zinin <zinin@amt.ru>
+
+        * ospf_abr.c
+        wrote major functions implementing ABR activity
+
+1999-08-30  Alex Zinin <zinin@amt.ru>
+
+        * ospf_ia.c ospf_route.c ospf_route.h 
+        fixed the bug with ospf_route.origin field.
+        Now it holds pointer to lsa_header
+
+1999-08-30  Alex Zinin <zinin@amt.ru>
+
+        * ospf_flood.c ospf_flood.h:
+        transformed ospf_flood_if_select into ospf_flood_through_area()
+        added new ospf_flood_if_select() and ospf_flood_through_as()
+
+1999-08-30  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_flood.[ch]: New file added.
+
+        * ospf_packet.c (ospf_lsa_flooding),
+        (ospf_lsa_flooding_select_if): functions move to ospf_flood.c
+
+        * ospf_neighbor.c (ospf_put_lsa_on_retransm_list),
+        (ospf_remove_lsa_from_retransm_list),
+        (ospf_nbr_remove_all_lsas_from_retransm_list),
+        (ospf_lsa_remove_from_ls_retransmit):
+        (ospf_lsa_retransmit): functions move to
+        ospf_flood.c, and change function's name:
+
+        ospf_put_lsa_on_retransm_list ()
+          -> ospf_ls_retransmit_add ()
+        ospf_remove_lsa_from_retransm_list ()
+          -> ospf_ls_retransmit_delete ()
+        ospf_nbr_remove_all_lsas_from_retransm_list ()
+          -> ospf_ls_retransmit_clear ()
+        ospf_lsa_remove_from_ls_retransmit ()
+          -> ospf_ls_retransmit_delete_nbr_all ()
+        ospf_lsa_retransmit ()
+          -> ospf_ls_retransmit_add_nbr_all ()
+
+        * ospf_lsa.c (ospf_lsa_lookup_from_list): function move to
+        ospf_flood.c, and change name to ospf_ls_retransmit_lookup ().
+
+1999-08-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_neighbor.c (ospf_nbr_lookup_by_addr): Use
+        route_node_lookup() instead of route_node_get().
+
+        * ospf_packet.c (ospf_ls_upd): Temporary comment out (6) check.
+
+1999-08-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_route.c (ospf_lookup_int_by_prefix): Add check of
+        oi->address.
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_lsa.c 
+        MaxAge LSA deletion functions added.
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_neighbor.c 
+        ospf_nbr_lookup_by_addr(): added route_unlock_node()
+        when function returns NULL if (rn->info == NULL)
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospfd.c
+        added a hack for area range deletion
+        
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_lsa.h 
+        included lsdb field into struct ospf_lsa, to find
+        LSDB easier when removing MaxAge LSAs.
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_lsa.c ospf_neighbor.c ospf_nsm.c 
+          ospf_packet.c changed to honor new retransmit list
+          management functions
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_neighbor.c , .h added new retransmit list functions.
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * Makefile.in
+        added ospf_ase, ospf_abr, ospf_ia
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_spf.c:
+        - changed ospf_next_hop_calculation() to include interface
+          and nexthop addr for directly connected routers---more informative
+          and solves problem with route installation into the kernel
+        - changed ospf_nexthop_out_if_addr() to support routers, not only
+          transit networks
+        - added ospf_process_stubs();
+
+1999-08-29  Alex Zinin <zinin@amt.ru>
+        * ospf_lsa.c:
+        - changed ospf_router_lsa() to provide correct links
+          for p-t-p interfaces;
+        - changed ospf_summary_lsa_install() to support table
+          of self-originated summary-LSAs;
+        - added ospf_summary_asbr_lsa_install() and ospf_external_lsa_install()
+        - changed ospf_lsa_install() accordingly
+        - changed show_ip_ospf_database_router_links() to support p-t-p
+
+1999-08-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_packet.c (ospf_make_db_desc): Only master can clear more
+        flag.
+
+1999-08-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_packet.c (ospf_read): Add check of IP src address.
+
+1999-08-28  Alex Zinin <zinin@amt.ru>
+        * ospf_neighbor.h
+        added ospf_nbr_lookup_by_routerid()
+
+1999-08-28  Alex Zinin <zinin@amt.ru>
+        * ospfd.h
+        added ABR/ASBR flag definitions and fields;
+        added iflist field to area structure;
+        summary_lsa_self and summary_lsa_asbr_self are changed
+        to be route tables;
+        added ranges field---configured area ranges;
+        A separate Routers RT added;
+        area range config commands and config write added
+
+
+1999-08-28  Alex Zinin <zinin@amt.ru>
+        * ospf_route.c :
+        ospf_route_free()--added code to free the list of paths;
+        The following functions added:
+                ospf_intra_add_router();
+                ospf_intra_add_transit();
+                ospf_intra_add_stub();
+        the last function uses new ospf_int_lookup_by_prefix();
+        show_ip_ospf_route_cmd()--changed to support new RT structure;
+        added ospf_cmp_routes()--general route comparision function;
+        added ospf_route_copy_nexthops() and ospf_route_copy_nexthops_from_vertex()
+        they are used in ASE and IA routing;
+        added ospf_subst_route() and ospf_add_route();
+
+1999-08-28  Alex Zinin <zinin@amt.ru>
+        * ospf_route.h :
+        changed struct ospf_path to include output interface,
+        changed struct ospf_route to support IA and ASE routing.
+        added prototypes of the function used in IA and ASE modules.
+
+1999-08-28  Alex Zinin <zinin@amt.ru>
+        * ospf_lsa.h ospf_lsa.c :
+        added ospf_my_lsa(), an interface independent version of
+        ospf_lsa_is_self_originated(), it will be used in ASE and IA-routing.
+
+1999-08-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_interface.c (interface_config_write): Add check for
+        oi->nbr_self.
+
+1999-08-25  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (ospf_lsa_dup): New function added.
+
+        * ospf_packet.c (ospf_write), (ospf_read): Print send/recv
+        interface in debug message.
+
+1999-08-25  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_ls_ack_send): The name is changed from
+        `ospf_ls_ack_send'.
+        (ospf_ls_ack_send_delayed) (ospf_ls_ack_timer): New function added.
+        Delayed Link State Acknowledgment is scheduled by timer.
+
+1999-08-25  Alex Zinin  <zinin@amt.ru>
+
+        * ospf_lsa.c (ospf_router_lsa): Incorrectly included link to
+        a stub network instead of link to a transit network into
+        originated router-LSA, bug fixed.
+
+1999-08-24  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (ospf_update_router_id): New function added.
+
+        * ospf_network.c (ospf_write): Create new socket per transmission.
+        And select outgoing interface whether dst is unicast or multicast.
+
+        * ospf_packet.c: LSA flooding will work.        
+
+1999-08-24  VOP <vop@unity.net>
+
+        * ospf_route.c: Include "sockunion.h"
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_network.c (ospf_serv_sock_init): Enclose
+        IPTOS_PREC_INTERNETCONTROL setting with #ifdef for OS which does
+        not have the definition.
+
+1999-08-23  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c: Fix bug of DD processing.
+
+1999-08-18  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (show_ip_ospf_database): Show actual `LS age'.
+
+1999-08-17  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.h (OSPF_MAX_LSA): The value of OSPF_MAX_LSA is
+        corrected.  The bug of `mes_lookup' is fixed.  
+        This had been reported by Poul-Henning Kamp <phk@freebsd.org>.
+
+        * ospf_lsa.c (ospf_router_lsa_install): The name is changed from
+        `ospf_add_router_lsa'.
+        (ospf_network_lsa_install): The name is changed from
+        `ospf_add_network_lsa'.
+
+        * ospf_interface.h (ospf_interface): Add member `nbr_self'.
+
+        * ospf_interface.c (ospf_if_is_enable): New function added.
+
+1999-08-16  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.h (struct lsa_header): The name is changed from
+        `struct ospf_lsa'.
+        (struct ospf_lsa): New struct added to control each LSA's aging
+        and timers.     
+
+        * ospf_lsa.c (ospf_lsa_data_free): The name is change from
+        `ospf_lsa_free'.
+        (ospf_lsa_data_new), (ospf_lsa_new), (ospf_lsa_free),
+        (ospf_lsa_different), (ospf_lsa_install): New function added.
+
+        * ospf_packet.c (ospf_ls_upd_list_lsa): New function added.
+
+1999-08-12  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_nsm.c (nsm_reset_nbr): New function added.
+        KillNbr and LLDown neighbor event call this function.
+        
+1999-08-10  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_ls_retransmit)
+        (ospf_ls_upd_timer): New function added.
+        Set retransmission timer for Link State Update.
+
+1999-07-29  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.c (ospf_dr_election): Fix bug of DR election.
+
+1999-07-28  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_network.c (ospf_serv_sock_init): Set IP precedence field
+        with IPTOS_PREC_INTERNET_CONTROL.
+
+        * ospf_nsm.c (nsm_change_status): Schedule NeighborChange event
+        if NSM status change.
+        
+        * ospf_packet.c (ospf_make_hello): Never include a neighbor in
+        Hello packet, when the neighbor goes down.
+
+1999-07-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * Makefile.am (noinst_HEADERS): Add ospf_route.h.
+
+        * ospf_route.c (show_ip_ospf_route): Add `show ip ospf route'
+        command.
+
+1999-07-25  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (ospf_router_lsa): Fix bug of LS sequence number
+        assignement.
+
+1999-07-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_route.c (ospf_route_table_free): New function added.
+
+        * ospf_spf.c (ospf_spf_next): Free vertex w when cw's and w's
+        distance is same.
+
+        * ospfd.h (struct ospf): Add old_table.
+
+        * ospf_main.c (sighup): Call of log_rotate () removed.
+
+        * ospf_lsa.c (ospf_lsa_is_self_originated): Fix bug of checking
+        area->lsa as self LSA.  This should be area->lsa_self.
+
+1999-07-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_zebra.c (ospf_zebra_add): ospf_zebra_add
+        (),ospf_zebra_delete () added.
+
+        * ospf_spf.c (ospf_spf_calculate): Call ospf_intra_route_add ().
+
+1999-07-24  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c: Change LS sequence number treatment.
+        (ospf_lsa_is_self_originated): New function added.
+        (show_ip_ospf_database_self_originated): New DEFUN added.
+        
+1999-07-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_interface.c (ospf_if_lookup_by_addr): Add loopback check.
+
+1999-07-22  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_spf.c (ospf_nexthop_new), (ospf_nexthop_free),
+        (ospf_nexthop_dup): function added.
+        (ospf_nexthop_calculation): function changed.
+
+        * ospf_interface.c (ospf_if_lookup_by_addr): function added.
+        
+1999-07-21  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_spf.c (ospf_spf_closest_vertex): function removed.
+        
+1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_spf.c (ospf_spf_next): Apply ntohs for fetching metric.
+
+1999-07-21  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_neighbor.c (ospf_nbr_lookup_by_router_id): fundtion removed.
+
+        * ospf_lsa.c (show_ip_ospf_database_router): describe each
+        connected link.
+
+1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_spf.c (ospf_spf_next): V is router LSA or network LSA so
+        change behavior according to LSA type.
+        (ospf_lsa_has_link): Link check function is added.
+
+1999-07-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_spf.c (ospf_spf_calculate_schedule): Add new function for
+        SPF calcultion schedule addtition.
+        (ospf_spf_calculate_timer_add): Rough 30 sec interval SPF calc
+        timer is added.
+        (ospf_spf_next_router): Delete ospf_spf_next_network ().
+
+        * ospf_lsa.c (show_ip_ospf_database_all): Network-LSA display
+        header typo correction.  Display of router LSA's #link added.
+
+1999-07-19  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_check_network_mask): Added new function for
+        receiving Raw IP packet on an appropriate interface.
+
+1999-07-16  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c (ospf_router_id): new DEFUN added.
+
+1999-07-15  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_spf.c (ospf_spf_init), (ospf_spf_free),
+        (ospf_spf_has_vertex), (ospf_vertex_lookup),
+        (ospf_spf_next_router), (ospf_spf_next_network),
+        (ospf_spf_closest_vertex), (ospf_spf_calculate):
+        function added.
+
+1999-07-13  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.c: fix bug of DR Election.
+
+        * ospf_nsm.c: fix bug of adjacency forming.
+
+1999-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospfd.c (ospf_init): Change to use install_default.
+
+1999-07-01  Rick Payne <rickp@rossfell.co.uk>
+
+        * ospf_zebra.c (zebra_init): Install standard commands to
+        ZEBRA_NODE.
+
+1999-06-30  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_dump.c: Whole debug command is improved.
+        (ISM|NSM) (events|status|timers) debug option added.
+        (show_debugging_ospf): new DEFUN added.
+
+1999-06-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_lsa.c (ospf_lsa_lookup_from_list): Change !IPV4_ADDR_CMP to
+        IPV4_ADDR_SAME.
+
+1999-06-29  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_dump.c (ospf_summary_lsa_dump): Add summary-LSA dump routine.
+        (ospf_as_external_lsa_dump): Add AS-external-LSA dump routine.
+
+        * ospf_nsm.c (nsm_twoway_received): fix condtion of adjacnet.
+
+        * ospf_ism.c (ospf_dr_election): fix DR Election.
+        
+        * ospf_dump.c (ospf_nbr_state_message): fix `show ip ospf neighbor'
+        command's state.
+
+1999-06-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_dump.c (ospf_router_lsa_dump): Add router-LSA dump routine.
+
+1999-06-28  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (show_ip_ospf_database_network): fix bug of
+        `show ip ospf database network' command output.
+
+        * ospf_nsm.c (nsm_inactivity_timer): Clear list of Link State
+        Retransmission, Database Summary and Link State Request.
+
+        * ospf_packet.c (ospf_ls_req_timer): New function added.
+        Set Link State Request retransmission timer.
+
+1999-06-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_main.c (main): Change default output from ZLOG_SYSLOG to
+        ZLOG_STDOUT.
+
+        * ospfd.c (ospf_init): Register show_ip_ospf_interface_cmd and
+        show_ip_ospf_neighbor_cmd to VIEW_NODE.
+
+        * ospf_lsa.c (ospf_lsa_init): Register show_ip_ospf_database_cmd
+        and show_ip_ospf_database_type_cmd to VIEW_NODE.
+
+1999-06-25  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c: fix bug of DD making.
+        fix bug of LS-Update reading.
+        
+1999-06-23  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c: All type of packets are changed to use
+        fifo queue structure.
+        (ospf_fill_header) function added.
+
+1999-06-22  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c (ospf_packet_new): New function added to handle
+        sending ospf packet by fifo queue structure.
+        (ospf_packet_free), (ospf_fifo_new), (ospf_fifo_push),
+        (ospf_fifo_pop), (ospf_fifo_head), (ospf_fifo_flush),
+        (ospf_fifo_free): Likewise.
+
+1999-06-21  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_nsm.c (ospf_db_desc_timer): function added.
+        (nsm_timer_set) function added.
+        * ospf_dump.c (ospf_option_dump): function added.
+        * ospf_packet.c (ospf_ls_req) (ospf_make_ls_req): function added.
+
+1999-06-20  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c (ospf_lsa_more_recent): function added.
+        * ospf_neighbor.h (struct ospf_neighbor): Change member ms_flag
+        to dd_flags.
+        
+1999-06-19  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c: DEFUN (show_ip_ospf_database) Added.
+        * ospf_interface.c (if_ospf_cost), (if_ospf_dead_interval),
+        (if_ospf_hello_interval), (if_ospf_priority),
+        (if_ospf_retransmit_interval), (if_ospf_transmit_delay)
+        argument changed from NUMBER to <range>.
+        DEFUN (if_ospf_network_broadcast),
+        DEFUN (if_ospf_network_non_broadcast),
+        DEFUN (if_ospf_network_point_to_multipoint),
+        DEFUN (if_ospf_network_point_to_point) functions are combined to
+        DEFUN (if_ospf_network).
+        
+1999-06-18  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c: ospf_add_router_lsa (), ospf_add_network_lsa (),
+        ospf_lsa_lookup (), ospf_lsa_count () Added.
+
+1999-06-15  Toshiaki Takada  <takada@zebra.org>
+
+        * DEFUN (ospf_debug_ism), DEFUN (ospf_debug_nsm),
+        DEFUN (no_ospf_debug_ism), DEFUN (no_ospf_debug_nsm) Added.
+        `debug ospf ism' command shows debug message.
+        `debuf ospf nsm' command shows debug message.
+
+1999-06-14  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c: ospf_network_lsa () Added.
+        ospf_lsa_checksum () Added.
+        * DEFUN (ospf_debug_packet), DEFUN (no_ospf_debug_packet) Added.
+        `debug ospf packet' command shows debug message.
+
+1999-06-13  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.h: Remove struct ospf_ls_req {}, ospf_ls_upd {},
+        ospf_ls_ack {}.
+
+1999-06-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_dump.c: fix IP packet length treatment.
+
+1999-06-10  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.h: Add OSPF_ISM_EVENT_EXECUTE() Macro Added.
+        * ospf_nsm.h: Add OSPF_NSM_EVENT_EXECUTE() Macro Added.
+
+        * ospf_packet.c: ospf_db_desc (), ospf_db_desc_send () Added.
+        ospf_make_hello (), ospf_make_db_desc () Added.
+        ospf_db_desc_proc () Added.n
+
+        * Database Description packet can be processed.
+
+1999-06-08  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.c: New file.
+        
+1999-06-07  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_neighbor.c: ospf_fully_adjacent_count () Added.
+
+1999-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_spf.[ch]: New file.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_zebra.c: Changed to use lib/zclient.c routines.
+
+        * ospf_zebra.h (zebra_start): Remove struct zebra.
+
+1999-05-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospfd.c (ospf_config_write): Add cast (unsigned long int) to
+        ntohl for sprintf warning.
+
+1999-05-19  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.c (ospf_dr_election): Join AllDRouters Multicast group
+        if interface state changes to DR or BDR.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+        * ospf_main.c (signal_init): SIGTERM call sigint.
+        (sigint): Logging more better message.
+
+1999-05-12  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c: Fix bug of `no router ospf' statement, it will work.
+
+1999-05-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_neighbor.c: ospf_nbr_free () Added.
+
+1999-05-10  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.h: struct ospf_area { }, struct ospf_network { } Changed.
+        * Fix bug of `no network' statement, it will work.
+
+1999-05-07  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.c, ospf_zebra.c: Fix bug of last interface is not
+        updated by ospf_if_update ().
+
+1999-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * Makefile.am (noinst_HEADERS): Add ospf_lsa.h for distribution.
+
+1999-04-25  Toshiaki Takada <takada@zebra.org>
+
+        * ospf_interface.c: DEFUN (no_if_ospf_cost),
+        DEFUN (no_if_ospf_dead_interval),
+        DEFUN (no_if_ospf_hello_interval),
+        DEFUN (no_if_ospf_priority),
+        DEFUN (no_if_ospf_retransmit_interval),
+        DEFUN (no_if_ospf_transmit_delay) Added.
+
+        interface_config_write () suppress showing interface
+        default values.
+
+1999-04-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_dump.c (ospf_timer_dump): If thread is NULL return "inactive".
+
+        * ospfd.c (ospf_if_update): Fix bug of using ospf_area { } instead
+        of ospf_network { }.  So `router ospf' statement in ospfd.conf
+        works again.
+        (ospf_if_update): Call ospf_get_router_id for updating router ID.
+
+1999-04-25  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.c: DEFUN (if_ospf_network) deleted.
+        DEFUN (if_ospf_network_broadcast),
+        DEFUN (if_ospf_network_non_broadcast),
+        DEFUN (if_ospf_network_point_to_multipoint),
+        DEFUN (if_ospf_network_point_to_point),
+        DEFUN (no_if_ospf_network) Added.
+
+1999-04-23  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.h: struct area { } changed to struct ospf_network { }.
+        Add struct ospf_area { }.
+        * ospfd.c: Add ospf_area_lookup_by_area_id (), ospf_network_new (),
+        and ospf_network_free ().
+        DEFUN (area_authentication), DEFUN (no_area_authentication) Added.
+
+1999-04-22  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_lsa.h: New file.
+        * ospf_packet.h: LSA related struct definition are moved to
+        ospf_lsa.h.
+        * ospf_packet.c: ospf_verify_header () Added.
+
+1999-04-21  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.c: ospf_elect_dr () and related function is changed.
+        DR Election bug fixed.
+        * ospf_dump.c: ospf_nbr_state_message (), ospf_timer_dump () Added.
+        * ospfd.c: DEFUN (show_ip_ospf_neighbor) Added.
+
+1999-04-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_main.c (main): access_list_init () is added for vty
+        connection filtering.
+
+1999-04-16  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.c: DEFUN (show_ip_ospf_interface) Added.
+        * ospf_neighbor.c: ospf_nbr_count () Added.
+        
+1999-04-15  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.h: struct ospf { } Changed.
+        * ospfd.c: ospf_lookup_by_process_id () Deleted.
+        * ospf_ism.c: ospf_wait_timer () Added. WaitTimer will work.
+
+1999-04-14  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.c: ospf_elect_dr () Added.
+        * ospf_network.c: ospf_if_ipmulticast () Added.
+
+1999-04-11  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.c: interface_config_write (),
+        DEFUN (if_ip_ospf_cost),
+        DEFUN (if_ip_ospf_dead_interval),
+        DEFUN (if_ip_ospf_hello_interval),
+        DEFUN (if_ip_ospf_priority),
+        DEFUN (if_ip_ospf_retransmit_interval) and
+        DEFUN (if_ip_ospf_transmit_delay) Added.
+
+1999-04-08  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_dump.c: ospf_packet_db_desc_dump () Added.
+        * ospf_neighbor.c: ospf_nbr_bidirectional () Added.
+        * ospf_nsm.c: nsm_twoway_received () Added.
+
+1999-04-02  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_neighbor.c: New file.
+        * ospf_neighbor.h: New file.
+        * ospf_nsm.c: New file.
+        * ospf_nsm.h: New file.
+        * ospf_packet.c: Add ospf_make_header (), ospf_hello () and
+        ospf_hello_send (). Now OSPFd can receive Hello and send Hello.
+
+1999-03-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_packet.c: Add ospf_recv_packet ().  Now OSPF Hello can receive.
+
+1999-03-19  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_packet.c: New file.
+        * ospf_packet.h: New file.
+        * ospf_network.c: New file.
+        * ospf_network.h: New file.
+        * ospfd.h: move OSPF message structure has moved to ospf_packet.h.
+
+1999-03-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * ospf_zebra.c (ospf_zebra_get_interface): Fix for IPv6 interface
+        address.
+
+        * Makefile.am (install-sysconfDATA): Overwrite install-sysconfDATA
+        for install ospfd.conf.sample as owner read only file.
+
+        * ospf_main.c (usage): Change to use ZEBRA_BUG_ADDRESS.
+
+1999-03-15  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_ism.c: New file.
+        * ospf_ism.h: New file.
+        * ospf_dump.c: New file.
+        * ospf_dump.h: New file.
+
+        * ospfd.h: Add (struct ospf), (struct config_network),
+        (struct message) structure.
+
+        * ospf_interface.c: Add ospf_if_match_network ().
+        * ospf_interface.h (struct ospf_interface): Change struct members.
+
+        * ospfd.c: ospf_lookup_by_process_id (), ospf_network_new (),
+        DEFUN (network_area): Added.
+
+        * ospfd.conf.sample: Change sample configuration.
+
+1999-03-05  Toshiaki Takada  <takada@zebra.org>
+
+        * ospf_interface.c: New file.
+        * ospf_interface.h: New file.
+        * ospf_zebra.h: New file.
+        * ospf_zebra.c: Add interface function for zebra daemon.
+        * ospfd.c: New file.
+
+1999-02-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * Move IPv6 codes and files to ospf6d directory.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+        * syslog support added
+
+1998-12-22  Toshiaki Takada  <takada@zebra.org>
+
+        * ospfd.h: New file.
+        * ospf_lsa.h: New file.
+
+1998-12-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+        * Makefile.am: New file.
+        * ospf_main.c: New file.
+
diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am
new file mode 100644 (file)
index 0000000..1ced11c
--- /dev/null
@@ -0,0 +1,44 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf.a
+sbin_PROGRAMS = ospfd
+
+libospf_a_SOURCES = \
+       ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \
+       ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \
+       ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \
+       ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \
+       ospf_opaque.c ospf_te.c ospf_vty.c
+
+noinst_HEADERS = \
+       ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \
+       ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \
+       ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \
+       ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \
+       ospf_te.h ospf_vty.h
+
+ospfd_SOURCES = \
+       ospf_main.c $(libospf_a_SOURCES)
+
+ospfd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospfd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
diff --git a/ospfd/Makefile.in b/ospfd/Makefile.in
new file mode 100644 (file)
index 0000000..8472535
--- /dev/null
@@ -0,0 +1,532 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf.a
+sbin_PROGRAMS = ospfd
+
+libospf_a_SOURCES = \
+       ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \
+       ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \
+       ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \
+       ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \
+       ospf_opaque.c ospf_te.c ospf_vty.c
+
+
+noinst_HEADERS = \
+       ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \
+       ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \
+       ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \
+       ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \
+       ospf_te.h ospf_vty.h
+
+
+ospfd_SOURCES = \
+       ospf_main.c $(libospf_a_SOURCES)
+
+
+ospfd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospfd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt
+subdir = ospfd
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libospf_a_AR = $(AR) cru
+libospf_a_LIBADD =
+am_libospf_a_OBJECTS = ospfd.$(OBJEXT) ospf_zebra.$(OBJEXT) \
+       ospf_interface.$(OBJEXT) ospf_ism.$(OBJEXT) \
+       ospf_neighbor.$(OBJEXT) ospf_nsm.$(OBJEXT) ospf_dump.$(OBJEXT) \
+       ospf_network.$(OBJEXT) ospf_packet.$(OBJEXT) ospf_lsa.$(OBJEXT) \
+       ospf_spf.$(OBJEXT) ospf_route.$(OBJEXT) ospf_ase.$(OBJEXT) \
+       ospf_abr.$(OBJEXT) ospf_ia.$(OBJEXT) ospf_flood.$(OBJEXT) \
+       ospf_lsdb.$(OBJEXT) ospf_asbr.$(OBJEXT) ospf_routemap.$(OBJEXT) \
+       ospf_snmp.$(OBJEXT) ospf_opaque.$(OBJEXT) ospf_te.$(OBJEXT) \
+       ospf_vty.$(OBJEXT)
+libospf_a_OBJECTS = $(am_libospf_a_OBJECTS)
+sbin_PROGRAMS = ospfd$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ospfd.$(OBJEXT) ospf_zebra.$(OBJEXT) \
+       ospf_interface.$(OBJEXT) ospf_ism.$(OBJEXT) \
+       ospf_neighbor.$(OBJEXT) ospf_nsm.$(OBJEXT) ospf_dump.$(OBJEXT) \
+       ospf_network.$(OBJEXT) ospf_packet.$(OBJEXT) ospf_lsa.$(OBJEXT) \
+       ospf_spf.$(OBJEXT) ospf_route.$(OBJEXT) ospf_ase.$(OBJEXT) \
+       ospf_abr.$(OBJEXT) ospf_ia.$(OBJEXT) ospf_flood.$(OBJEXT) \
+       ospf_lsdb.$(OBJEXT) ospf_asbr.$(OBJEXT) ospf_routemap.$(OBJEXT) \
+       ospf_snmp.$(OBJEXT) ospf_opaque.$(OBJEXT) ospf_te.$(OBJEXT) \
+       ospf_vty.$(OBJEXT)
+am_ospfd_OBJECTS = ospf_main.$(OBJEXT) $(am__objects_1)
+ospfd_OBJECTS = $(am_ospfd_OBJECTS)
+ospfd_DEPENDENCIES = ../lib/libzebra.a
+ospfd_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf_abr.Po ./$(DEPDIR)/ospf_asbr.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_ase.Po ./$(DEPDIR)/ospf_dump.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_flood.Po ./$(DEPDIR)/ospf_ia.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_interface.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_ism.Po ./$(DEPDIR)/ospf_lsa.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_lsdb.Po ./$(DEPDIR)/ospf_main.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_neighbor.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_network.Po ./$(DEPDIR)/ospf_nsm.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_opaque.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_packet.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_route.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_routemap.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_snmp.Po ./$(DEPDIR)/ospf_spf.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_te.Po ./$(DEPDIR)/ospf_vty.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ospf_zebra.Po ./$(DEPDIR)/ospfd.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libospf_a_SOURCES) $(ospfd_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(libospf_a_SOURCES) $(ospfd_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  ospfd/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libospf.a: $(libospf_a_OBJECTS) $(libospf_a_DEPENDENCIES) 
+       -rm -f libospf.a
+       $(libospf_a_AR) libospf.a $(libospf_a_OBJECTS) $(libospf_a_LIBADD)
+       $(RANLIB) libospf.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sbindir)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+         rm -f $(DESTDIR)$(sbindir)/$$f; \
+       done
+
+clean-sbinPROGRAMS:
+       -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ospfd$(EXEEXT): $(ospfd_OBJECTS) $(ospfd_DEPENDENCIES) 
+       @rm -f ospfd$(EXEEXT)
+       $(LINK) $(ospfd_LDFLAGS) $(ospfd_OBJECTS) $(ospfd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_abr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_asbr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ase.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_flood.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ia.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ism.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_neighbor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_nsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_opaque.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_spf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_te.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_vty.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfd.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+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 =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-noinstLIBRARIES clean-sbinPROGRAMS ctags 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 pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ospfd/OSPF-MIB.txt b/ospfd/OSPF-MIB.txt
new file mode 100644 (file)
index 0000000..de7d03f
--- /dev/null
@@ -0,0 +1,2723 @@
+OSPF-MIB DEFINITIONS ::= BEGIN
+
+    IMPORTS
+            MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32,
+            Integer32, IpAddress
+                FROM SNMPv2-SMI
+            TEXTUAL-CONVENTION, TruthValue, RowStatus
+                FROM SNMPv2-TC
+            MODULE-COMPLIANCE, OBJECT-GROUP          FROM SNMPv2-CONF
+            mib-2                                    FROM RFC1213-MIB;
+
+--  This MIB module uses the extended OBJECT-TYPE macro as
+--  defined in [9].
+
+ospf MODULE-IDENTITY
+        LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995
+        ORGANIZATION "IETF OSPF Working Group"
+        CONTACT-INFO
+       "       Fred Baker
+       Postal: Cisco Systems
+               519 Lado Drive
+               Santa Barbara, California 93111
+       Tel:    +1 805 681 0115
+       E-Mail: fred@cisco.com
+
+               Rob Coltun
+       Postal: RainbowBridge Communications
+       Tel:    (301) 340-9416
+       E-Mail: rcoltun@rainbow-bridge.com"
+    DESCRIPTION
+       "The MIB module to describe the OSPF Version 2
+       Protocol"
+    ::= { mib-2 14 }
+
+--  The Area ID, in OSPF, has the same format as an IP Address,
+--  but has the function of defining a summarization point for
+--  Link State Advertisements
+
+AreaID ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "An OSPF Area Identifier."
+    SYNTAX      IpAddress
+
+
+--  The Router ID, in OSPF, has the same format as an IP Address,
+--  but identifies the router independent of its IP Address.
+
+RouterID ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "A OSPF Router Identifier."
+    SYNTAX      IpAddress
+
+
+--  The OSPF Metric is defined as an unsigned value in the range
+
+Metric ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The OSPF Internal Metric."
+    SYNTAX      Integer32 (0..'FFFF'h)
+
+BigMetric ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The OSPF External Metric."
+    SYNTAX      Integer32 (0..'FFFFFF'h)
+
+--  Status Values
+
+Status ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The status of an interface: 'enabled' indicates that
+       it is willing to communicate with other OSPF Routers,
+       while 'disabled' indicates that it is not."
+    SYNTAX      INTEGER { enabled (1), disabled (2) }
+
+--  Time Durations measured in seconds
+
+PositiveInteger ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "A positive integer. Values in excess are precluded as
+       unnecessary and prone to interoperability issues."
+    SYNTAX      Integer32 (0..'7FFFFFFF'h)
+
+HelloRange ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The range of intervals on which hello messages are
+       exchanged."
+    SYNTAX      Integer32 (1..'FFFF'h)
+
+UpToMaxAge ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The values that one might find or configure for
+       variables bounded by the maximum age of an LSA."
+    SYNTAX      Integer32 (0..3600)
+
+
+--  The range of ifIndex
+
+InterfaceIndex ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The range of ifIndex."
+    SYNTAX      Integer32
+
+
+--  Potential Priorities for the Designated Router Election
+
+DesignatedRouterPriority ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "The values defined for the priority of a system for
+       becoming the designated router."
+    SYNTAX      Integer32 (0..'FF'h)
+
+TOSType ::= TEXTUAL-CONVENTION
+    STATUS      current
+    DESCRIPTION
+       "Type of Service is defined as a mapping to the IP Type of
+       Service Flags as defined in the IP Forwarding Table MIB
+
+       +-----+-----+-----+-----+-----+-----+-----+-----+
+       |                 |                       |     |
+       |   PRECEDENCE    |    TYPE OF SERVICE    |  0  |
+       |                 |                       |     |
+       +-----+-----+-----+-----+-----+-----+-----+-----+
+
+                IP TOS                IP TOS
+           Field     Policy      Field     Policy
+
+           Contents    Code      Contents    Code
+           0 0 0 0  ==>   0      0 0 0 1  ==>   2
+           0 0 1 0  ==>   4      0 0 1 1  ==>   6
+           0 1 0 0  ==>   8      0 1 0 1  ==>  10
+           0 1 1 0  ==>  12      0 1 1 1  ==>  14
+           1 0 0 0  ==>  16      1 0 0 1  ==>  18
+           1 0 1 0  ==>  20      1 0 1 1  ==>  22
+           1 1 0 0  ==>  24      1 1 0 1  ==>  26
+           1 1 1 0  ==>  28      1 1 1 1  ==>  30
+
+       The remaining values are left for future definition."
+    SYNTAX      Integer32 (0..30)
+
+
+--  OSPF General Variables
+
+--      These parameters apply globally to the Router's
+--      OSPF Process.
+
+ospfGeneralGroup OBJECT IDENTIFIER ::= { ospf 1 }
+
+
+    ospfRouterId OBJECT-TYPE
+        SYNTAX   RouterID
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "A  32-bit  integer  uniquely  identifying  the
+           router in the Autonomous System.
+
+           By  convention,  to  ensure  uniqueness,   this
+           should  default  to  the  value  of  one of the
+           router's IP interface addresses."
+       REFERENCE
+          "OSPF Version 2, C.1 Global parameters"
+      ::= { ospfGeneralGroup 1 }
+
+
+    ospfAdminStat OBJECT-TYPE
+        SYNTAX   Status
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "The  administrative  status  of  OSPF  in  the
+           router.   The  value 'enabled' denotes that the
+           OSPF Process is active on at least  one  inter-
+           face;  'disabled'  disables  it  on  all inter-
+           faces."
+       ::= { ospfGeneralGroup 2 }
+
+    ospfVersionNumber OBJECT-TYPE
+        SYNTAX   INTEGER    { version2 (2) }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The current version number of the OSPF  proto-
+           col is 2."
+       REFERENCE
+          "OSPF Version 2, Title"
+      ::= { ospfGeneralGroup 3 }
+
+
+    ospfAreaBdrRtrStatus OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "A flag to note whether this router is an  area
+           border router."
+       REFERENCE
+          "OSPF Version 2, Section 3 Splitting the AS into
+          Areas"
+      ::= { ospfGeneralGroup 4 }
+
+
+    ospfASBdrRtrStatus OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "A flag to note whether this router is  config-
+           ured as an Autonomous System border router."
+       REFERENCE
+          "OSPF Version 2, Section 3.3  Classification  of
+          routers"
+      ::= { ospfGeneralGroup 5 }
+
+    ospfExternLsaCount OBJECT-TYPE
+        SYNTAX   Gauge32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of external (LS type 5)  link-state
+           advertisements in the link-state database."
+       REFERENCE
+          "OSPF Version 2, Appendix A.4.5 AS external link
+          advertisements"
+      ::= { ospfGeneralGroup 6 }
+
+
+    ospfExternLsaCksumSum OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The 32-bit unsigned sum of the LS checksums of
+           the  external  link-state  advertisements  con-
+           tained in the link-state  database.   This  sum
+           can  be  used  to determine if there has been a
+           change in a router's link state  database,  and
+           to  compare  the  link-state  database  of  two
+           routers."
+       ::= { ospfGeneralGroup 7 }
+
+
+    ospfTOSSupport OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "The router's support for type-of-service rout-
+           ing."
+       REFERENCE
+          "OSPF Version 2,  Appendix  F.1.2  Optional  TOS
+          support"
+      ::= { ospfGeneralGroup 8 }
+
+    ospfOriginateNewLsas OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of  new  link-state  advertisements
+           that  have been originated.  This number is in-
+           cremented each time the router originates a new
+           LSA."
+       ::= { ospfGeneralGroup 9 }
+
+
+    ospfRxNewLsas OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of  link-state  advertisements  re-
+           ceived  determined  to  be  new instantiations.
+           This number does not include  newer  instantia-
+           tions  of self-originated link-state advertise-
+           ments."
+       ::= { ospfGeneralGroup 10 }
+
+    ospfExtLsdbLimit OBJECT-TYPE
+        SYNTAX   Integer32 (-1..'7FFFFFFF'h)
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "The  maximum   number   of   non-default   AS-
+           external-LSAs entries that can be stored in the
+           link-state database.  If the value is -1,  then
+           there is no limit.
+
+           When the number of non-default AS-external-LSAs
+           in   a  router's  link-state  database  reaches
+           ospfExtLsdbLimit, the router  enters  Overflow-
+           State.   The   router  never  holds  more  than
+           ospfExtLsdbLimit  non-default  AS-external-LSAs
+           in  its  database. OspfExtLsdbLimit MUST be set
+           identically in all routers attached to the OSPF
+           backbone  and/or  any regular OSPF area. (i.e.,
+           OSPF stub areas and NSSAs are excluded)."
+       DEFVAL { -1 }
+       ::= { ospfGeneralGroup 11 }
+
+    ospfMulticastExtensions OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "A Bit Mask indicating whether  the  router  is
+           forwarding  IP  multicast  (Class  D) datagrams
+           based on the algorithms defined in  the  Multi-
+           cast Extensions to OSPF.
+
+           Bit 0, if set, indicates that  the  router  can
+           forward  IP multicast datagrams in the router's
+           directly attached areas (called intra-area mul-
+           ticast routing).
+
+           Bit 1, if set, indicates that  the  router  can
+           forward  IP  multicast  datagrams  between OSPF
+           areas (called inter-area multicast routing).
+
+           Bit 2, if set, indicates that  the  router  can
+           forward  IP  multicast  datagrams between Auto-
+           nomous Systems (called inter-AS multicast rout-
+           ing).
+
+           Only certain combinations of bit  settings  are
+           allowed,  namely: 0 (no multicast forwarding is
+           enabled), 1 (intra-area multicasting  only),  3
+           (intra-area  and  inter-area  multicasting),  5
+           (intra-area and inter-AS  multicasting)  and  7
+           (multicasting  everywhere). By default, no mul-
+           ticast forwarding is enabled."
+       DEFVAL { 0 }
+       ::= { ospfGeneralGroup 12 }
+
+    ospfExitOverflowInterval OBJECT-TYPE
+        SYNTAX   PositiveInteger
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "The number of  seconds  that,  after  entering
+           OverflowState,  a  router will attempt to leave
+           OverflowState. This allows the router to  again
+           originate  non-default  AS-external-LSAs.  When
+           set to 0, the router will not  leave  Overflow-
+           State until restarted."
+       DEFVAL { 0 }
+       ::= { ospfGeneralGroup 13 }
+
+
+    ospfDemandExtensions OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "The router's support for demand routing."
+       REFERENCE
+          "OSPF Version 2, Appendix on Demand Routing"
+      ::= { ospfGeneralGroup 14 }
+
+
+--      The OSPF Area Data Structure contains information
+--      regarding the various areas. The interfaces and
+--      virtual links are configured as part of these areas.
+--      Area 0.0.0.0, by definition, is the Backbone Area
+
+
+    ospfAreaTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfAreaEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "Information describing the configured  parame-
+           ters  and cumulative statistics of the router's
+           attached areas."
+       REFERENCE
+          "OSPF Version 2, Section 6  The Area Data Struc-
+          ture"
+      ::= { ospf 2 }
+
+
+    ospfAreaEntry OBJECT-TYPE
+        SYNTAX   OspfAreaEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "Information describing the configured  parame-
+           ters  and  cumulative  statistics of one of the
+           router's attached areas."
+       INDEX { ospfAreaId }
+       ::= { ospfAreaTable 1 }
+
+OspfAreaEntry ::=
+    SEQUENCE {
+        ospfAreaId
+            AreaID,
+        ospfAuthType
+            Integer32,
+        ospfImportAsExtern
+            INTEGER,
+        ospfSpfRuns
+            Counter32,
+        ospfAreaBdrRtrCount
+            Gauge32,
+        ospfAsBdrRtrCount
+            Gauge32,
+        ospfAreaLsaCount
+            Gauge32,
+        ospfAreaLsaCksumSum
+            Integer32,
+        ospfAreaSummary
+            INTEGER,
+        ospfAreaStatus
+            RowStatus
+              }
+
+    ospfAreaId OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "A 32-bit integer uniquely identifying an area.
+           Area ID 0.0.0.0 is used for the OSPF backbone."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaEntry 1 }
+
+
+    ospfAuthType OBJECT-TYPE
+        SYNTAX   Integer32
+                    -- none (0),
+                    -- simplePassword (1)
+                    -- md5 (2)
+                    -- reserved for specification by IANA (> 2)
+        MAX-ACCESS   read-create
+        STATUS   obsolete
+        DESCRIPTION
+           "The authentication type specified for an area.
+           Additional authentication types may be assigned
+           locally on a per Area basis."
+       REFERENCE
+          "OSPF Version 2, Appendix E Authentication"
+      DEFVAL { 0 }        -- no authentication, by default
+      ::= { ospfAreaEntry 2 }
+
+    ospfImportAsExtern OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    importExternal (1),
+                    importNoExternal (2),
+                    importNssa (3)
+                  }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The area's support for importing  AS  external
+           link- state advertisements."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      DEFVAL { importExternal }
+      ::= { ospfAreaEntry 3 }
+
+
+    ospfSpfRuns OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of times that the intra-area  route
+           table  has  been  calculated  using this area's
+           link-state database.  This  is  typically  done
+           using Dijkstra's algorithm."
+       ::= { ospfAreaEntry 4 }
+
+
+    ospfAreaBdrRtrCount OBJECT-TYPE
+        SYNTAX   Gauge32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The total number of area border routers reach-
+           able within this area.  This is initially zero,
+           and is calculated in each SPF Pass."
+       ::= { ospfAreaEntry 5 }
+
+    ospfAsBdrRtrCount OBJECT-TYPE
+        SYNTAX   Gauge32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The total number of Autonomous  System  border
+           routers  reachable  within  this area.  This is
+           initially zero, and is calculated in  each  SPF
+           Pass."
+       ::= { ospfAreaEntry 6 }
+
+
+    ospfAreaLsaCount OBJECT-TYPE
+        SYNTAX   Gauge32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The total number of link-state  advertisements
+           in  this  area's link-state database, excluding
+           AS External LSA's."
+       ::= { ospfAreaEntry 7 }
+
+
+    ospfAreaLsaCksumSum OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The 32-bit unsigned sum of the link-state  ad-
+           vertisements'  LS  checksums  contained in this
+           area's link-state database.  This sum  excludes
+           external (LS type 5) link-state advertisements.
+           The sum can be used to determine if  there  has
+           been  a  change  in a router's link state data-
+           base, and to compare the link-state database of
+           two routers."
+       DEFVAL   { 0 }
+       ::= { ospfAreaEntry 8 }
+
+    ospfAreaSummary OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    noAreaSummary (1),
+                    sendAreaSummary (2)
+                  }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The variable ospfAreaSummary controls the  im-
+           port  of  summary LSAs into stub areas.  It has
+           no effect on other areas.
+
+           If it is noAreaSummary, the router will neither
+           originate  nor  propagate summary LSAs into the
+           stub area.  It will rely entirely  on  its  de-
+           fault route.
+
+           If it is sendAreaSummary, the router will  both
+           summarize and propagate summary LSAs."
+       DEFVAL   { noAreaSummary }
+       ::= { ospfAreaEntry 9 }
+
+
+    ospfAreaStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfAreaEntry 10 }
+
+
+--  OSPF Area Default Metric Table
+
+--      The OSPF Area Default Metric Table describes the metrics
+--      that a default Area Border Router will advertise into a
+--      Stub area.
+
+
+    ospfStubAreaTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfStubAreaEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The set of metrics that will be advertised  by
+           a default Area Border Router into a stub area."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2, Area Parameters"
+      ::= { ospf 3 }
+
+
+    ospfStubAreaEntry OBJECT-TYPE
+        SYNTAX   OspfStubAreaEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The metric for a given Type  of  Service  that
+           will  be  advertised  by  a default Area Border
+           Router into a stub area."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2, Area Parameters"
+      INDEX { ospfStubAreaId, ospfStubTOS }
+      ::= { ospfStubAreaTable 1 }
+
+OspfStubAreaEntry ::=
+    SEQUENCE {
+        ospfStubAreaId
+            AreaID,
+        ospfStubTOS
+            TOSType,
+        ospfStubMetric
+            BigMetric,
+        ospfStubStatus
+            RowStatus,
+        ospfStubMetricType
+            INTEGER
+              }
+
+    ospfStubAreaId OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The 32 bit identifier for the Stub  Area.   On
+           creation,  this  can  be  derived  from the in-
+           stance."
+       ::= { ospfStubAreaEntry 1 }
+
+
+    ospfStubTOS OBJECT-TYPE
+        SYNTAX   TOSType
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The  Type  of  Service  associated  with   the
+           metric.   On creation, this can be derived from
+           the instance."
+       ::= { ospfStubAreaEntry 2 }
+
+
+    ospfStubMetric OBJECT-TYPE
+        SYNTAX   BigMetric
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The metric value applied at the indicated type
+           of  service.  By default, this equals the least
+           metric at the type of service among the  inter-
+           faces to other areas."
+       ::= { ospfStubAreaEntry 3 }
+
+
+    ospfStubStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfStubAreaEntry 4 }
+
+    ospfStubMetricType OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    ospfMetric (1),                -- OSPF Metric
+                    comparableCost (2),        -- external type 1
+                    nonComparable  (3)        -- external type 2
+                  }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the type of metric  ad-
+           vertised as a default route."
+       DEFVAL   { ospfMetric }
+       ::= { ospfStubAreaEntry 5 }
+
+--  OSPF Link State Database
+
+--      The Link State Database contains the Link State
+--      Advertisements from throughout the areas that the
+--      device is attached to.
+
+
+    ospfLsdbTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfLsdbEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The OSPF Process's Link State Database."
+       REFERENCE
+          "OSPF Version 2, Section 12  Link  State  Adver-
+          tisements"
+      ::= { ospf 4 }
+
+
+    ospfLsdbEntry OBJECT-TYPE
+        SYNTAX   OspfLsdbEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A single Link State Advertisement."
+       INDEX { ospfLsdbAreaId, ospfLsdbType,
+               ospfLsdbLsid, ospfLsdbRouterId }
+       ::= { ospfLsdbTable 1 }
+
+OspfLsdbEntry ::=
+    SEQUENCE {
+        ospfLsdbAreaId
+            AreaID,
+        ospfLsdbType
+            INTEGER,
+        ospfLsdbLsid
+            IpAddress,
+        ospfLsdbRouterId
+            RouterID,
+        ospfLsdbSequence
+            Integer32,
+        ospfLsdbAge
+            Integer32,
+        ospfLsdbChecksum
+            Integer32,
+        ospfLsdbAdvertisement
+            OCTET STRING
+              }
+    ospfLsdbAreaId OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The 32 bit identifier of the Area  from  which
+           the LSA was received."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfLsdbEntry 1 }
+
+-- External Link State Advertisements are permitted
+-- for backward compatibility, but should be displayed in
+-- the ospfExtLsdbTable rather than here.
+
+    ospfLsdbType OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    routerLink (1),
+                    networkLink (2),
+                    summaryLink (3),
+                    asSummaryLink (4),
+                    asExternalLink (5), -- but see ospfExtLsdbTable
+                    multicastLink (6),
+                    nssaExternalLink (7)
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The type  of  the  link  state  advertisement.
+           Each  link state type has a separate advertise-
+           ment format."
+       REFERENCE
+          "OSPF Version 2, Appendix A.4.1 The  Link  State
+          Advertisement header"
+      ::= { ospfLsdbEntry 2 }
+
+    ospfLsdbLsid OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Link State ID is an LS Type Specific field
+           containing either a Router ID or an IP Address;
+           it identifies the piece of the  routing  domain
+           that is being described by the advertisement."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.4 Link State ID"
+      ::= { ospfLsdbEntry 3 }
+    ospfLsdbRouterId OBJECT-TYPE
+        SYNTAX   RouterID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The 32 bit number that uniquely identifies the
+           originating router in the Autonomous System."
+       REFERENCE
+          "OSPF Version 2, Appendix C.1 Global parameters"
+      ::= { ospfLsdbEntry 4 }
+
+--  Note that the OSPF Sequence Number is a 32 bit signed
+--  integer.  It starts with the value '80000001'h,
+--  or -'7FFFFFFF'h, and increments until '7FFFFFFF'h
+--  Thus, a typical sequence number will be very negative.
+
+    ospfLsdbSequence OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The sequence number field is a  signed  32-bit
+           integer.   It  is used to detect old and dupli-
+           cate link state advertisements.  The  space  of
+           sequence  numbers  is  linearly  ordered.   The
+           larger the sequence number the more recent  the
+           advertisement."
+       REFERENCE
+          "OSPF Version  2,  Section  12.1.6  LS  sequence
+          number"
+      ::= { ospfLsdbEntry 5 }
+
+
+    ospfLsdbAge OBJECT-TYPE
+        SYNTAX   Integer32    -- Should be 0..MaxAge
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "This field is the age of the link state adver-
+           tisement in seconds."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.1 LS age"
+      ::= { ospfLsdbEntry 6 }
+
+    ospfLsdbChecksum OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "This field is the  checksum  of  the  complete
+           contents  of  the  advertisement, excepting the
+           age field.  The age field is excepted  so  that
+           an   advertisement's  age  can  be  incremented
+           without updating the  checksum.   The  checksum
+           used  is  the same that is used for ISO connec-
+           tionless datagrams; it is commonly referred  to
+           as the Fletcher checksum."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.7 LS checksum"
+      ::= { ospfLsdbEntry 7 }
+
+
+    ospfLsdbAdvertisement OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE (1..65535))
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The entire Link State Advertisement, including
+           its header."
+       REFERENCE
+          "OSPF Version 2, Section 12  Link  State  Adver-
+          tisements"
+      ::= { ospfLsdbEntry 8 }
+
+
+--  Address Range Table
+
+--      The Address Range Table acts as an adjunct to the Area
+--      Table; It describes those Address Range Summaries that
+--      are configured to be propagated from an Area to reduce
+--      the amount of information about it which is known beyond
+--      its borders.
+
+    ospfAreaRangeTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfAreaRangeEntry
+        MAX-ACCESS   not-accessible
+        STATUS   obsolete
+        DESCRIPTION
+           "A range if IP addresses  specified  by  an  IP
+           address/IP  network  mask  pair.   For example,
+           class B address range of X.X.X.X with a network
+           mask  of  255.255.0.0 includes all IP addresses
+           from X.X.0.0 to X.X.255.255"
+       REFERENCE
+          "OSPF Version 2, Appendix C.2  Area parameters"
+      ::= { ospf 5 }
+    ospfAreaRangeEntry OBJECT-TYPE
+        SYNTAX   OspfAreaRangeEntry
+        MAX-ACCESS   not-accessible
+        STATUS   obsolete
+        DESCRIPTION
+           "A range if IP addresses  specified  by  an  IP
+           address/IP  network  mask  pair.   For example,
+           class B address range of X.X.X.X with a network
+           mask  of  255.255.0.0 includes all IP addresses
+           from X.X.0.0 to X.X.255.255"
+       REFERENCE
+          "OSPF Version 2, Appendix C.2  Area parameters"
+      INDEX { ospfAreaRangeAreaId, ospfAreaRangeNet }
+      ::= { ospfAreaRangeTable 1 }
+
+OspfAreaRangeEntry ::=
+    SEQUENCE {
+        ospfAreaRangeAreaId
+            AreaID,
+        ospfAreaRangeNet
+            IpAddress,
+        ospfAreaRangeMask
+            IpAddress,
+        ospfAreaRangeStatus
+            RowStatus,
+        ospfAreaRangeEffect
+            INTEGER
+              }
+
+    ospfAreaRangeAreaId OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   obsolete
+        DESCRIPTION
+           "The Area the Address  Range  is  to  be  found
+           within."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaRangeEntry 1 }
+
+
+    ospfAreaRangeNet OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   obsolete
+        DESCRIPTION
+           "The IP Address of the Net or Subnet  indicated
+           by the range."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaRangeEntry 2 }
+
+
+    ospfAreaRangeMask OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-create
+        STATUS   obsolete
+        DESCRIPTION
+           "The Subnet Mask that pertains to  the  Net  or
+           Subnet."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaRangeEntry 3 }
+
+    ospfAreaRangeStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   obsolete
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfAreaRangeEntry 4 }
+
+
+    ospfAreaRangeEffect OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    advertiseMatching (1),
+                    doNotAdvertiseMatching (2)
+                  }
+        MAX-ACCESS   read-create
+        STATUS   obsolete
+        DESCRIPTION
+           "Subnets subsumed by ranges either trigger  the
+           advertisement  of the indicated summary (adver-
+           tiseMatching), or result in  the  subnet's  not
+           being advertised at all outside the area."
+       DEFVAL   { advertiseMatching }
+       ::= { ospfAreaRangeEntry 5 }
+
+
+
+--  OSPF Host Table
+
+--      The Host/Metric Table indicates what hosts are directly
+--      attached to the Router, and what metrics and types of
+--      service should be advertised for them.
+
+    ospfHostTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfHostEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The list of Hosts, and their metrics, that the
+           router will advertise as host routes."
+       REFERENCE
+          "OSPF Version 2, Appendix C.6  Host route param-
+          eters"
+      ::= { ospf 6 }
+
+
+    ospfHostEntry OBJECT-TYPE
+        SYNTAX   OspfHostEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A metric to be advertised, for a given type of
+           service, when a given host is reachable."
+       INDEX { ospfHostIpAddress, ospfHostTOS }
+       ::= { ospfHostTable 1 }
+
+OspfHostEntry ::=
+    SEQUENCE {
+        ospfHostIpAddress
+            IpAddress,
+        ospfHostTOS
+            TOSType,
+        ospfHostMetric
+            Metric,
+        ospfHostStatus
+            RowStatus,
+        ospfHostAreaID
+            AreaID
+              }
+
+    ospfHostIpAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of the Host."
+       REFERENCE
+          "OSPF Version 2, Appendix C.6 Host route parame-
+          ters"
+      ::= { ospfHostEntry 1 }
+
+
+    ospfHostTOS OBJECT-TYPE
+        SYNTAX   TOSType
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Type of Service of the route being config-
+           ured."
+       REFERENCE
+          "OSPF Version 2, Appendix C.6 Host route parame-
+          ters"
+      ::= { ospfHostEntry 2 }
+
+
+    ospfHostMetric OBJECT-TYPE
+        SYNTAX   Metric
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The Metric to be advertised."
+       REFERENCE
+          "OSPF Version 2, Appendix C.6 Host route parame-
+          ters"
+      ::= { ospfHostEntry 3 }
+
+    ospfHostStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfHostEntry 4 }
+
+
+    ospfHostAreaID OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Area the Host Entry is to be found within.
+           By  default, the area that a subsuming OSPF in-
+           terface is in, or 0.0.0.0"
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfHostEntry 5 }
+
+
+--  OSPF Interface Table
+
+--      The OSPF Interface Table augments the ipAddrTable
+--             with OSPF specific information.
+
+    ospfIfTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfIfEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The OSPF Interface Table describes the  inter-
+           faces from the viewpoint of OSPF."
+       REFERENCE
+          "OSPF Version 2, Appendix C.3  Router  interface
+          parameters"
+      ::= { ospf 7 }
+
+
+    ospfIfEntry OBJECT-TYPE
+        SYNTAX   OspfIfEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The OSPF Interface Entry describes one  inter-
+           face from the viewpoint of OSPF."
+       INDEX { ospfIfIpAddress, ospfAddressLessIf }
+       ::= { ospfIfTable 1 }
+
+OspfIfEntry ::=
+    SEQUENCE {
+        ospfIfIpAddress
+            IpAddress,
+        ospfAddressLessIf
+            Integer32,
+        ospfIfAreaId
+            AreaID,
+        ospfIfType
+            INTEGER,
+        ospfIfAdminStat
+            Status,
+        ospfIfRtrPriority
+            DesignatedRouterPriority,
+        ospfIfTransitDelay
+            UpToMaxAge,
+        ospfIfRetransInterval
+            UpToMaxAge,
+        ospfIfHelloInterval
+            HelloRange,
+        ospfIfRtrDeadInterval
+            PositiveInteger,
+        ospfIfPollInterval
+            PositiveInteger,
+        ospfIfState
+            INTEGER,
+        ospfIfDesignatedRouter
+            IpAddress,
+        ospfIfBackupDesignatedRouter
+            IpAddress,
+        ospfIfEvents
+            Counter32,
+        ospfIfAuthType
+            INTEGER,
+        ospfIfAuthKey
+            OCTET STRING,
+        ospfIfStatus
+            RowStatus,
+        ospfIfMulticastForwarding
+            INTEGER,
+        ospfIfDemand
+            TruthValue
+              }
+
+    ospfIfIpAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP address of this OSPF interface."
+       ::= { ospfIfEntry 1 }
+
+    ospfAddressLessIf OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "For the purpose of easing  the  instancing  of
+           addressed   and  addressless  interfaces;  This
+           variable takes the value 0 on  interfaces  with
+           IP  Addresses,  and  the corresponding value of
+           ifIndex for interfaces having no IP Address."
+       ::= { ospfIfEntry 2 }
+    ospfIfAreaId OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "A 32-bit integer uniquely identifying the area
+           to  which  the  interface  connects.   Area  ID
+           0.0.0.0 is used for the OSPF backbone."
+       DEFVAL   { '00000000'H }    -- 0.0.0.0
+       ::= { ospfIfEntry 3 }
+
+    ospfIfType OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    broadcast (1),
+                    nbma (2),
+                    pointToPoint (3),
+                    pointToMultipoint (5)
+                  }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The OSPF interface type.
+
+           By way of a default, this field may be intuited
+           from the corresponding value of ifType.  Broad-
+           cast LANs, such as  Ethernet  and  IEEE  802.5,
+           take  the  value  'broadcast', X.25 and similar
+           technologies take the value 'nbma',  and  links
+           that  are  definitively point to point take the
+           value 'pointToPoint'."
+       ::= { ospfIfEntry 4 }
+
+
+    ospfIfAdminStat OBJECT-TYPE
+        SYNTAX   Status
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The OSPF  interface's  administrative  status.
+           The  value formed on the interface, and the in-
+           terface will be advertised as an internal route
+           to  some  area.   The  value 'disabled' denotes
+           that the interface is external to OSPF."
+       DEFVAL { enabled }
+       ::= { ospfIfEntry 5 }
+
+    ospfIfRtrPriority OBJECT-TYPE
+        SYNTAX   DesignatedRouterPriority
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The  priority  of  this  interface.   Used  in
+           multi-access  networks,  this  field is used in
+           the designated router election algorithm.   The
+           value 0 signifies that the router is not eligi-
+           ble to become the  designated  router  on  this
+           particular  network.   In the event of a tie in
+           this value, routers will use their Router ID as
+           a tie breaker."
+       DEFVAL { 1 }
+       ::= { ospfIfEntry 6 }
+
+
+    ospfIfTransitDelay OBJECT-TYPE
+        SYNTAX   UpToMaxAge
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The estimated number of seconds  it  takes  to
+           transmit  a  link state update packet over this
+           interface."
+       DEFVAL { 1 }
+       ::= { ospfIfEntry 7 }
+
+
+    ospfIfRetransInterval OBJECT-TYPE
+        SYNTAX   UpToMaxAge
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The number of seconds between  link-state  ad-
+           vertisement  retransmissions,  for  adjacencies
+           belonging to this  interface.   This  value  is
+           also used when retransmitting database descrip-
+           tion and link-state request packets."
+       DEFVAL { 5 }
+       ::= { ospfIfEntry 8 }
+
+
+    ospfIfHelloInterval OBJECT-TYPE
+        SYNTAX   HelloRange
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The length of time, in  seconds,  between  the
+           Hello  packets that the router sends on the in-
+           terface.  This value must be the same  for  all
+           routers attached to a common network."
+       DEFVAL { 10 }
+       ::= { ospfIfEntry 9 }
+
+
+    ospfIfRtrDeadInterval OBJECT-TYPE
+        SYNTAX   PositiveInteger
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The number of seconds that  a  router's  Hello
+           packets  have  not been seen before it's neigh-
+           bors declare the router down.  This  should  be
+           some  multiple  of  the  Hello  interval.  This
+           value must be the same for all routers attached
+           to a common network."
+       DEFVAL { 40 }
+       ::= { ospfIfEntry 10 }
+
+
+    ospfIfPollInterval OBJECT-TYPE
+        SYNTAX   PositiveInteger
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The larger time interval, in seconds,  between
+           the  Hello  packets  sent  to  an inactive non-
+           broadcast multi- access neighbor."
+       DEFVAL { 120 }
+       ::= { ospfIfEntry 11 }
+
+
+    ospfIfState OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    down (1),
+                    loopback (2),
+                    waiting (3),
+                    pointToPoint (4),
+                    designatedRouter (5),
+                    backupDesignatedRouter (6),
+                    otherDesignatedRouter (7)
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The OSPF Interface State."
+       DEFVAL { down }
+       ::= { ospfIfEntry 12 }
+
+
+    ospfIfDesignatedRouter OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of the Designated Router."
+       DEFVAL   { '00000000'H }    -- 0.0.0.0
+       ::= { ospfIfEntry 13 }
+
+
+    ospfIfBackupDesignatedRouter OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The  IP  Address  of  the  Backup   Designated
+           Router."
+       DEFVAL   { '00000000'H }    -- 0.0.0.0
+       ::= { ospfIfEntry 14 }
+
+    ospfIfEvents OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of times this  OSPF  interface  has
+           changed its state, or an error has occurred."
+       ::= { ospfIfEntry 15 }
+
+
+    ospfIfAuthKey OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE (0..256))
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The Authentication Key.  If the Area's Author-
+           ization  Type  is  simplePassword,  and the key
+           length is shorter than 8 octets, the agent will
+           left adjust and zero fill to 8 octets.
+
+           Note that unauthenticated  interfaces  need  no
+           authentication key, and simple password authen-
+           tication cannot use a key of more  than  8  oc-
+           tets.  Larger keys are useful only with authen-
+           tication mechanisms not specified in this docu-
+           ment.
+
+           When read, ospfIfAuthKey always returns an  Oc-
+           tet String of length zero."
+       REFERENCE
+          "OSPF Version 2, Section 9  The  Interface  Data
+          Structure"
+      DEFVAL   { '0000000000000000'H }    -- 0.0.0.0.0.0.0.0
+      ::= { ospfIfEntry 16 }
+
+    ospfIfStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfIfEntry 17 }
+
+
+    ospfIfMulticastForwarding OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                            blocked (1),        -- no multicast forwarding
+                            multicast (2),        -- using multicast address
+                            unicast (3)        -- to each OSPF neighbor
+                  }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The way multicasts should  forwarded  on  this
+           interface;  not  forwarded,  forwarded  as data
+           link multicasts, or forwarded as data link uni-
+           casts.   Data link multicasting is not meaning-
+           ful on point to point and NBMA interfaces,  and
+           setting ospfMulticastForwarding to 0 effective-
+           ly disables all multicast forwarding."
+       DEFVAL { blocked }
+       ::= { ospfIfEntry 18 }
+
+
+    ospfIfDemand OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "Indicates whether Demand OSPF procedures (hel-
+           lo supression to FULL neighbors and setting the
+           DoNotAge flag on proogated LSAs) should be per-
+           formed on this interface."
+       DEFVAL { false }
+       ::= { ospfIfEntry 19 }
+
+
+    ospfIfAuthType OBJECT-TYPE
+        SYNTAX   INTEGER (0..255)
+                    -- none (0),
+                    -- simplePassword (1)
+                    -- md5 (2)
+                    -- reserved for specification by IANA (> 2)
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The authentication type specified for  an  in-
+           terface.   Additional  authentication types may
+           be assigned locally."
+       REFERENCE
+          "OSPF Version 2, Appendix E Authentication"
+      DEFVAL { 0 }        -- no authentication, by default
+      ::= { ospfIfEntry 20 }
+
+
+--  OSPF Interface Metric Table
+
+--      The Metric Table describes the metrics to be advertised
+--      for a specified interface at the various types of service.
+--      As such, this table is an adjunct of the OSPF Interface
+--      Table.
+
+-- Types of service, as defined by RFC 791, have the ability
+-- to request low delay, high bandwidth, or reliable linkage.
+
+-- For the purposes of this specification, the measure of
+-- bandwidth
+
+--      Metric = 10^8 / ifSpeed
+
+-- is the default value.  For multiple link interfaces, note
+-- that ifSpeed is the sum of the individual link speeds.
+-- This yields a number having the following typical values:
+
+--      Network Type/bit rate   Metric
+
+--      >= 100 MBPS                 1
+--      Ethernet/802.3             10
+--      E1                         48
+--      T1 (ESF)                   65
+--       64 KBPS                 1562
+--       56 KBPS                 1785
+--       19.2 KBPS               5208
+--        9.6 KBPS              10416
+
+-- Routes that are not specified use the default (TOS 0) metric
+
+    ospfIfMetricTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfIfMetricEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The TOS metrics for  a  non-virtual  interface
+           identified by the interface index."
+       REFERENCE
+          "OSPF Version 2, Appendix C.3  Router  interface
+          parameters"
+      ::= { ospf 8 }
+
+    ospfIfMetricEntry OBJECT-TYPE
+        SYNTAX   OspfIfMetricEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A particular TOS metric for a non-virtual  in-
+           terface identified by the interface index."
+       REFERENCE
+          "OSPF Version 2, Appendix C.3  Router  interface
+          parameters"
+      INDEX { ospfIfMetricIpAddress,
+  ospfIfMetricAddressLessIf,
+  ospfIfMetricTOS }
+      ::= { ospfIfMetricTable 1 }
+
+OspfIfMetricEntry ::=
+    SEQUENCE {
+        ospfIfMetricIpAddress
+            IpAddress,
+        ospfIfMetricAddressLessIf
+            Integer32,
+        ospfIfMetricTOS
+            TOSType,
+        ospfIfMetricValue
+            Metric,
+        ospfIfMetricStatus
+            RowStatus
+              }
+
+    ospfIfMetricIpAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP address of this OSPF interface.  On row
+           creation,  this  can  be  derived  from the in-
+           stance."
+       ::= { ospfIfMetricEntry 1 }
+
+    ospfIfMetricAddressLessIf OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "For the purpose of easing  the  instancing  of
+           addressed   and  addressless  interfaces;  This
+           variable takes the value 0 on  interfaces  with
+           IP  Addresses, and the value of ifIndex for in-
+           terfaces having no IP Address.   On  row  crea-
+           tion, this can be derived from the instance."
+       ::= { ospfIfMetricEntry 2 }
+
+
+    ospfIfMetricTOS OBJECT-TYPE
+        SYNTAX   TOSType
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The type of service metric  being  referenced.
+           On  row  creation, this can be derived from the
+           instance."
+       ::= { ospfIfMetricEntry 3 }
+
+
+    ospfIfMetricValue OBJECT-TYPE
+        SYNTAX   Metric
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The metric of using this type  of  service  on
+           this interface.  The default value of the TOS 0
+           Metric is 10^8 / ifSpeed."
+       ::= { ospfIfMetricEntry 4 }
+
+    ospfIfMetricStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfIfMetricEntry 5 }
+
+
+--  OSPF Virtual Interface Table
+
+--      The Virtual Interface Table describes the virtual
+--      links that the OSPF Process is configured to
+--      carry on.
+
+    ospfVirtIfTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfVirtIfEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "Information about this router's virtual inter-
+           faces."
+       REFERENCE
+          "OSPF Version  2,  Appendix  C.4   Virtual  link
+          parameters"
+      ::= { ospf 9 }
+
+
+    ospfVirtIfEntry OBJECT-TYPE
+        SYNTAX   OspfVirtIfEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "Information about a single Virtual Interface."
+       INDEX { ospfVirtIfAreaId, ospfVirtIfNeighbor }
+       ::= { ospfVirtIfTable 1 }
+
+OspfVirtIfEntry ::=
+    SEQUENCE {
+        ospfVirtIfAreaId
+            AreaID,
+        ospfVirtIfNeighbor
+            RouterID,
+        ospfVirtIfTransitDelay
+            UpToMaxAge,
+        ospfVirtIfRetransInterval
+            UpToMaxAge,
+        ospfVirtIfHelloInterval
+            HelloRange,
+        ospfVirtIfRtrDeadInterval
+            PositiveInteger,
+        ospfVirtIfState
+            INTEGER,
+        ospfVirtIfEvents
+            Counter32,
+        ospfVirtIfAuthType
+            INTEGER,
+        ospfVirtIfAuthKey
+            OCTET STRING,
+        ospfVirtIfStatus
+            RowStatus
+              }
+
+    ospfVirtIfAreaId OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The  Transit  Area  that  the   Virtual   Link
+           traverses.  By definition, this is not 0.0.0.0"
+       ::= { ospfVirtIfEntry 1 }
+
+
+    ospfVirtIfNeighbor OBJECT-TYPE
+        SYNTAX   RouterID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Router ID of the Virtual Neighbor."
+       ::= { ospfVirtIfEntry 2 }
+
+
+    ospfVirtIfTransitDelay OBJECT-TYPE
+        SYNTAX   UpToMaxAge
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The estimated number of seconds  it  takes  to
+           transmit  a link- state update packet over this
+           interface."
+       DEFVAL { 1 }
+       ::= { ospfVirtIfEntry 3 }
+
+
+    ospfVirtIfRetransInterval OBJECT-TYPE
+        SYNTAX   UpToMaxAge
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The number of seconds between  link-state  ad-
+           vertisement  retransmissions,  for  adjacencies
+           belonging to this  interface.   This  value  is
+           also used when retransmitting database descrip-
+           tion  and  link-state  request  packets.   This
+           value  should  be well over the expected round-
+           trip time."
+       DEFVAL { 5 }
+       ::= { ospfVirtIfEntry 4 }
+
+
+    ospfVirtIfHelloInterval OBJECT-TYPE
+        SYNTAX   HelloRange
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The length of time, in  seconds,  between  the
+           Hello  packets that the router sends on the in-
+           terface.  This value must be the same  for  the
+           virtual neighbor."
+       DEFVAL { 10 }
+       ::= { ospfVirtIfEntry 5 }
+
+
+    ospfVirtIfRtrDeadInterval OBJECT-TYPE
+        SYNTAX   PositiveInteger
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The number of seconds that  a  router's  Hello
+           packets  have  not been seen before it's neigh-
+           bors declare the router down.  This  should  be
+           some  multiple  of  the  Hello  interval.  This
+           value must be the same for the  virtual  neigh-
+           bor."
+       DEFVAL { 60 }
+       ::= { ospfVirtIfEntry 6 }
+
+
+    ospfVirtIfState OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    down (1),            -- these use the same encoding
+                    pointToPoint (4)     -- as the ospfIfTable
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "OSPF virtual interface states."
+       DEFVAL   { down }
+       ::= { ospfVirtIfEntry 7 }
+
+
+    ospfVirtIfEvents OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of state changes or error events on
+           this Virtual Link"
+       ::= { ospfVirtIfEntry 8 }
+
+
+    ospfVirtIfAuthKey OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE(0..256))
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "If Authentication Type is simplePassword,  the
+           device  will left adjust and zero fill to 8 oc-
+           tets.
+
+           Note that unauthenticated  interfaces  need  no
+           authentication key, and simple password authen-
+           tication cannot use a key of more  than  8  oc-
+           tets.  Larger keys are useful only with authen-
+           tication mechanisms not specified in this docu-
+           ment.
+
+           When  read,  ospfVifAuthKey  always  returns  a
+           string of length zero."
+       REFERENCE
+          "OSPF Version 2, Section 9  The  Interface  Data
+          Structure"
+      DEFVAL   { '0000000000000000'H }    -- 0.0.0.0.0.0.0.0
+      ::= { ospfVirtIfEntry 9 }
+
+
+    ospfVirtIfStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfVirtIfEntry 10 }
+
+
+    ospfVirtIfAuthType OBJECT-TYPE
+        SYNTAX   INTEGER (0..255)
+                    -- none (0),
+                    -- simplePassword (1)
+                    -- md5 (2)
+                    -- reserved for specification by IANA (> 2)
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The authentication type specified for a virtu-
+           al  interface.  Additional authentication types
+           may be assigned locally."
+       REFERENCE
+          "OSPF Version 2, Appendix E Authentication"
+      DEFVAL { 0 }        -- no authentication, by default
+      ::= { ospfVirtIfEntry 11 }
+
+
+--  OSPF Neighbor Table
+
+--      The OSPF Neighbor Table describes all neighbors in
+--      the locality of the subject router.
+
+    ospfNbrTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfNbrEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A table of non-virtual neighbor information."
+       REFERENCE
+          "OSPF Version 2, Section 10  The  Neighbor  Data
+          Structure"
+      ::= { ospf 10 }
+
+
+    ospfNbrEntry OBJECT-TYPE
+        SYNTAX   OspfNbrEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The information regarding a single neighbor."
+       REFERENCE
+          "OSPF Version 2, Section 10  The  Neighbor  Data
+          Structure"
+      INDEX { ospfNbrIpAddr, ospfNbrAddressLessIndex }
+      ::= { ospfNbrTable 1 }
+
+OspfNbrEntry ::=
+    SEQUENCE {
+        ospfNbrIpAddr
+            IpAddress,
+        ospfNbrAddressLessIndex
+            InterfaceIndex,
+        ospfNbrRtrId
+            RouterID,
+        ospfNbrOptions
+            Integer32,
+        ospfNbrPriority
+            DesignatedRouterPriority,
+        ospfNbrState
+            INTEGER,
+        ospfNbrEvents
+            Counter32,
+        ospfNbrLsRetransQLen
+            Gauge32,
+        ospfNbmaNbrStatus
+            RowStatus,
+        ospfNbmaNbrPermanence
+            INTEGER,
+        ospfNbrHelloSuppressed
+            TruthValue
+              }
+
+    ospfNbrIpAddr OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP address this neighbor is using  in  its
+           IP  Source  Address.  Note that, on addressless
+           links, this will not be 0.0.0.0,  but  the  ad-
+           dress of another of the neighbor's interfaces."
+       ::= { ospfNbrEntry 1 }
+
+
+    ospfNbrAddressLessIndex OBJECT-TYPE
+        SYNTAX   InterfaceIndex
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "On an interface having an  IP  Address,  zero.
+           On  addressless  interfaces,  the corresponding
+           value of ifIndex in the Internet Standard  MIB.
+           On  row  creation, this can be derived from the
+           instance."
+       ::= { ospfNbrEntry 2 }
+
+
+    ospfNbrRtrId OBJECT-TYPE
+        SYNTAX   RouterID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "A 32-bit integer (represented as a type  IpAd-
+           dress)  uniquely  identifying  the  neighboring
+           router in the Autonomous System."
+       DEFVAL   { '00000000'H }    -- 0.0.0.0
+       ::= { ospfNbrEntry 3 }
+
+
+    ospfNbrOptions OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "A Bit Mask corresponding to the neighbor's op-
+           tions field.
+
+           Bit 0, if set, indicates that the  system  will
+           operate  on  Type of Service metrics other than
+           TOS 0.  If zero, the neighbor will  ignore  all
+           metrics except the TOS 0 metric.
+
+           Bit 1, if set, indicates  that  the  associated
+           area  accepts and operates on external informa-
+           tion; if zero, it is a stub area.
+
+           Bit 2, if set, indicates that the system is ca-
+           pable  of routing IP Multicast datagrams; i.e.,
+           that it implements the Multicast Extensions  to
+           OSPF.
+
+           Bit 3, if set, indicates  that  the  associated
+           area  is  an  NSSA.  These areas are capable of
+           carrying type 7 external advertisements,  which
+           are  translated into type 5 external advertise-
+           ments at NSSA borders."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.2 Options"
+      DEFVAL { 0 }
+      ::= { ospfNbrEntry 4 }
+
+
+    ospfNbrPriority OBJECT-TYPE
+        SYNTAX   DesignatedRouterPriority
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The priority of this neighbor in the designat-
+           ed router election algorithm.  The value 0 sig-
+           nifies that the neighbor is not eligible to be-
+           come  the  designated router on this particular
+           network."
+       DEFVAL { 1 }
+       ::= { ospfNbrEntry 5 }
+
+
+    ospfNbrState OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    down (1),
+                    attempt (2),
+                    init (3),
+                    twoWay (4),
+                    exchangeStart (5),
+                    exchange (6),
+                    loading (7),
+                    full (8)
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The State of the relationship with this Neigh-
+           bor."
+       REFERENCE
+          "OSPF Version 2, Section 10.1 Neighbor States"
+      DEFVAL   { down }
+      ::= { ospfNbrEntry 6 }
+
+
+    ospfNbrEvents OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of times this neighbor relationship
+           has changed state, or an error has occurred."
+       ::= { ospfNbrEntry 7 }
+
+
+    ospfNbrLsRetransQLen OBJECT-TYPE
+        SYNTAX   Gauge32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The  current  length  of  the   retransmission
+           queue."
+       ::= { ospfNbrEntry 8 }
+
+
+    ospfNbmaNbrStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfNbrEntry 9 }
+
+
+    ospfNbmaNbrPermanence OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    dynamic (1),        -- learned through protocol
+                    permanent (2)       -- configured address
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.   'dynamic'  and  'permanent' refer to how
+           the neighbor became known."
+       DEFVAL { permanent }
+       ::= { ospfNbrEntry 10 }
+
+
+    ospfNbrHelloSuppressed OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "Indicates whether Hellos are being  suppressed
+           to the neighbor"
+       ::= { ospfNbrEntry 11 }
+
+
+--  OSPF Virtual Neighbor Table
+
+--      This table describes all virtual neighbors.
+--      Since Virtual Links are configured in the
+--      virtual interface table, this table is read-only.
+
+    ospfVirtNbrTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfVirtNbrEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A table of virtual neighbor information."
+       REFERENCE
+          "OSPF Version 2, Section 15  Virtual Links"
+      ::= { ospf 11 }
+
+
+    ospfVirtNbrEntry OBJECT-TYPE
+        SYNTAX   OspfVirtNbrEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "Virtual neighbor information."
+       INDEX { ospfVirtNbrArea, ospfVirtNbrRtrId }
+       ::= { ospfVirtNbrTable 1 }
+
+OspfVirtNbrEntry ::=
+    SEQUENCE {
+        ospfVirtNbrArea
+            AreaID,
+        ospfVirtNbrRtrId
+            RouterID,
+        ospfVirtNbrIpAddr
+            IpAddress,
+        ospfVirtNbrOptions
+            Integer32,
+        ospfVirtNbrState
+            INTEGER,
+        ospfVirtNbrEvents
+            Counter32,
+        ospfVirtNbrLsRetransQLen
+            Gauge32,
+        ospfVirtNbrHelloSuppressed
+                TruthValue
+              }
+
+    ospfVirtNbrArea OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Transit Area Identifier."
+       ::= { ospfVirtNbrEntry 1 }
+
+
+    ospfVirtNbrRtrId OBJECT-TYPE
+        SYNTAX   RouterID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "A  32-bit  integer  uniquely  identifying  the
+           neighboring router in the Autonomous System."
+       ::= { ospfVirtNbrEntry 2 }
+
+
+    ospfVirtNbrIpAddr OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP address this Virtual  Neighbor  is  us-
+           ing."
+       ::= { ospfVirtNbrEntry 3 }
+
+
+    ospfVirtNbrOptions OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "A Bit Mask corresponding to the neighbor's op-
+           tions field.
+
+           Bit 1, if set, indicates that the  system  will
+           operate  on  Type of Service metrics other than
+           TOS 0.  If zero, the neighbor will  ignore  all
+           metrics except the TOS 0 metric.
+
+           Bit 2, if set, indicates  that  the  system  is
+           Network  Multicast  capable; ie, that it imple-
+           ments OSPF Multicast Routing."
+       ::= { ospfVirtNbrEntry 4 }
+    ospfVirtNbrState OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    down (1),
+                    attempt (2),
+                    init (3),
+                    twoWay (4),
+                    exchangeStart (5),
+                    exchange (6),
+                    loading (7),
+                    full (8)
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The state of the  Virtual  Neighbor  Relation-
+           ship."
+       ::= { ospfVirtNbrEntry 5 }
+
+
+    ospfVirtNbrEvents OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of  times  this  virtual  link  has
+           changed its state, or an error has occurred."
+       ::= { ospfVirtNbrEntry 6 }
+
+
+    ospfVirtNbrLsRetransQLen OBJECT-TYPE
+        SYNTAX   Gauge32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The  current  length  of  the   retransmission
+           queue."
+       ::= { ospfVirtNbrEntry 7 }
+
+
+    ospfVirtNbrHelloSuppressed OBJECT-TYPE
+        SYNTAX   TruthValue
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "Indicates whether Hellos are being  suppressed
+           to the neighbor"
+       ::= { ospfVirtNbrEntry 8 }
+
+--  OSPF Link State Database, External
+
+--      The Link State Database contains the Link State
+--      Advertisements from throughout the areas that the
+--      device is attached to.
+
+--             This table is identical to the OSPF LSDB Table in
+--      format, but contains only External Link State
+--             Advertisements.  The purpose is to allow external
+--      LSAs to be displayed once for the router rather
+--      than once in each non-stub area.
+
+    ospfExtLsdbTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfExtLsdbEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "The OSPF Process's Links State Database."
+       REFERENCE
+          "OSPF Version 2, Section 12  Link  State  Adver-
+          tisements"
+      ::= { ospf 12 }
+
+
+    ospfExtLsdbEntry OBJECT-TYPE
+        SYNTAX   OspfExtLsdbEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A single Link State Advertisement."
+       INDEX { ospfExtLsdbType, ospfExtLsdbLsid, ospfExtLsdbRouterId }
+       ::= { ospfExtLsdbTable 1 }
+
+OspfExtLsdbEntry ::=
+    SEQUENCE {
+        ospfExtLsdbType
+            INTEGER,
+        ospfExtLsdbLsid
+            IpAddress,
+        ospfExtLsdbRouterId
+            RouterID,
+        ospfExtLsdbSequence
+            Integer32,
+        ospfExtLsdbAge
+            Integer32,
+        ospfExtLsdbChecksum
+            Integer32,
+        ospfExtLsdbAdvertisement
+            OCTET STRING
+              }
+
+    ospfExtLsdbType OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    asExternalLink (5)
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The type  of  the  link  state  advertisement.
+           Each  link state type has a separate advertise-
+           ment format."
+       REFERENCE
+          "OSPF Version 2, Appendix A.4.1 The  Link  State
+          Advertisement header"
+      ::= { ospfExtLsdbEntry 1 }
+
+
+    ospfExtLsdbLsid OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Link State ID is an LS Type Specific field
+           containing either a Router ID or an IP Address;
+           it identifies the piece of the  routing  domain
+           that is being described by the advertisement."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.4 Link State ID"
+      ::= { ospfExtLsdbEntry 2 }
+
+
+    ospfExtLsdbRouterId OBJECT-TYPE
+        SYNTAX   RouterID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The 32 bit number that uniquely identifies the
+           originating router in the Autonomous System."
+       REFERENCE
+          "OSPF Version 2, Appendix C.1 Global parameters"
+      ::= { ospfExtLsdbEntry 3 }
+
+--  Note that the OSPF Sequence Number is a 32 bit signed
+--  integer.  It starts with the value '80000001'h,
+--  or -'7FFFFFFF'h, and increments until '7FFFFFFF'h
+--  Thus, a typical sequence number will be very negative.
+    ospfExtLsdbSequence OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The sequence number field is a  signed  32-bit
+           integer.   It  is used to detect old and dupli-
+           cate link state advertisements.  The  space  of
+           sequence  numbers  is  linearly  ordered.   The
+           larger the sequence number the more recent  the
+           advertisement."
+       REFERENCE
+          "OSPF Version  2,  Section  12.1.6  LS  sequence
+          number"
+      ::= { ospfExtLsdbEntry 4 }
+
+
+    ospfExtLsdbAge OBJECT-TYPE
+        SYNTAX   Integer32    -- Should be 0..MaxAge
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "This field is the age of the link state adver-
+           tisement in seconds."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.1 LS age"
+      ::= { ospfExtLsdbEntry 5 }
+
+
+    ospfExtLsdbChecksum OBJECT-TYPE
+        SYNTAX   Integer32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "This field is the  checksum  of  the  complete
+           contents  of  the  advertisement, excepting the
+           age field.  The age field is excepted  so  that
+           an   advertisement's  age  can  be  incremented
+           without updating the  checksum.   The  checksum
+           used  is  the same that is used for ISO connec-
+           tionless datagrams; it is commonly referred  to
+           as the Fletcher checksum."
+       REFERENCE
+          "OSPF Version 2, Section 12.1.7 LS checksum"
+      ::= { ospfExtLsdbEntry 6 }
+
+
+    ospfExtLsdbAdvertisement OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE(36))
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The entire Link State Advertisement, including
+           its header."
+       REFERENCE
+          "OSPF Version 2, Section 12  Link  State  Adver-
+          tisements"
+      ::= { ospfExtLsdbEntry 7 }
+
+
+--  OSPF Use of the CIDR Route Table
+
+ospfRouteGroup           OBJECT IDENTIFIER ::= { ospf 13 }
+
+-- The IP Forwarding Table defines a number of objects for use by
+-- the routing protocol to externalize its information.  Most of
+-- the variables (ipForwardDest, ipForwardMask, ipForwardPolicy,
+-- ipForwardNextHop, ipForwardIfIndex, ipForwardType,
+-- ipForwardProto, ipForwardAge, and ipForwardNextHopAS) are
+-- defined there.
+
+-- Those that leave some discretion are defined here.
+
+-- ipCidrRouteProto is, of course, ospf (13).
+
+-- ipCidrRouteAge is the time since the route was first calculated,
+-- as opposed to the time since the last SPF run.
+
+-- ipCidrRouteInfo is an OBJECT IDENTIFIER for use by the routing
+-- protocol.  The following values shall be found there depending
+-- on the way the route was calculated.
+
+ospfIntraArea      OBJECT IDENTIFIER ::= { ospfRouteGroup 1 }
+ospfInterArea      OBJECT IDENTIFIER ::= { ospfRouteGroup 2 }
+ospfExternalType1  OBJECT IDENTIFIER ::= { ospfRouteGroup 3 }
+ospfExternalType2  OBJECT IDENTIFIER ::= { ospfRouteGroup 4 }
+
+-- ipCidrRouteMetric1 is, by definition, the primary routing
+-- metric.  Therefore, it should be the metric that route
+-- selection is based on.  For intra-area and inter-area routes,
+-- it is an OSPF metric.  For External Type 1 (comparable value)
+-- routes, it is an OSPF metric plus the External Metric.  For
+-- external Type 2 (non-comparable value) routes, it is the
+-- external metric.
+
+-- ipCidrRouteMetric2 is, by definition, a secondary routing
+-- metric.  Therefore, it should be the metric that breaks a tie
+-- among routes having equal metric1 values and the same
+-- calculation rule.  For intra-area, inter-area routes, and
+-- External Type 1 (comparable value) routes, it is unused.  For
+-- external Type 2 (non-comparable value) routes, it is the metric
+-- to the AS border router.
+
+-- ipCidrRouteMetric3, ipCidrRouteMetric4, and ipCidrRouteMetric5 are
+-- unused.
+
+--
+--      The OSPF Area Aggregate Table
+--
+--      This table replaces the OSPF Area Summary Table, being an
+--      extension of that for CIDR routers.
+
+    ospfAreaAggregateTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF OspfAreaAggregateEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A range of IP addresses  specified  by  an  IP
+           address/IP  network  mask  pair.   For example,
+           class B address range of X.X.X.X with a network
+           mask  of  255.255.0.0 includes all IP addresses
+           from X.X.0.0  to  X.X.255.255.   Note  that  if
+           ranges  are configured such that one range sub-
+           sumes  another  range  (e.g.,   10.0.0.0   mask
+           255.0.0.0  and  10.1.0.0 mask 255.255.0.0), the
+           most specific match is the preferred one."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2  Area parameters"
+      ::= { ospf 14 }
+
+
+    ospfAreaAggregateEntry OBJECT-TYPE
+        SYNTAX   OspfAreaAggregateEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A range of IP addresses  specified  by  an  IP
+           address/IP  network  mask  pair.   For example,
+           class B address range of X.X.X.X with a network
+           mask  of  255.255.0.0 includes all IP addresses
+           from X.X.0.0  to  X.X.255.255.   Note  that  if
+           ranges are range configured such that one range
+           subsumes another  range  (e.g.,  10.0.0.0  mask
+           255.0.0.0  and  10.1.0.0 mask 255.255.0.0), the
+           most specific match is the preferred one."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2  Area parameters"
+      INDEX { ospfAreaAggregateAreaID, ospfAreaAggregateLsdbType,
+              ospfAreaAggregateNet, ospfAreaAggregateMask }
+      ::= { ospfAreaAggregateTable 1 }
+
+
+OspfAreaAggregateEntry ::=
+    SEQUENCE {
+        ospfAreaAggregateAreaID
+            AreaID,
+        ospfAreaAggregateLsdbType
+            INTEGER,
+        ospfAreaAggregateNet
+            IpAddress,
+        ospfAreaAggregateMask
+            IpAddress,
+        ospfAreaAggregateStatus
+            RowStatus,
+        ospfAreaAggregateEffect
+            INTEGER
+              }
+
+    ospfAreaAggregateAreaID OBJECT-TYPE
+        SYNTAX   AreaID
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Area the Address Aggregate is to be  found
+           within."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaAggregateEntry 1 }
+
+
+    ospfAreaAggregateLsdbType OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    summaryLink (3),
+                    nssaExternalLink (7)
+                  }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The type of the Address Aggregate.  This field
+           specifies  the  Lsdb type that this Address Ag-
+           gregate applies to."
+       REFERENCE
+          "OSPF Version 2, Appendix A.4.1 The  Link  State
+          Advertisement header"
+      ::= { ospfAreaAggregateEntry 2 }
+
+
+    ospfAreaAggregateNet OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of the Net or Subnet  indicated
+           by the range."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaAggregateEntry 3 }
+
+
+    ospfAreaAggregateMask OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The Subnet Mask that pertains to  the  Net  or
+           Subnet."
+       REFERENCE
+          "OSPF Version 2, Appendix C.2 Area parameters"
+      ::= { ospfAreaAggregateEntry 4 }
+
+
+    ospfAreaAggregateStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable displays the status of  the  en-
+           try.  Setting it to 'invalid' has the effect of
+           rendering it inoperative.  The internal  effect
+           (row removal) is implementation dependent."
+       ::= { ospfAreaAggregateEntry 5 }
+
+
+    ospfAreaAggregateEffect OBJECT-TYPE
+        SYNTAX   INTEGER    {
+                    advertiseMatching (1),
+                    doNotAdvertiseMatching (2)
+                  }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "Subnets subsumed by ranges either trigger  the
+           advertisement  of  the indicated aggregate (ad-
+           vertiseMatching), or result in the subnet's not
+           being advertised at all outside the area."
+       DEFVAL   { advertiseMatching }
+       ::= { ospfAreaAggregateEntry 6 }
+
+
+-- conformance information
+
+ospfConformance OBJECT IDENTIFIER ::= { ospf 15 }
+
+ospfGroups      OBJECT IDENTIFIER ::= { ospfConformance 1 }
+ospfCompliances OBJECT IDENTIFIER ::= { ospfConformance 2 }
+
+-- compliance statements
+
+    ospfCompliance MODULE-COMPLIANCE
+        STATUS  current
+        DESCRIPTION
+           "The compliance statement "
+       MODULE  -- this module
+       MANDATORY-GROUPS {
+                    ospfBasicGroup,
+                    ospfAreaGroup,
+                    ospfStubAreaGroup,
+                    ospfIfGroup,
+                    ospfIfMetricGroup,
+                    ospfVirtIfGroup,
+                    ospfNbrGroup,
+                    ospfVirtNbrGroup,
+                    ospfAreaAggregateGroup
+           }
+       ::= { ospfCompliances 1 }
+
+
+-- units of conformance
+
+    ospfBasicGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfRouterId,
+                    ospfAdminStat,
+                    ospfVersionNumber,
+                    ospfAreaBdrRtrStatus,
+                    ospfASBdrRtrStatus,
+                    ospfExternLsaCount,
+                    ospfExternLsaCksumSum,
+                    ospfTOSSupport,
+                    ospfOriginateNewLsas,
+                    ospfRxNewLsas,
+                    ospfExtLsdbLimit,
+                    ospfMulticastExtensions,
+                    ospfExitOverflowInterval,
+                    ospfDemandExtensions
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 1 }
+
+
+    ospfAreaGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfAreaId,
+                    ospfImportAsExtern,
+                    ospfSpfRuns,
+                    ospfAreaBdrRtrCount,
+                    ospfAsBdrRtrCount,
+                    ospfAreaLsaCount,
+                    ospfAreaLsaCksumSum,
+                    ospfAreaSummary,
+                    ospfAreaStatus
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required  for  OSPF  systems
+           supporting areas."
+       ::= { ospfGroups 2 }
+
+
+    ospfStubAreaGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfStubAreaId,
+                    ospfStubTOS,
+                    ospfStubMetric,
+                    ospfStubStatus,
+                    ospfStubMetricType
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required  for  OSPF  systems
+           supporting stub areas."
+       ::= { ospfGroups 3 }
+
+
+    ospfLsdbGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfLsdbAreaId,
+                    ospfLsdbType,
+                    ospfLsdbLsid,
+                    ospfLsdbRouterId,
+                    ospfLsdbSequence,
+                    ospfLsdbAge,
+                    ospfLsdbChecksum,
+                    ospfLsdbAdvertisement
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required  for  OSPF  systems
+           that display their link state database."
+       ::= { ospfGroups 4 }
+
+
+    ospfAreaRangeGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfAreaRangeAreaId,
+                    ospfAreaRangeNet,
+                    ospfAreaRangeMask,
+                    ospfAreaRangeStatus,
+                    ospfAreaRangeEffect
+        }
+        STATUS  obsolete
+        DESCRIPTION
+           "These objects are required for  non-CIDR  OSPF
+           systems that support multiple areas."
+       ::= { ospfGroups 5 }
+
+
+    ospfHostGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfHostIpAddress,
+                    ospfHostTOS,
+                    ospfHostMetric,
+                    ospfHostStatus,
+                    ospfHostAreaID
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required  for  OSPF  systems
+           that support attached hosts."
+       ::= { ospfGroups 6 }
+
+
+    ospfIfGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfIfIpAddress,
+                    ospfAddressLessIf,
+                    ospfIfAreaId,
+                    ospfIfType,
+                    ospfIfAdminStat,
+                    ospfIfRtrPriority,
+                    ospfIfTransitDelay,
+                    ospfIfRetransInterval,
+                    ospfIfHelloInterval,
+                    ospfIfRtrDeadInterval,
+                    ospfIfPollInterval,
+                    ospfIfState,
+                    ospfIfDesignatedRouter,
+                    ospfIfBackupDesignatedRouter,
+                    ospfIfEvents,
+                    ospfIfAuthType,
+                    ospfIfAuthKey,
+                    ospfIfStatus,
+                    ospfIfMulticastForwarding,
+                    ospfIfDemand
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 7 }
+
+
+    ospfIfMetricGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfIfMetricIpAddress,
+                    ospfIfMetricAddressLessIf,
+                    ospfIfMetricTOS,
+                    ospfIfMetricValue,
+                    ospfIfMetricStatus
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 8 }
+
+
+    ospfVirtIfGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfVirtIfAreaId,
+                    ospfVirtIfNeighbor,
+                    ospfVirtIfTransitDelay,
+                    ospfVirtIfRetransInterval,
+                    ospfVirtIfHelloInterval,
+                    ospfVirtIfRtrDeadInterval,
+                    ospfVirtIfState,
+                    ospfVirtIfEvents,
+                    ospfVirtIfAuthType,
+                    ospfVirtIfAuthKey,
+                    ospfVirtIfStatus
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 9 }
+
+
+    ospfNbrGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfNbrIpAddr,
+                    ospfNbrAddressLessIndex,
+                    ospfNbrRtrId,
+                    ospfNbrOptions,
+                    ospfNbrPriority,
+                    ospfNbrState,
+                    ospfNbrEvents,
+                    ospfNbrLsRetransQLen,
+                    ospfNbmaNbrStatus,
+                    ospfNbmaNbrPermanence,
+                    ospfNbrHelloSuppressed
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 10 }
+
+
+    ospfVirtNbrGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfVirtNbrArea,
+                    ospfVirtNbrRtrId,
+                    ospfVirtNbrIpAddr,
+                    ospfVirtNbrOptions,
+                    ospfVirtNbrState,
+                    ospfVirtNbrEvents,
+                    ospfVirtNbrLsRetransQLen,
+                    ospfVirtNbrHelloSuppressed
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 11 }
+
+
+    ospfExtLsdbGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfExtLsdbType,
+                    ospfExtLsdbLsid,
+                    ospfExtLsdbRouterId,
+                    ospfExtLsdbSequence,
+                    ospfExtLsdbAge,
+                    ospfExtLsdbChecksum,
+                    ospfExtLsdbAdvertisement
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required  for  OSPF  systems
+           that display their link state database."
+       ::= { ospfGroups 12 }
+
+
+    ospfAreaAggregateGroup    OBJECT-GROUP
+        OBJECTS {
+                    ospfAreaAggregateAreaID,
+                    ospfAreaAggregateLsdbType,
+                    ospfAreaAggregateNet,
+                    ospfAreaAggregateMask,
+                    ospfAreaAggregateStatus,
+                    ospfAreaAggregateEffect
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required for OSPF systems."
+       ::= { ospfGroups 13 }
+
+END
diff --git a/ospfd/OSPF-TRAP-MIB.txt b/ospfd/OSPF-TRAP-MIB.txt
new file mode 100644 (file)
index 0000000..8a3ab99
--- /dev/null
@@ -0,0 +1,443 @@
+OSPF-TRAP-MIB DEFINITIONS ::= BEGIN
+
+    IMPORTS
+            MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, IpAddress
+                FROM SNMPv2-SMI
+            MODULE-COMPLIANCE, OBJECT-GROUP
+                FROM SNMPv2-CONF
+            ospfRouterId, ospfIfIpAddress, ospfAddressLessIf, ospfIfState,
+            ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfState,
+            ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId,
+            ospfNbrState, ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrState,
+            ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId, ospfLsdbAreaId,
+            ospfExtLsdbLimit, ospf
+                FROM OSPF-MIB;
+
+    ospfTrap MODULE-IDENTITY
+           LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995
+           ORGANIZATION "IETF OSPF Working Group"
+           CONTACT-INFO
+           "                      Fred Baker
+           Postal:                Cisco Systems
+                                  519 Lado Drive
+                                  Santa Barbara, California 93111
+           Tel:                   +1 805 681 0115
+           E-Mail:                fred@cisco.com
+
+                                  Rob Coltun
+           Postal:                RainbowBridge Communications
+           Tel:                   (301) 340-9416
+           E-Mail:                rcoltun@rainbow-bridge.com"
+       DESCRIPTION
+          "The MIB module to describe traps for  the  OSPF
+          Version 2 Protocol."
+      ::= { ospf 16 }
+
+-- Trap Support Objects
+
+--         The following are support objects for the OSPF traps.
+
+ospfTrapControl OBJECT IDENTIFIER ::= { ospfTrap 1 }
+ospfTraps OBJECT IDENTIFIER ::= { ospfTrap 2 }
+
+    ospfSetTrap OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE(4))
+        MAX-ACCESS   read-write
+        STATUS   current
+        DESCRIPTION
+           "A four-octet string serving as a bit  map  for
+           the trap events defined by the OSPF traps. This
+           object is used to enable and  disable  specific
+           OSPF   traps   where  a  1  in  the  bit  field
+           represents enabled.  The right-most bit  (least
+           significant) represents trap 0."
+       ::= { ospfTrapControl 1 }
+
+
+    ospfConfigErrorType OBJECT-TYPE
+        SYNTAX   INTEGER   {
+                    badVersion (1),
+                    areaMismatch (2),
+                    unknownNbmaNbr (3), -- Router is Dr eligible
+                    unknownVirtualNbr (4),
+                    authTypeMismatch(5),
+                    authFailure (6),
+                    netMaskMismatch (7),
+                    helloIntervalMismatch (8),
+                    deadIntervalMismatch (9),
+                    optionMismatch (10) }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "Potential types  of  configuration  conflicts.
+           Used  by the ospfConfigError and ospfConfigVir-
+           tError traps."
+   ::= { ospfTrapControl 2 }
+
+
+    ospfPacketType OBJECT-TYPE
+        SYNTAX   INTEGER   {
+                    hello (1),
+                    dbDescript (2),
+                    lsReq (3),
+                    lsUpdate (4),
+                    lsAck (5) }
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "OSPF packet types."
+   ::= { ospfTrapControl 3 }
+
+
+    ospfPacketSrc OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP address of an inbound packet that  can-
+           not be identified by a neighbor instance."
+       ::= { ospfTrapControl 4 }
+
+
+-- Traps
+
+
+    ospfIfStateChange NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfIfIpAddress,
+                    ospfAddressLessIf,
+                    ospfIfState   -- The new state
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfIfStateChange trap signifies that there
+           has been a change in the state of a non-virtual
+           OSPF interface. This trap should  be  generated
+           when  the interface state regresses (e.g., goes
+           from Dr to Down) or progresses  to  a  terminal
+           state  (i.e.,  Point-to-Point, DR Other, Dr, or
+           Backup)."
+   ::= { ospfTraps 16 }
+
+
+    ospfVirtIfStateChange NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfVirtIfAreaId,
+                    ospfVirtIfNeighbor,
+                    ospfVirtIfState  -- The new state
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfIfStateChange trap signifies that there
+           has  been a change in the state of an OSPF vir-
+           tual interface.
+           This trap should be generated when  the  inter-
+           face  state  regresses  (e.g., goes from Point-
+           to-Point to Down) or progresses to  a  terminal
+           state (i.e., Point-to-Point)."
+   ::= { ospfTraps 1 }
+
+
+    ospfNbrStateChange NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfNbrIpAddr,
+                    ospfNbrAddressLessIndex,
+                    ospfNbrRtrId,
+                    ospfNbrState  -- The new state
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An  ospfNbrStateChange  trap  signifies   that
+           there  has been a change in the state of a non-
+           virtual OSPF neighbor.   This  trap  should  be
+           generated  when  the  neighbor  state regresses
+           (e.g., goes from Attempt or Full  to  1-Way  or
+           Down)  or progresses to a terminal state (e.g.,
+           2-Way or Full).  When an  neighbor  transitions
+           from  or  to Full on non-broadcast multi-access
+           and broadcast networks, the trap should be gen-
+           erated  by the designated router.  A designated
+           router transitioning to Down will be  noted  by
+           ospfIfStateChange."
+   ::= { ospfTraps 2 }
+
+
+    ospfVirtNbrStateChange NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfVirtNbrArea,
+                    ospfVirtNbrRtrId,
+                    ospfVirtNbrState  -- The new state
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfIfStateChange trap signifies that there
+           has  been a change in the state of an OSPF vir-
+           tual neighbor.  This trap should  be  generated
+           when  the  neighbor state regresses (e.g., goes
+           from Attempt or  Full  to  1-Way  or  Down)  or
+           progresses to a terminal state (e.g., Full)."
+   ::= { ospfTraps 3 }
+    ospfIfConfigError NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfIfIpAddress,
+                    ospfAddressLessIf,
+                    ospfPacketSrc,  -- The source IP address
+                    ospfConfigErrorType, -- Type of error
+                    ospfPacketType
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfIfConfigError  trap  signifies  that  a
+           packet  has  been received on a non-virtual in-
+           terface  from  a  router  whose   configuration
+           parameters  conflict  with this router's confi-
+           guration parameters.  Note that the  event  op-
+           tionMismatch  should  cause  a  trap only if it
+           prevents an adjacency from forming."
+                  ::= { ospfTraps 4 }
+
+
+    ospfVirtIfConfigError NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfVirtIfAreaId,
+                    ospfVirtIfNeighbor,
+                    ospfConfigErrorType, -- Type of error
+                    ospfPacketType
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfConfigError trap signifies that a pack-
+           et  has  been  received  on a virtual interface
+           from a router  whose  configuration  parameters
+           conflict   with   this  router's  configuration
+           parameters.  Note that the event optionMismatch
+           should  cause a trap only if it prevents an ad-
+           jacency from forming."
+   ::= { ospfTraps 5 }
+
+
+    ospfIfAuthFailure NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfIfIpAddress,
+                    ospfAddressLessIf,
+                    ospfPacketSrc,  -- The source IP address
+                    ospfConfigErrorType, -- authTypeMismatch or
+                                         -- authFailure
+                    ospfPacketType
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfIfAuthFailure  trap  signifies  that  a
+           packet  has  been received on a non-virtual in-
+           terface from a router whose authentication  key
+           or  authentication  type  conflicts  with  this
+           router's authentication key  or  authentication
+           type."
+   ::= { ospfTraps 6 }
+
+
+    ospfVirtIfAuthFailure NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfVirtIfAreaId,
+                    ospfVirtIfNeighbor,
+                    ospfConfigErrorType, -- authTypeMismatch or
+                                         -- authFailure
+                    ospfPacketType
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfVirtIfAuthFailure trap signifies that a
+           packet has been received on a virtual interface
+           from a router whose authentication key  or  au-
+           thentication  type conflicts with this router's
+           authentication key or authentication type."
+   ::= { ospfTraps 7 }
+
+
+    ospfIfRxBadPacket NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfIfIpAddress,
+                    ospfAddressLessIf,
+                    ospfPacketSrc,  -- The source IP address
+                    ospfPacketType
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfIfRxBadPacket trap  signifies  that  an
+           OSPF  packet has been received on a non-virtual
+           interface that cannot be parsed."
+   ::= { ospfTraps 8 }
+
+    ospfVirtIfRxBadPacket NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfVirtIfAreaId,
+                    ospfVirtIfNeighbor,
+                    ospfPacketType
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfRxBadPacket trap signifies that an OSPF
+           packet has been received on a virtual interface
+           that cannot be parsed."
+   ::= { ospfTraps 9 }
+
+
+    ospfTxRetransmit NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfIfIpAddress,
+                    ospfAddressLessIf,
+                    ospfNbrRtrId, -- Destination
+                    ospfPacketType,
+                    ospfLsdbType,
+                    ospfLsdbLsid,
+                    ospfLsdbRouterId
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfTxRetransmit  trap  signifies  than  an
+           OSPF  packet  has  been retransmitted on a non-
+           virtual interface.  All packets that may be re-
+           transmitted  are associated with an LSDB entry.
+           The LS type, LS ID, and Router ID are  used  to
+           identify the LSDB entry."
+   ::= { ospfTraps 10 }
+
+
+    ospfVirtIfTxRetransmit NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfVirtIfAreaId,
+                    ospfVirtIfNeighbor,
+                    ospfPacketType,
+                    ospfLsdbType,
+                    ospfLsdbLsid,
+                    ospfLsdbRouterId
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfTxRetransmit  trap  signifies  than  an
+           OSPF packet has been retransmitted on a virtual
+           interface.  All packets that may be retransmit-
+           ted  are  associated with an LSDB entry. The LS
+           type, LS ID, and Router ID are used to identify
+           the LSDB entry."
+   ::= { ospfTraps 11 }
+
+
+    ospfOriginateLsa NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfLsdbAreaId,  -- 0.0.0.0 for AS Externals
+                    ospfLsdbType,
+                    ospfLsdbLsid,
+                    ospfLsdbRouterId
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfOriginateLsa trap signifies that a  new
+           LSA  has  been originated by this router.  This
+           trap should not be invoked for simple refreshes
+           of  LSAs  (which happesn every 30 minutes), but
+           instead will only be invoked  when  an  LSA  is
+           (re)originated due to a topology change.  Addi-
+           tionally, this trap does not include LSAs  that
+           are  being  flushed  because  they have reached
+           MaxAge."
+   ::= { ospfTraps 12 }
+
+
+    ospfMaxAgeLsa NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfLsdbAreaId,  -- 0.0.0.0 for AS Externals
+                    ospfLsdbType,
+                    ospfLsdbLsid,
+                    ospfLsdbRouterId
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfMaxAgeLsa trap signifies  that  one  of
+           the LSA in the router's link-state database has
+           aged to MaxAge."
+   ::= { ospfTraps 13 }
+
+
+    ospfLsdbOverflow NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfExtLsdbLimit
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfLsdbOverflow trap  signifies  that  the
+           number of LSAs in the router's link-state data-
+           base has exceeded ospfExtLsdbLimit."
+   ::= { ospfTraps 14 }
+
+
+    ospfLsdbApproachingOverflow NOTIFICATION-TYPE
+        OBJECTS {
+                    ospfRouterId, -- The originator of the trap
+                    ospfExtLsdbLimit
+                  }
+        STATUS             current
+        DESCRIPTION
+           "An ospfLsdbApproachingOverflow trap  signifies
+           that  the  number of LSAs in the router's link-
+           state database has exceeded ninety  percent  of
+           ospfExtLsdbLimit."
+   ::= { ospfTraps 15 }
+
+
+-- conformance information
+
+ospfTrapConformance OBJECT IDENTIFIER ::= { ospfTrap 3 }
+
+ospfTrapGroups      OBJECT IDENTIFIER ::= { ospfTrapConformance 1 }
+ospfTrapCompliances OBJECT IDENTIFIER ::= { ospfTrapConformance 2 }
+
+-- compliance statements
+
+    ospfTrapCompliance MODULE-COMPLIANCE
+        STATUS  current
+        DESCRIPTION
+           "The compliance statement "
+       MODULE  -- this module
+       MANDATORY-GROUPS { ospfTrapControlGroup }
+
+
+        GROUP       ospfTrapControlGroup
+        DESCRIPTION
+           "This group is optional but recommended for all
+           OSPF systems"
+       ::= { ospfTrapCompliances 1 }
+
+
+-- units of conformance
+
+    ospfTrapControlGroup    OBJECT-GROUP
+        OBJECTS {
+                           ospfSetTrap,
+                           ospfConfigErrorType,
+                           ospfPacketType,
+                           ospfPacketSrc
+        }
+        STATUS  current
+        DESCRIPTION
+           "These objects are required  to  control  traps
+           from OSPF systems."
+       ::= { ospfTrapGroups 1 }
+
+
+END
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
new file mode 100644 (file)
index 0000000..ec3b153
--- /dev/null
@@ -0,0 +1,1741 @@
+/*
+ * OSPF ABR functions.
+ * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "vty.h"
+#include "filter.h"
+#include "plist.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ia.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+\f
+struct ospf_area_range *
+ospf_area_range_new (struct prefix_ipv4 *p)
+{
+  struct ospf_area_range *range;
+
+  range = XCALLOC (MTYPE_OSPF_AREA_RANGE, sizeof (struct ospf_area_range));
+  range->addr = p->prefix;
+  range->masklen = p->prefixlen;
+  range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC;
+
+  return range;
+}
+
+void
+ospf_area_range_free (struct ospf_area_range *range)
+{
+  XFREE (MTYPE_OSPF_AREA_RANGE, range);
+}
+
+void
+ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = range->masklen;
+  p.prefix = range->addr;
+
+  rn = route_node_get (area->ranges, (struct prefix *)&p);
+  if (rn->info)
+    route_unlock_node (rn);
+  else
+    rn->info = range;
+}
+
+void
+ospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = range->masklen;
+  p.prefix = range->addr;
+
+  rn = route_node_lookup (area->ranges, (struct prefix *)&p);
+  if (rn)
+    {
+      ospf_area_range_free (rn->info);
+      rn->info = NULL;
+      route_unlock_node (rn);
+      route_unlock_node (rn);
+    }
+}
+
+struct ospf_area_range *
+ospf_area_range_lookup (struct ospf_area *area, struct prefix_ipv4 *p)
+{
+  struct route_node *rn;
+
+  rn = route_node_lookup (area->ranges, (struct prefix *)p);
+  if (rn)
+    {
+      route_unlock_node (rn);
+      return rn->info;
+    }
+  return NULL;
+}
+
+struct ospf_area_range *
+ospf_area_range_lookup_next (struct ospf_area *area, struct in_addr *range_net,
+                            int first)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  struct ospf_area_range *find;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.prefix = *range_net;
+
+  if (first)
+    rn = route_top (area->ranges);
+  else
+    {
+      rn = route_node_get (area->ranges, (struct prefix *) &p);
+      rn = route_next (rn);
+    }
+
+  for (; rn; rn = route_next (rn))
+    if (rn->info)
+      break;
+
+  if (rn && rn->info)
+    {
+      find = rn->info;
+      *range_net = rn->p.u.prefix4;
+      route_unlock_node (rn);
+      return find;
+    }
+  return NULL;
+}
+
+struct ospf_area_range *
+ospf_area_range_match (struct ospf_area *area, struct prefix_ipv4 *p)
+{
+  struct route_node *node;
+
+  node = route_node_match (area->ranges, (struct prefix *) p);
+  if (node)
+    {
+      route_unlock_node (node);
+      return node->info;
+    }
+  return NULL;
+}
+
+struct ospf_area_range *
+ospf_area_range_match_any (struct ospf *ospf, struct prefix_ipv4 *p)
+{
+  struct ospf_area_range *range;
+  listnode node;
+
+  for (node = listhead (ospf->areas); node; nextnode (node))
+    if ((range = ospf_area_range_match (node->data, p)))
+      return range;
+
+  return NULL;
+}
+
+int
+ospf_area_range_active (struct ospf_area_range *range)
+{
+  return range->specifics;
+}
+
+int
+ospf_area_actively_attached (struct ospf_area *area)
+{
+  return area->act_ints;
+}
+
+int
+ospf_area_range_set (struct ospf *ospf, struct in_addr area_id,
+                    struct prefix_ipv4 *p, int advertise)
+{
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+  int ret = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  area = ospf_area_get (area_id, ret);
+  if (area == NULL)
+    return 0;
+
+  range = ospf_area_range_lookup (area, p);
+  if (range != NULL)
+    {
+      if ((CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)
+          && !CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE))
+         || (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)
+             && CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)))
+       ospf_schedule_abr_task ();
+    }
+  else
+    {
+      range = ospf_area_range_new (p);
+      ospf_area_range_add (area, range);
+      ospf_schedule_abr_task ();
+    }
+
+  if (CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE))
+    SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE);
+  else
+    UNSET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE);
+
+  return 1;
+}
+
+int
+ospf_area_range_cost_set (struct ospf *ospf, struct in_addr area_id,
+                         struct prefix_ipv4 *p, u_int32_t cost)
+{
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+  int ret = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  area = ospf_area_get (area_id, ret);
+  if (area == NULL)
+    return 0;
+
+  range = ospf_area_range_new (p);
+  if (range == NULL)
+    return 0;
+
+  if (range->cost_config != cost)
+    {
+      range->cost_config = cost;
+      if (ospf_area_range_active (range))
+       ospf_schedule_abr_task ();
+    }
+
+  return 1;
+}
+
+int
+ospf_area_range_unset (struct ospf *ospf, struct in_addr area_id,
+                      struct prefix_ipv4 *p)
+{
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 0;
+
+  range = ospf_area_range_lookup (area, p);
+  if (range == NULL)
+    return 0;
+
+  if (ospf_area_range_active (range))
+    ospf_schedule_abr_task ();
+
+  ospf_area_range_delete (area, range);
+
+  return 1;
+}
+
+int
+ospf_area_range_substitute_set (struct ospf *ospf, struct in_addr area_id,
+                               struct prefix_ipv4 *p, struct prefix_ipv4 *s)
+{
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+  int ret = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  area = ospf_area_get (area_id, ret);
+  range = ospf_area_range_lookup (area, p);
+
+  if (range != NULL)
+    {
+      if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) ||
+         !CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE))
+       ospf_schedule_abr_task ();
+    }
+  else
+    {
+      range = ospf_area_range_new (p);
+      ospf_area_range_add (area, range);
+      ospf_schedule_abr_task ();
+    }
+
+  SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE);
+  SET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE);
+  range->subst_addr = s->prefix;
+  range->subst_masklen = s->prefixlen;
+
+  return 1;
+}
+
+int
+ospf_area_range_substitute_unset (struct ospf *ospf, struct in_addr area_id,
+                                 struct prefix_ipv4 *p)
+{
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 0;
+
+  range = ospf_area_range_lookup (area, p);
+  if (range == NULL)
+    return 0;
+
+  if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE))
+    if (ospf_area_range_active (range))
+      ospf_schedule_abr_task ();
+
+  UNSET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE);
+  range->subst_addr.s_addr = 0;
+  range->subst_masklen = 0;
+
+  return 1;
+}
+
+int
+ospf_act_bb_connection ()
+{
+  if (ospf_top->backbone == NULL)
+    return 0;
+
+  return ospf_top->backbone->full_nbrs;
+}
+
+/* Check area border router status. */
+void
+ospf_check_abr_status ()
+{
+  struct ospf_area *area;
+  listnode node;
+  int bb_configured = 0;
+  int bb_act_attached = 0;
+  int areas_configured = 0;
+  int areas_act_attached = 0;
+
+  u_char new_flags = ospf_top->flags;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_check_abr_status(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (listcount (area->oiflist)) 
+       {
+         areas_configured++;
+         
+         if (OSPF_IS_AREA_BACKBONE (area))
+           bb_configured = 1;
+       }
+
+      if (ospf_area_actively_attached (area))
+       {
+         areas_act_attached++;
+         
+         if (OSPF_IS_AREA_BACKBONE (area))
+            bb_act_attached = 1;
+       }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    {
+      zlog_info ("ospf_check_abr_status(): looked through areas");
+      zlog_info ("ospf_check_abr_status(): bb_configured: %d", bb_configured);
+      zlog_info ("ospf_check_abr_status(): bb_act_attached: %d",
+                bb_act_attached);
+      zlog_info ("ospf_check_abr_status(): areas_configured: %d",
+                areas_configured);
+      zlog_info ("ospf_check_abr_status(): areas_act_attached: %d",
+                areas_act_attached);
+    }
+
+  switch (ospf_top->abr_type)
+    {
+    case OSPF_ABR_SHORTCUT:
+    case OSPF_ABR_STAND:
+      if (areas_act_attached > 1)
+       SET_FLAG (new_flags, OSPF_FLAG_ABR);
+      else
+       UNSET_FLAG (new_flags, OSPF_FLAG_ABR);
+      break;
+
+    case OSPF_ABR_IBM:
+      if ((areas_act_attached > 1) && bb_configured)
+       SET_FLAG (new_flags, OSPF_FLAG_ABR);
+      else
+       UNSET_FLAG (new_flags, OSPF_FLAG_ABR);
+      break;
+
+    case OSPF_ABR_CISCO:
+      if ((areas_configured > 1) && bb_act_attached)
+       SET_FLAG (new_flags, OSPF_FLAG_ABR);
+      else
+       UNSET_FLAG (new_flags, OSPF_FLAG_ABR);
+      break;
+    default:
+      break;
+    }
+
+  if (new_flags != ospf_top->flags)
+    {
+      ospf_spf_calculate_schedule ();
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_check_abr_status(): new router flags: %x",new_flags);
+      ospf_top->flags = new_flags;
+      OSPF_TIMER_ON (ospf_top->t_router_lsa_update,
+                    ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
+    }
+}
+
+void
+ospf_abr_update_aggregate (struct ospf_area_range *range,
+                          struct ospf_route *or)
+{
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_update_aggregate(): Start");
+
+  if (range->cost_config != -1)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_update_aggregate(): use configured cost %d",
+                  range->cost_config);
+
+      range->cost = range->cost_config;
+    }
+  else
+    {
+      if (range->specifics == 0)
+       range->cost = or->cost; /* 1st time get 1st cost */
+
+      if (or->cost < range->cost)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_update_aggregate(): lowest cost, update");
+
+         range->cost = or->cost;
+       }
+    }
+
+  range->specifics++;
+}
+
+static void
+set_metric (struct ospf_lsa *lsa, u_int32_t metric)
+{
+  struct summary_lsa *header;
+  u_char *mp;
+  metric = htonl (metric);
+  mp = (char *) &metric;
+  mp++;
+  header = (struct summary_lsa *) lsa->data;
+  memcpy(header->metric, mp, 3);
+}
+
+#ifdef HAVE_NSSA
+int
+ospf_abr_check_nssa_range (struct prefix_ipv4 *p, u_int32_t cost,
+                                  struct ospf_area *area)
+{
+  /* The Type-7 is tested against the aggregated prefix and forwarded
+       for lsa installation and flooding */
+  return 0;
+}
+
+/* ospf_abr_translate_nssa */
+int
+ospf_abr_translate_nssa (struct ospf_lsa *lsa, void *p_arg, int int_arg)
+{
+  /* Incoming Type-7 or later aggregated Type-7 
+
+     LSA is skipped if P-bit is off.
+     LSA is aggregated if within range.
+
+     The Type-7 is translated, Installed/Approved as a Type-5 into
+     global LSDB, then Flooded through AS
+
+     Later, any Unapproved Translated Type-5's are flushed/discarded */
+
+  struct ospf_lsa *dup;
+
+  if (! CHECK_FLAG (lsa->data->options, OSPF_OPTION_NP))
+    {
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_abr_nssa(): P-bit off, NO Translation");
+      return 0; 
+    }
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa(): TRANSLATING 7 to 5");
+
+  /* No more P-bit. */
+  /* UNSET_FLAG (lsa->data->options, OSPF_OPTION_NP); */
+
+  /* Area where Aggregate testing will be inserted, just like summary
+     advertisements */
+  /* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */
+
+  /* Follow thru here means no aggregation */
+  dup = ospf_lsa_dup (lsa);    /* keep LSDB intact, lock = 1 */
+
+  SET_FLAG (dup->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7  */
+  SET_FLAG (dup->flags, OSPF_LSA_APPROVED); /* So, do not remove it */
+
+  dup->data->type = OSPF_AS_EXTERNAL_LSA;  /* make Type-5 */
+
+  ospf_lsa_checksum (dup->data);
+
+  ospf_lsa_install (NULL, dup); /* Install this Type-5 into LSDB, Lock = 2. */
+
+  ospf_flood_through_as (NULL, dup); /* flood non-NSSA/STUB areas */
+  
+  /* This translated Type-5 will go to all non-NSSA areas connected to
+     this ABR; The Type-5 could come from any of the NSSA's connected
+     to this ABR.  */
+
+  return 0;
+}
+
+void
+ospf_abr_translate_nssa_range (struct prefix_ipv4 *p, u_int32_t cost)
+{
+  /* The Type-7 is created from the aggregated prefix and forwarded
+     for lsa installation and flooding... to be added... */
+}
+#endif /* HAVE_NSSA */
+
+void
+ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost,
+                                  struct ospf_area *area)
+{
+  struct ospf_lsa *lsa, *old = NULL;
+  struct summary_lsa *sl = NULL;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_network_to_area(): Start");
+
+  old = OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX (area, p);
+
+  if (old)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network_to_area(): old summary found");
+      sl = (struct summary_lsa *) old->data;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network_to_area(): "
+                  "old metric: %d, new metric: %d",
+                  GET_METRIC (sl->metric), cost);
+    }
+
+  if (old && (GET_METRIC (sl->metric) == cost))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network_to_area(): "
+                  "old summary approved"); 
+      SET_FLAG (old->flags, OSPF_LSA_APPROVED);
+    }
+  else
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network_to_area(): "
+                  "creating new summary");
+      if (old)
+       {
+
+         set_metric (old, cost);
+         lsa = ospf_summary_lsa_refresh (old);
+         /* This will flood through area. */
+       }
+      else
+       {
+         lsa = ospf_summary_lsa_originate (p, cost, area);
+         /* This will flood through area. */
+       }
+      
+
+      SET_FLAG (lsa->flags, OSPF_LSA_APPROVED);
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network_to_area(): "
+                  "flooding new version of summary");
+
+#ifndef HAVE_NSSA      
+      ospf_flood_through_area (area, NULL, lsa);
+#endif /* ! HAVE_NSSA */
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_network_to_area(): Stop");
+}
+
+int
+ospf_abr_nexthops_belong_to_area (struct ospf_route *or,
+                                 struct ospf_area *area)
+{
+  listnode node;
+
+  for (node = listhead (or->path); node; nextnode (node))
+    {
+      struct ospf_path *path = node->data;
+      struct ospf_interface *oi = path->oi;
+
+      if (oi != NULL)
+       if (oi->area == area)
+         return 1;
+    }
+
+  return 0;
+}
+
+int
+ospf_abr_should_accept (struct prefix *p, struct ospf_area *area)
+{
+  if (IMPORT_NAME (area))
+    {
+      if (IMPORT_LIST (area) == NULL)
+       IMPORT_LIST (area) = access_list_lookup (AFI_IP, IMPORT_NAME (area));
+
+      if (IMPORT_LIST (area))
+        if (access_list_apply (IMPORT_LIST (area), p) == FILTER_DENY)
+           return 0;
+    }
+
+ return 1;
+}
+
+int
+ospf_abr_plist_in_check (struct ospf_area *area, struct ospf_route *or,
+                        struct prefix *p)
+{
+  if (PREFIX_NAME_IN (area))
+    {
+      if (PREFIX_LIST_IN (area) == NULL)
+       PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP,
+                                                   PREFIX_NAME_IN (area));
+      if (PREFIX_LIST_IN (area))
+       if (prefix_list_apply (PREFIX_LIST_IN (area), p) != PREFIX_PERMIT)
+         return 0;
+    }
+  return 1;
+}
+
+int
+ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or,
+                         struct prefix *p)
+{
+  if (PREFIX_NAME_OUT (area))
+    {
+      if (PREFIX_LIST_OUT (area) == NULL)
+       PREFIX_LIST_OUT (area) = prefix_list_lookup (AFI_IP,
+                                                    PREFIX_NAME_OUT (area));
+      if (PREFIX_LIST_OUT (area))
+       if (prefix_list_apply (PREFIX_LIST_OUT (area), p) != PREFIX_PERMIT)
+         return 0;
+    }
+  return 1;
+}
+
+void
+ospf_abr_announce_network (struct route_node *n, struct ospf_route *or)
+{
+  listnode node;
+  struct ospf_area_range *range;
+  struct prefix_ipv4 *p;
+  struct ospf_area *area, *or_area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_network(): Start");
+  p = (struct prefix_ipv4 *) &n->p;
+
+  or_area = ospf_area_lookup_by_area_id (or->u.std.area_id); 
+  assert (or_area);
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network(): looking at area %s",
+                  inet_ntoa (area->area_id));
+
+      if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
+       continue;
+
+      if (ospf_abr_nexthops_belong_to_area (or, area))
+       continue;
+
+      if (!ospf_abr_should_accept (&n->p, area))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_network(): "
+                      "prefix %s/%d was denied by import-list",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         continue; 
+       }
+
+      if (!ospf_abr_plist_in_check (area, or, &n->p))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_network(): "
+                      "prefix %s/%d was denied by prefix-list",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         continue; 
+       }
+
+      if (area->external_routing != OSPF_AREA_DEFAULT && area->no_summary)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_network(): "
+                      "area %s is stub and no_summary",
+                      inet_ntoa (area->area_id));
+          continue;
+       }
+
+      if (or->path_type == OSPF_PATH_INTER_AREA)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_network(): this is "
+                      "inter-area route to %s/%d",
+                      inet_ntoa (p->prefix), p->prefixlen);
+
+          if (!OSPF_IS_AREA_BACKBONE (area))
+           ospf_abr_announce_network_to_area (p, or->cost, area);
+       }
+
+      if (or->path_type == OSPF_PATH_INTRA_AREA)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_network(): "
+                      "this is intra-area route to %s/%d",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         if ((range = ospf_area_range_match (or_area, p)) &&
+              !ospf_area_is_transit (area))
+           ospf_abr_update_aggregate (range, or);
+         else
+           ospf_abr_announce_network_to_area (p, or->cost, area);
+       }
+    }
+}
+
+int
+ospf_abr_should_announce (struct prefix *p, struct ospf_route *or)
+{
+  struct ospf_area *area = ospf_area_lookup_by_area_id (or->u.std.area_id);
+
+  assert (area);
+  
+  if (EXPORT_NAME (area))
+    {
+      if (EXPORT_LIST (area) == NULL)
+       EXPORT_LIST (area) = access_list_lookup (AFI_IP, EXPORT_NAME (area));
+
+      if (EXPORT_LIST (area))
+        if (access_list_apply (EXPORT_LIST (area), p) == FILTER_DENY)
+           return 0;
+    }
+
+  return 1;
+}
+
+#ifdef HAVE_NSSA
+void
+ospf_abr_process_nssa_translates ()
+{
+  /* Scan through all NSSA_LSDB records for all areas;
+
+     If P-bit is on, translate all Type-7's to 5's and aggregate or
+     flood install as approved in Type-5 LSDB with XLATE Flag on
+     later, do same for all aggregates...  At end, DISCARD all
+     remaining UNAPPROVED Type-5's (Aggregate is for future ) */
+  listnode node;
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_process_nssa_translates(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (! area->NSSATranslator)
+       continue; /* skip if not translator */
+      
+      if (area->external_routing != OSPF_AREA_NSSA)
+       continue;  /* skip if not Nssa Area */
+
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_abr_process_nssa_translates(): "
+                  "looking at area %s", inet_ntoa (area->area_id));
+      
+      foreach_lsa (NSSA_LSDB (area), area, 0, ospf_abr_translate_nssa);
+    }
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_process_nssa_translates(): Stop");
+
+}
+#endif /* HAVE_NSSA */
+
+void
+ospf_abr_process_network_rt (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_process_network_rt(): Start");
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    {
+      if ((or = rn->info) == NULL)
+       continue;
+
+      if (!(area = ospf_area_lookup_by_area_id (or->u.std.area_id)))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_process_network_rt(): area %s no longer exists",
+                      inet_ntoa (or->u.std.area_id));
+         continue;
+       }
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_process_network_rt(): this is a route to %s/%d",
+                  inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+      if (or->path_type >= OSPF_PATH_TYPE1_EXTERNAL)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_process_network_rt(): "
+                      "this is an External router, skipping");
+         continue;
+       }
+
+      if (or->cost >= OSPF_LS_INFINITY)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_process_network_rt():"
+                      " this route's cost is infinity, skipping");
+         continue;
+       }
+
+      if (or->type == OSPF_DESTINATION_DISCARD)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_process_network_rt():"
+                      " this is a discard entry, skipping");
+         continue;
+       }
+
+      if (or->path_type == OSPF_PATH_INTRA_AREA &&
+         !ospf_abr_should_announce (&rn->p, or))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info("ospf_abr_process_network_rt(): denied by export-list");
+         continue;
+       }
+
+      if (or->path_type == OSPF_PATH_INTRA_AREA &&
+         !ospf_abr_plist_out_check (area, or, &rn->p))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info("ospf_abr_process_network_rt(): denied by prefix-list");
+         continue;
+       }
+
+      if ((or->path_type == OSPF_PATH_INTER_AREA) &&
+          !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_process_network_rt():"
+                      " this is route is not backbone one, skipping");
+         continue;
+       }
+
+
+      if ((ospf_top->abr_type == OSPF_ABR_CISCO) ||
+          (ospf_top->abr_type == OSPF_ABR_IBM))
+
+          if (!ospf_act_bb_connection () &&
+              or->path_type != OSPF_PATH_INTRA_AREA)
+            {
+              if (IS_DEBUG_OSPF_EVENT)
+                zlog_info ("ospf_abr_process_network_rt(): ALT ABR: "
+                           "No BB connection, skip not intra-area routes");
+              continue;
+            }
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_process_network_rt(): announcing");
+      ospf_abr_announce_network (rn, or);
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_process_network_rt(): Stop");
+}
+
+void
+ospf_abr_announce_rtr_to_area (struct prefix_ipv4 *p, u_int32_t cost,
+                              struct ospf_area *area)
+{
+  struct ospf_lsa *lsa, *old = NULL;
+  struct summary_lsa *slsa = NULL;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_rtr_to_area(): Start");
+
+  old = OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX (area, p);
+  /* old = ospf_find_self_summary_asbr_lsa_by_prefix (area, p); */
+
+  if (old)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_rtr_to_area(): old summary found");
+      slsa = (struct summary_lsa *) old->data;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_network_to_area(): "
+                  "old metric: %d, new metric: %d",
+                  GET_METRIC (slsa->metric), cost);
+    }
+
+  if (old && (GET_METRIC (slsa->metric) == cost))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_rtr_to_area(): old summary approved");
+      SET_FLAG (old->flags, OSPF_LSA_APPROVED);
+    }
+  else
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_rtr_to_area(): 2.2");
+       
+      if (old) 
+       { 
+         set_metric (old, cost);
+         lsa = ospf_summary_asbr_lsa_refresh (old);
+       }
+      else
+       lsa = ospf_summary_asbr_lsa_originate (p, cost, area);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_rtr_to_area(): "
+                  "flooding new version of summary");
+      /*
+      zlog_info ("ospf_abr_announce_rtr_to_area(): creating new summary");
+      lsa = ospf_summary_asbr_lsa (p, cost, area, old); */
+
+      SET_FLAG (lsa->flags, OSPF_LSA_APPROVED);
+      /* ospf_flood_through_area (area, NULL, lsa);*/
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_rtr_to_area(): Stop");
+}
+
+
+void
+ospf_abr_announce_rtr (struct prefix_ipv4 *p, struct ospf_route *or)
+{
+  listnode node;
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_rtr(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_rtr(): looking at area %s",
+                  inet_ntoa (area->area_id));
+
+      if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
+       continue;
+
+      if (ospf_abr_nexthops_belong_to_area (or, area))
+       continue;
+
+      if (area->external_routing != OSPF_AREA_DEFAULT)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_network(): "
+                      "area %s doesn't support external routing",
+                      inet_ntoa(area->area_id));
+          continue;
+       }
+
+      if (or->path_type == OSPF_PATH_INTER_AREA)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_rtr(): "
+                      "this is inter-area route to %s", inet_ntoa (p->prefix));
+          if (!OSPF_IS_AREA_BACKBONE (area))
+           ospf_abr_announce_rtr_to_area (p, or->cost, area);
+       }
+
+      if (or->path_type == OSPF_PATH_INTRA_AREA)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_abr_announce_rtr(): "
+                      "this is intra-area route to %s", inet_ntoa (p->prefix));
+          ospf_abr_announce_rtr_to_area (p, or->cost, area);
+       }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_rtr(): Stop");
+}
+
+void
+ospf_abr_process_router_rt (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct list *l;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_process_router_rt(): Start");
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    {
+      listnode node;
+      char flag = 0;
+      struct ospf_route *best = NULL;
+
+      if (rn->info == NULL)
+       continue;
+
+      l = rn->info;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_process_router_rt(): this is a route to %s",
+                  inet_ntoa (rn->p.u.prefix4));
+
+      for (node = listhead (l); node; nextnode (node))
+       {
+         or = getdata (node);
+         if (or == NULL)
+           continue;
+
+         if (!ospf_area_lookup_by_area_id (or->u.std.area_id))
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("ospf_abr_process_router_rt(): area %s no longer exists",
+                        inet_ntoa (or->u.std.area_id));
+             continue;
+           }
+
+
+         if (!CHECK_FLAG (or->u.std.flags, ROUTER_LSA_EXTERNAL))
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("ospf_abr_process_router_rt(): "
+                          "This is not an ASBR, skipping");
+             continue;
+           }
+
+         if (!flag)
+           {
+             best = ospf_find_asbr_route (rt, (struct prefix_ipv4 *) &rn->p);
+             flag = 1;
+           }
+         
+        if (best == NULL)
+         continue;
+       
+        if (or != best)
+         {
+           if (IS_DEBUG_OSPF_EVENT)
+             zlog_info ("ospf_abr_process_router_rt(): "
+                        "This route is not the best among possible, skipping");
+           continue;
+         }
+       
+        if (or->path_type == OSPF_PATH_INTER_AREA &&
+            !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id))
+         {
+           if (IS_DEBUG_OSPF_EVENT)
+             zlog_info ("ospf_abr_process_router_rt(): "
+                        "This route is not a backbone one, skipping");
+           continue;
+         }
+
+        if (or->cost >= OSPF_LS_INFINITY)
+         {
+           if (IS_DEBUG_OSPF_EVENT)
+             zlog_info ("ospf_abr_process_router_rt(): "
+                        "This route has LS_INFINITY metric, skipping");
+           continue;
+         }
+
+        if (ospf_top->abr_type == OSPF_ABR_CISCO ||
+            ospf_top->abr_type == OSPF_ABR_IBM)
+         if (!ospf_act_bb_connection () &&
+             or->path_type != OSPF_PATH_INTRA_AREA)
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info("ospf_abr_process_network_rt(): ALT ABR: "
+                         "No BB connection, skip not intra-area routes");
+             continue;
+           }
+
+        ospf_abr_announce_rtr ((struct prefix_ipv4 *) &rn->p, or);
+
+       }
+
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_process_router_rt(): Stop");
+}
+
+#ifdef HAVE_NSSA
+int
+ospf_abr_unapprove_translates_apply (struct ospf_lsa *lsa, void *p_arg,
+                                   int int_arg)
+{
+  /* Could be a mix of Normal Type-5's, self-originated, or Type-7s
+      that are Locally ABR Translated */
+
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+    UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED);
+  
+  return 0;
+}
+
+void
+ospf_abr_unapprove_translates () /* For NSSA Translations */
+{
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_unapprove_translates(): Start");
+
+  /* NSSA Translator is not checked, because it may have gone away,
+    and we would want to flush any residuals anyway */
+
+  foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0,
+              ospf_abr_unapprove_translates_apply);
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_unapprove_translates(): Stop");
+}
+#endif /* HAVE_NSSA */
+
+int
+ospf_abr_unapprove_summaries_apply (struct ospf_lsa *lsa, void *p_arg,
+                                   int int_arg)
+{
+  if (ospf_lsa_is_self_originated (lsa))
+    UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED);
+
+  return 0;
+}
+
+void
+ospf_abr_unapprove_summaries ()
+{
+  listnode node;
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_unapprove_summaries(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+      foreach_lsa (SUMMARY_LSDB (area), NULL, 0,
+                  ospf_abr_unapprove_summaries_apply);
+      foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0,
+                  ospf_abr_unapprove_summaries_apply);
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_unapprove_summaries(): Stop");
+}
+
+void
+ospf_abr_prepare_aggregates ()
+{
+  listnode node;
+  struct route_node *rn;
+  struct ospf_area_range *range;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_prepare_aggregates(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = getdata (node);
+
+      for (rn = route_top (area->ranges); rn; rn = route_next (rn))
+       if ((range = rn->info) != NULL)
+         {
+           range->cost = 0;
+           range->specifics = 0;
+         }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_prepare_aggregates(): Stop");
+}
+
+void
+ospf_abr_announce_aggregates ()
+{
+  struct ospf_area *area, *ar;
+  struct ospf_area_range *range;
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  listnode node, n;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_aggregates(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_aggregates(): looking at area %s",
+                  inet_ntoa (area->area_id));
+
+      for (rn = route_top (area->ranges); rn; rn = route_next (rn))
+       if ((range =  rn->info))
+         {
+           if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE))
+             {
+               if (IS_DEBUG_OSPF_EVENT)
+                 zlog_info ("ospf_abr_announce_aggregates():"
+                            " discarding suppress-ranges");
+               continue;
+             }
+
+           p.family = AF_INET;
+           p.prefix = range->addr;
+           p.prefixlen = range->masklen;
+
+           if (IS_DEBUG_OSPF_EVENT)
+             zlog_info ("ospf_abr_announce_aggregates():"
+                        " this is range: %s/%d",
+                        inet_ntoa (p.prefix), p.prefixlen);
+
+           if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE))
+             {
+               p.family = AF_INET;
+               p.prefix = range->subst_addr;
+               p.prefixlen = range->subst_masklen;
+             }
+
+           if (range->specifics)
+             {
+               if (IS_DEBUG_OSPF_EVENT)
+                 zlog_info ("ospf_abr_announce_aggregates(): active range");
+
+               for (n = listhead (ospf_top->areas); n; nextnode (n))
+                 {
+                   ar = getdata (n);
+                   if (ar == area)
+                     continue;
+
+                   /* We do not check nexthops here, because
+                      intra-area routes can be associated with
+                      one area only */
+
+                   /* backbone routes are not summarized
+                      when announced into transit areas */
+
+                   if (ospf_area_is_transit (ar) &&
+                       OSPF_IS_AREA_BACKBONE (area))
+                     {
+                       if (IS_DEBUG_OSPF_EVENT)
+                         zlog_info ("ospf_abr_announce_aggregates(): Skipping "
+                                    "announcement of BB aggregate into"
+                                    " a transit area");
+                       continue; 
+                     }
+                   ospf_abr_announce_network_to_area (&p, range->cost, ar);
+                 }
+             }
+         }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_aggregates(): Stop");
+}
+
+#ifdef HAVE_NSSA
+void
+ospf_abr_send_nssa_aggregates () /* temporarily turned off */
+{
+  listnode node; /*, n; */
+  struct ospf_area *area; /*, *ar; */
+  struct route_node *rn;
+  struct ospf_area_range *range;
+  struct prefix_ipv4 p;
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_send_nssa_aggregates(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (! area->NSSATranslator)
+       continue;
+
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_abr_send_nssa_aggregates(): looking at area %s",
+                  inet_ntoa (area->area_id));
+
+      for (rn = route_top (area->ranges); rn; rn = route_next (rn))
+       {
+          if (rn->info == NULL)
+           continue;
+
+         range = rn->info;
+
+          if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE))
+           {
+             if (IS_DEBUG_OSPF_NSSA)
+               zlog_info ("ospf_abr_send_nssa_aggregates():"
+                          " discarding suppress-ranges");
+             continue;
+           }
+
+          p.family = AF_INET;
+          p.prefix = range->addr;
+          p.prefixlen = range->masklen;
+
+         if (IS_DEBUG_OSPF_NSSA)
+           zlog_info ("ospf_abr_send_nssa_aggregates():"
+                      " this is range: %s/%d",
+                      inet_ntoa (p.prefix), p.prefixlen);
+
+          if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE))
+           {
+             p.family = AF_INET;
+             p.prefix = range->subst_addr;
+             p.prefixlen = range->subst_masklen;
+           }
+
+          if (range->specifics)
+           {
+             if (IS_DEBUG_OSPF_NSSA)
+               zlog_info ("ospf_abr_send_nssa_aggregates(): active range");
+
+             /* Fetch LSA-Type-7 from aggregate prefix, and then
+                 translate, Install (as Type-5), Approve, and Flood */
+               ospf_abr_translate_nssa_range (&p, range->cost);
+           } /* if (range->specifics)*/
+       } /* all area ranges*/
+    } /* all areas */
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_send_nssa_aggregates(): Stop");
+}
+
+void
+ospf_abr_announce_nssa_defaults () /* By ABR-Translator */
+{
+  listnode node;
+  struct ospf_area *area;
+  struct prefix_ipv4 p;
+
+  if (! OSPF_IS_ABR)
+    return;
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_announce_stub_defaults(): Start");
+
+  p.family = AF_INET;
+  p.prefix.s_addr = OSPF_DEFAULT_DESTINATION;
+  p.prefixlen = 0;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_abr_announce_nssa_defaults(): looking at area %s",
+                  inet_ntoa (area->area_id));
+
+      if (area->external_routing != OSPF_AREA_NSSA)
+       continue;
+
+      if (OSPF_IS_AREA_BACKBONE (area))
+       continue; /* Sanity Check */
+
+      /* if (!TranslatorRole continue V 1.0 look for "always" conf */
+      if (area->NSSATranslator)
+       {
+         if (IS_DEBUG_OSPF_NSSA)
+           zlog_info ("ospf_abr_announce_nssa_defaults(): "
+                      "announcing 0.0.0.0/0 to this nssa");
+         /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */
+       }
+    }
+}
+#endif /* HAVE_NSSA */
+
+void
+ospf_abr_announce_stub_defaults ()
+{
+  listnode node;
+  struct ospf_area *area;
+  struct prefix_ipv4 p;
+
+  if (! OSPF_IS_ABR)
+    return;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_stub_defaults(): Start");
+
+  p.family = AF_INET;
+  p.prefix.s_addr = OSPF_DEFAULT_DESTINATION;
+  p.prefixlen = 0;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_stub_defaults(): looking at area %s",
+                  inet_ntoa (area->area_id));
+
+#ifdef HAVE_NSSA
+      if (area->external_routing != OSPF_AREA_STUB)
+#else /* ! HAVE_NSSA */
+      if (area->external_routing == OSPF_AREA_DEFAULT)
+#endif /* HAVE_NSSA */
+       continue;
+
+      if (OSPF_IS_AREA_BACKBONE (area))
+       continue; /* Sanity Check */
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_announce_stub_defaults(): "
+                  "announcing 0.0.0.0/0 to this area");
+      ospf_abr_announce_network_to_area (&p, area->default_cost, area);
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_announce_stub_defaults(): Stop");
+}
+
+#ifdef HAVE_NSSA
+int
+ospf_abr_remove_unapproved_translates_apply (struct ospf_lsa *lsa, void *p_arg,
+                                            int int_arg)
+{
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)
+      && ! CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED))
+    {
+      zlog_info ("ospf_abr_remove_unapproved_translates(): "
+                "removing unapproved translates, ID: %s",
+                inet_ntoa (lsa->data->id));
+
+      /* FLUSH THROUGHOUT AS */
+      ospf_lsa_flush_as (lsa);
+
+      /* DISCARD from LSDB  */
+    }
+  return 0;
+}
+
+void
+ospf_abr_remove_unapproved_translates () /* For NSSA Translations */
+{
+  /* All AREA PROCESS should have APPROVED necessary LSAs */
+  /* Remove any left over and not APPROVED */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_remove_unapproved_translates(): Start");
+
+  foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0,
+              ospf_abr_remove_unapproved_translates_apply);
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_remove_unapproved_translates(): Stop");
+}
+#endif /* HAVE_NSSA */
+
+int
+ospf_abr_remove_unapproved_summaries_apply (struct ospf_lsa *lsa, void *p_arg,
+                                           int int_arg)
+{
+  struct ospf_area *area;
+
+  area = (struct ospf_area *) p_arg;
+
+  if (ospf_lsa_is_self_originated (lsa) &&
+      !CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_remove_unapproved_summaries(): "
+                  "removing unapproved summary, ID: %s",
+                  inet_ntoa (lsa->data->id));
+      ospf_lsa_flush_area (lsa, area);
+    }
+  return 0;
+}
+
+void
+ospf_abr_remove_unapproved_summaries ()
+{
+  listnode node;
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_remove_unapproved_summaries(): Start");
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_remove_unapproved_summaries(): "
+                  "looking at area %s", inet_ntoa (area->area_id));
+
+      foreach_lsa (SUMMARY_LSDB (area), area, 0,
+                  ospf_abr_remove_unapproved_summaries_apply);
+      foreach_lsa (ASBR_SUMMARY_LSDB (area), area, 0,
+                  ospf_abr_remove_unapproved_summaries_apply);
+    }
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_remove_unapproved_summaries(): Stop");
+}
+
+void
+ospf_abr_manage_discard_routes ()
+{
+  listnode node;
+  struct route_node *rn;
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    if ((area = node->data) != NULL)
+      for (rn = route_top (area->ranges); rn; rn = route_next (rn))
+       if ((range = rn->info) != NULL)
+         if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE))
+           {
+             if (range->specifics)
+               ospf_add_discard_route (ospf_top->new_table, area,
+                                       (struct prefix_ipv4 *) &rn->p);
+             else
+               ospf_delete_discard_route ((struct prefix_ipv4 *) &rn->p);
+           }
+}
+
+#ifdef HAVE_NSSA
+/* This is the function taking care about ABR NSSA, i.e.  NSSA
+   Translator, -LSA aggregation and flooding. For all NSSAs
+
+   Any SELF-AS-LSA is in the Type-5 LSDB and Type-7 LSDB.  These LSA's
+   are refreshed from the Type-5 LSDB, installed into the Type-7 LSDB
+   with the P-bit set.
+
+   Any received Type-5s are legal for an ABR, else illegal for IR.
+   Received Type-7s are installed, by area, with incoming P-bit.  They
+   are flooded; if the Elected NSSA Translator, then P-bit off.
+
+   Additionally, this ABR will place "translated type-7's" into the
+   Type-5 LSDB in order to keep track of APPROVAL or not.
+
+   It will scan through every area, looking for Type-7 LSAs with P-Bit
+   SET. The Type-7's are either AS-FLOODED & 5-INSTALLED or
+   AGGREGATED.  Later, the AGGREGATED LSAs are AS-FLOODED &
+   5-INSTALLED.
+
+   5-INSTALLED is into the Type-5 LSDB; Any UNAPPROVED Type-5 LSAs
+   left over are FLUSHED and DISCARDED.
+
+   For External Calculations, any NSSA areas use the Type-7 AREA-LSDB,
+   any ABR-non-NSSA areas use the Type-5 GLOBAL-LSDB. */
+
+void
+ospf_abr_nssa_task () /* called only if any_nssa */
+{
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("Check for NSSA-ABR Tasks():");
+
+  if (! OSPF_IS_ABR)
+    return;
+
+  if (! ospf_top->anyNSSA)
+    return;
+
+  /* Each area must confirm TranslatorRole */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): Start");
+
+  /* For all Global Entries flagged "local-translate", unset APPROVED */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): unapprove translates");
+
+  ospf_abr_unapprove_translates ();
+
+  /* RESET all Ranges in every Area, same as summaries */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): NSSA initialize aggregates");
+
+  /*    ospf_abr_prepare_aggregates ();  TURNED OFF just for now */
+
+  /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or
+     Aggregate as Type-7 */
+  /* Install or Approve in Type-5 Global LSDB */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): process translates");
+
+  ospf_abr_process_nssa_translates (ospf_top->new_table);
+
+  /* Translate/Send any "ranged" aggregates, and also 5-Install and
+     Approve */
+  /* Scan Type-7's for aggregates, translate to Type-5's,
+     Install/Flood/Approve */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info("ospf_abr_nssa_task(): send NSSA aggregates");
+  /*       ospf_abr_send_nssa_aggregates ();  TURNED OFF FOR NOW */
+
+  /* Send any NSSA defaults as Type-5 */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): announce nssa defaults");
+  ospf_abr_announce_nssa_defaults ();
+   
+  /* Flush any unapproved previous translates from Global Data Base */
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): remove unapproved translates");
+  ospf_abr_remove_unapproved_translates ();
+
+  ospf_abr_manage_discard_routes (); /* same as normal...discard */
+
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_abr_nssa_task(): Stop");
+}
+#endif /* HAVE_NSSA */
+
+/* This is the function taking care about ABR stuff, i.e.
+   summary-LSA origination and flooding. */
+void
+ospf_abr_task ()
+{
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_task(): Start");
+
+  if (ospf_top->new_table == NULL || ospf_top->new_rtrs == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_task(): Routing tables are not yet ready");
+      return;
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_task(): unapprove summaries");
+  ospf_abr_unapprove_summaries ();
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_task(): prepare aggregates");
+  ospf_abr_prepare_aggregates ();
+
+  if (OSPF_IS_ABR)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_task(): process network RT");
+      ospf_abr_process_network_rt (ospf_top->new_table);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_task(): process router RT");
+      ospf_abr_process_router_rt (ospf_top->new_rtrs);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_task(): announce aggregates");
+      ospf_abr_announce_aggregates ();
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_abr_task(): announce stub defaults");
+      ospf_abr_announce_stub_defaults ();
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_task(): remove unapproved summaries");
+  ospf_abr_remove_unapproved_summaries ();
+
+  ospf_abr_manage_discard_routes ();
+
+#ifdef HAVE_NSSA
+  ospf_abr_nssa_task(); /* if nssa-abr, then scan Type-7 LSDB */
+#endif /* HAVE_NSSA */
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_abr_task(): Stop");
+}
+
+
+int
+ospf_abr_task_timer (struct thread *t)
+{
+  ospf_top->t_abr_task = 0;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Running ABR task on timer");
+
+  ospf_check_abr_status ();
+
+  ospf_abr_task ();
+
+ return 0;
+}
+
+void
+ospf_schedule_abr_task ()
+{
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Scheduling ABR task");
+  if (! ospf_top->t_abr_task)
+    ospf_top->t_abr_task = thread_add_timer (master, ospf_abr_task_timer,
+                                            0, OSPF_ABR_TASK_DELAY);
+}
diff --git a/ospfd/ospf_abr.h b/ospfd/ospf_abr.h
new file mode 100644 (file)
index 0000000..3b385c3
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * OSPF ABR functions.
+ * Copyright (C) 1999 Alex Zinin
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_ABR_H
+#define _ZEBRA_OSPF_ABR_H
+
+#define OSPF_ABR_TASK_DELAY    7
+
+#define OSPF_AREA_RANGE_ADVERTISE      (1 << 0)
+#define OSPF_AREA_RANGE_SUBSTITUTE     (1 << 1)
+
+/* Area range. */
+struct ospf_area_range
+{
+  /* Area range address. */
+  struct in_addr addr;
+
+  /* Area range masklen. */
+  u_char masklen;
+
+  /* Flags. */
+  u_char flags;
+
+  /* Number of more specific prefixes. */
+  int specifics;
+
+  /* Addr and masklen to substitute. */
+  struct in_addr subst_addr;
+  u_char subst_masklen;
+
+  /* Range cost. */
+  u_int32_t cost;
+
+  /* Configured range cost. */
+  u_int32_t cost_config;
+#define OSPF_AREA_RANGE_COST_UNSPEC    -1
+};
+
+/* Prototypes. */
+struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *,
+                                               struct prefix_ipv4 *);
+struct ospf_area_range *ospf_some_area_range_match (struct prefix_ipv4 *);
+struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *,
+                                                    struct in_addr *, int);
+int ospf_area_range_set (struct ospf *, struct in_addr, struct prefix_ipv4 *,
+                        int);
+int ospf_area_range_cost_set (struct ospf *, struct in_addr,
+                             struct prefix_ipv4 *, u_int32_t);
+int ospf_area_range_unset (struct ospf *, struct in_addr,
+                          struct prefix_ipv4 *);
+int ospf_area_range_substitute_set (struct ospf *, struct in_addr,
+                                   struct prefix_ipv4 *,
+                                   struct prefix_ipv4 *);
+int ospf_area_range_substitute_unset (struct ospf *, struct in_addr,
+                                     struct prefix_ipv4 *);
+struct ospf_area_range *ospf_area_range_match_any (struct ospf *,
+                                                  struct prefix_ipv4 *);
+int ospf_area_range_active (struct ospf_area_range *);
+int ospf_act_bb_connection ();
+
+void ospf_check_abr_status ();
+void ospf_abr_task ();
+void ospf_schedule_abr_task ();
+
+#endif /* _ZEBRA_OSPF_ABR_H */
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
new file mode 100644 (file)
index 0000000..d13bbc4
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * OSPF AS Boundary Router functions.
+ * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "vty.h"
+#include "filter.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+\f
+/* Remove external route. */
+void
+ospf_external_route_remove (struct prefix_ipv4 *p)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+
+  rn = route_node_lookup (ospf_top->old_external_route, (struct prefix *) p);
+  if (rn)
+    if ((or = rn->info))
+      {
+       zlog_info ("Route[%s/%d]: external path deleted",
+                  inet_ntoa (p->prefix), p->prefixlen);
+
+       /* Remove route from zebra. */
+        if (or->type == OSPF_DESTINATION_NETWORK)
+         ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
+
+       ospf_route_free (or);
+       rn->info = NULL;
+
+       route_unlock_node (rn);
+       route_unlock_node (rn);
+       return;
+      }
+
+  zlog_info ("Route[%s/%d]: no such external path",
+            inet_ntoa (p->prefix), p->prefixlen);
+}
+
+/* Lookup external route. */
+struct ospf_route *
+ospf_external_route_lookup (struct prefix_ipv4 *p)
+{
+  struct route_node *rn;
+
+  rn = route_node_lookup (ospf_top->old_external_route, (struct prefix *) p);
+  if (rn)
+    {
+      route_unlock_node (rn);
+      if (rn->info)
+       return rn->info;
+    }
+
+  zlog_warn ("Route[%s/%d]: lookup, no such prefix",
+            inet_ntoa (p->prefix), p->prefixlen);
+
+  return NULL;
+}
+
+\f
+/* Add an External info for AS-external-LSA. */
+struct external_info *
+ospf_external_info_new (u_char type)
+{
+  struct external_info *new;
+
+  new = (struct external_info *)
+    XMALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info));
+  memset (new, 0, sizeof (struct external_info));
+  new->type = type;
+
+  ospf_reset_route_map_set_values (&new->route_map_set);
+  return new;
+}
+
+void
+ospf_external_info_free (struct external_info *ei)
+{
+  XFREE (MTYPE_OSPF_EXTERNAL_INFO, ei);
+}
+
+void
+ospf_reset_route_map_set_values (struct route_map_set_values *values)
+{
+  values->metric = -1;
+  values->metric_type = -1;
+}
+
+int
+ospf_route_map_set_compare (struct route_map_set_values *values1,
+                           struct route_map_set_values *values2)
+{
+  return values1->metric == values2->metric &&
+    values1->metric_type == values2->metric_type;
+}
+
+/* Add an External info for AS-external-LSA. */
+struct external_info *
+ospf_external_info_add (u_char type, struct prefix_ipv4 p,
+                       unsigned int ifindex, struct in_addr nexthop)
+{
+  struct external_info *new;
+  struct route_node *rn;
+
+  /* Initialize route table. */
+  if (EXTERNAL_INFO (type) == NULL)
+    EXTERNAL_INFO (type) = route_table_init ();
+
+  rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p);
+  /* If old info exists, -- discard new one or overwrite with new one? */
+  if (rn)
+    if (rn->info)
+      {
+       route_unlock_node (rn);
+       zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.",
+                  LOOKUP (ospf_redistributed_proto, type),
+                  inet_ntoa (p.prefix), p.prefixlen);
+       /* XFREE (MTYPE_OSPF_TMP, rn->info); */
+       return rn->info;
+      }
+
+  /* Create new External info instance. */
+  new = ospf_external_info_new (type);
+  new->p = p;
+  new->ifindex = ifindex;
+  new->nexthop = nexthop;
+  new->tag = 0;
+
+  rn->info = new;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("Redistribute[%s]: %s/%d external info created.",
+              LOOKUP (ospf_redistributed_proto, type),
+              inet_ntoa (p.prefix), p.prefixlen);
+  return new;
+}
+
+void
+ospf_external_info_delete (u_char type, struct prefix_ipv4 p)
+{
+  struct route_node *rn;
+
+  rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p);
+  if (rn)
+    {
+      ospf_external_info_free (rn->info);
+      rn->info = NULL;
+      route_unlock_node (rn);
+      route_unlock_node (rn);
+    }
+}
+
+struct external_info *
+ospf_external_info_lookup (u_char type, struct prefix_ipv4 *p)
+{
+  struct route_node *rn;
+  rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) p);
+  if (rn)
+    {
+      route_unlock_node (rn);
+      if (rn->info)
+       return rn->info;
+    }
+
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_external_info_find_lsa (struct prefix_ipv4 *p)
+{
+  struct ospf_lsa *lsa;
+  struct as_external_lsa *al;
+  struct in_addr mask, id;
+
+  lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA,
+                              p->prefix, ospf_top->router_id);
+
+  if (!lsa)
+    return NULL;
+
+  al = (struct as_external_lsa *) lsa->data;
+
+  masklen2ip (p->prefixlen, &mask);
+
+  if (mask.s_addr != al->mask.s_addr)
+    {
+      id.s_addr = p->prefix.s_addr | (~mask.s_addr);
+      lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA,
+                                  id, ospf_top->router_id);
+      if (!lsa)
+       return NULL;
+    }
+
+  return lsa;
+}
+
+\f
+/* Update ASBR status. */
+void
+ospf_asbr_status_update (u_char status)
+{
+  zlog_info ("ASBR[Status:%d]: Update", status);
+
+  /* ASBR on. */
+  if (status)
+    {
+      /* Already ASBR. */
+      if (OSPF_IS_ASBR)
+       {
+         zlog_info ("ASBR[Status:%d]: Already ASBR", status);
+         return;
+       }
+      SET_FLAG (ospf_top->flags, OSPF_FLAG_ASBR);
+    }
+  else
+    {
+      /* Already non ASBR. */
+      if (! OSPF_IS_ASBR)
+       {
+         zlog_info ("ASBR[Status:%d]: Already non ASBR", status);
+         return;
+       }
+      UNSET_FLAG (ospf_top->flags, OSPF_FLAG_ASBR);
+    }
+
+  /* Transition from/to status ASBR, schedule timer. */
+  ospf_spf_calculate_schedule ();
+  OSPF_TIMER_ON (ospf_top->t_router_lsa_update,
+                ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
+}
+
+void
+ospf_redistribute_withdraw (u_char type)
+{
+  struct route_node *rn;
+  struct external_info *ei;
+
+  /* Delete external info for specified type. */
+  if (EXTERNAL_INFO (type))
+    for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn))
+      if ((ei = rn->info))
+       if (ospf_external_info_find_lsa (&ei->p))
+         {
+           if (is_prefix_default (&ei->p) &&
+               ospf_top->default_originate != DEFAULT_ORIGINATE_NONE)
+             continue;
+           ospf_external_lsa_flush (type, &ei->p, ei->ifindex, ei->nexthop);
+           ospf_external_info_delete (type, ei->p);
+         }
+}
diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h
new file mode 100644 (file)
index 0000000..f368246
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * OSPF AS Boundary Router functions.
+ * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_ASBR_H
+#define _ZEBRA_OSPF_ASBR_H
+
+struct route_map_set_values
+{
+  int32_t metric;
+  int32_t metric_type;
+};
+
+/* Redistributed external information. */
+struct external_info
+{
+  /* Type of source protocol. */
+  u_char type;
+
+  /* Prefix. */
+  struct prefix_ipv4 p;
+
+  /* Interface index. */
+  unsigned int ifindex;
+
+  /* Nexthop address. */
+  struct in_addr nexthop;
+
+  /* Additional Route tag. */
+  u_int32_t tag;
+
+  struct route_map_set_values route_map_set;
+#define ROUTEMAP_METRIC(E)      (E)->route_map_set.metric
+#define ROUTEMAP_METRIC_TYPE(E) (E)->route_map_set.metric_type
+};
+
+#define OSPF_ASBR_CHECK_DELAY 30
+
+void ospf_external_route_remove (struct prefix_ipv4 *p);
+struct external_info *ospf_external_info_new (u_char);
+void ospf_reset_route_map_set_values (struct route_map_set_values *values);
+int ospf_route_map_set_compare (struct route_map_set_values *values1,
+                               struct route_map_set_values *values2);
+struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4,
+                                             unsigned int, struct in_addr);
+void ospf_external_info_delete (u_char, struct prefix_ipv4);
+struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *);
+
+void ospf_asbr_status_update (u_char);
+
+void ospf_redistribute_withdraw (u_char);
+void ospf_asbr_check ();
+void ospf_schedule_asbr_check ();
+void ospf_asbr_route_install_lsa (struct ospf_lsa *);
+struct ospf_lsa *ospf_external_info_find_lsa (struct prefix_ipv4 *p);
+
+#endif /* _ZEBRA_OSPF_ASBR_H */
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
new file mode 100644 (file)
index 0000000..9194c56
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * OSPF AS external route calculation.
+ * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "vty.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+#define DEBUG
+
+struct ospf_route *
+ospf_find_asbr_route (struct route_table *rtrs, struct prefix_ipv4 *asbr)
+{
+  struct route_node *rn;
+  struct ospf_route *or, *best = NULL;
+  listnode node;
+  list chosen;
+
+  /* Sanity check. */
+  if (rtrs == NULL)
+    return NULL;
+
+  rn = route_node_lookup (rtrs, (struct prefix *) asbr);
+  if (! rn)
+    return NULL;
+
+  route_unlock_node (rn);
+
+  chosen = list_new ();
+
+  /* First try to find intra-area non-bb paths. */
+  if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+    for (node = listhead ((list) rn->info); node; nextnode (node))
+      if ((or = getdata (node)) != NULL)
+       if (or->cost < OSPF_LS_INFINITY)
+         if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) &&
+             or->path_type == OSPF_PATH_INTRA_AREA)
+           listnode_add (chosen, or);
+
+  /* If none is found -- look through all. */
+  if (listcount (chosen) == 0)
+    {
+      list_free (chosen);
+      chosen = rn->info;
+    }
+
+  /* Now find the route with least cost. */
+  for (node = listhead (chosen); node; nextnode (node))
+    if ((or = getdata (node)) != NULL)
+      if (or->cost < OSPF_LS_INFINITY)
+       {
+         if (best == NULL)
+           best = or;
+         else if (best->cost > or->cost)
+           best = or;
+         else if (best->cost == or->cost &&
+                  IPV4_ADDR_CMP (&best->u.std.area_id,
+                                 &or->u.std.area_id) < 0)
+           best = or;
+       }
+
+  if (chosen != rn->info)
+    list_delete (chosen);
+
+  return best;
+}
+
+struct ospf_route * 
+ospf_find_asbr_route_through_area (struct route_table *rtrs, 
+                                  struct prefix_ipv4 *asbr, 
+                                  struct ospf_area *area)
+{
+  struct route_node *rn;
+
+  /* Sanity check. */
+  if (rtrs == NULL)
+    return NULL;
+
+  rn = route_node_lookup (rtrs, (struct prefix *) asbr);
+  if (rn)
+    {
+      listnode node;
+      struct ospf_route *or;
+
+      route_unlock_node (rn);
+
+      for (node = listhead ((list) rn->info); node; nextnode (node))
+       if ((or = getdata (node)) != NULL)
+         if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
+           return or;
+    }
+
+  return NULL;
+}
+
+void
+ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop)
+{
+  listnode node;
+  struct ospf_path *op;
+
+  for (node = listhead (ro->path); node; nextnode (node))
+    if ((op = getdata (node)) != NULL)
+      if (op->nexthop.s_addr == 0)
+       op->nexthop.s_addr = nexthop.s_addr;
+}
+
+int
+ospf_ase_forward_address_check (struct in_addr fwd_addr)
+{
+  listnode ifn;
+  struct ospf_interface *oi;
+
+  for (ifn = listhead (ospf_top->oiflist); ifn; nextnode (ifn))
+    if ((oi = getdata (ifn)) != NULL)
+      if (if_is_up (oi->ifp))
+       if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+         if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr))
+           return 0;
+  
+  return 1;
+}
+
+/* Calculate ASBR route. */
+struct ospf_route *
+ospf_ase_calculate_asbr_route (struct route_table *rt_network,
+                              struct route_table *rt_router,
+                              struct as_external_lsa *al)
+{
+  struct prefix_ipv4 asbr;
+  struct ospf_route *asbr_route;
+  struct route_node *rn;
+
+  /* Find ASBR route from Router routing table. */
+  asbr.family = AF_INET;
+  asbr.prefix = al->header.adv_router;
+  asbr.prefixlen = IPV4_MAX_BITLEN;
+  apply_mask_ipv4 (&asbr);
+
+  asbr_route = ospf_find_asbr_route (rt_router, &asbr);
+
+  if (asbr_route == NULL)
+    {
+      zlog_info ("ospf_ase_calculate(): Route to ASBR %s not found",
+                inet_ntoa (asbr.prefix));
+      return NULL;
+    }
+
+  if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
+    {
+      zlog_info ("ospf_ase_calculate(): Originating router is not an ASBR");
+      return NULL;
+    }
+   
+  if (al->e[0].fwd_addr.s_addr != 0)
+    {
+      zlog_info ("ospf_ase_calculate(): "
+                "Forwarding address is not 0.0.0.0.");
+
+      if (! ospf_ase_forward_address_check (al->e[0].fwd_addr))
+       {
+         zlog_info ("ospf_ase_calculate(): "
+                    "Forwarding address is one of our addresses, Ignore.");
+         return NULL;
+        }
+
+      zlog_info ("ospf_ase_calculate(): "
+                "Looking up in the Network Routing Table.");
+
+      /* Looking up the path to the fwd_addr from Network route. */
+      asbr.family = AF_INET;
+      asbr.prefix = al->e[0].fwd_addr;
+      asbr.prefixlen = IPV4_MAX_BITLEN;
+
+      rn = route_node_match (rt_network, (struct prefix *) &asbr);
+   
+      if (rn == NULL)
+       {
+         zlog_info ("ospf_ase_calculate(): "
+                    "Couldn't find a route to the forwarding address.");
+         return NULL;
+       }
+
+      route_unlock_node (rn);
+
+      if ((asbr_route = rn->info) == NULL)
+       {
+         zlog_info ("ospf_ase_calculate(): "
+                    "Somehow OSPF route to ASBR is lost");
+         return NULL;
+       }
+    }
+
+  return asbr_route;
+}
+
+struct ospf_route *
+ospf_ase_calculate_new_route (struct ospf_lsa *lsa,
+                             struct ospf_route *asbr_route, u_int32_t metric)
+{
+  struct as_external_lsa *al;
+  struct ospf_route *new;
+
+  al = (struct as_external_lsa *) lsa->data;
+
+  new = ospf_route_new ();
+
+  /* Set redistributed type -- does make sense? */
+  /* new->type = type; */
+  new->id = al->header.id;
+  new->mask = al->mask;
+
+  if (!IS_EXTERNAL_METRIC (al->e[0].tos))
+    {
+      zlog_info ("Route[External]: type-1 created.");
+      new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
+      new->cost = asbr_route->cost + metric;           /* X + Y */
+    }
+  else
+    {
+      zlog_info ("Route[External]: type-2 created.");
+      new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
+      new->cost = asbr_route->cost;                    /* X */
+      new->u.ext.type2_cost = metric;                  /* Y */
+    }
+
+  new->type = OSPF_DESTINATION_NETWORK;
+  new->path = list_new ();
+  new->u.ext.origin = lsa;
+  new->u.ext.tag = ntohl (al->e[0].route_tag);
+  new->u.ext.asbr = asbr_route;
+
+  assert (new != asbr_route);
+
+  return new;
+}
+
+#define OSPF_ASE_CALC_INTERVAL 1
+
+int
+ospf_ase_calculate_route (struct ospf_lsa * lsa, void * p_arg, int n_arg)
+{
+  u_int32_t metric;
+  struct as_external_lsa *al;
+  struct ospf_route *asbr_route;
+  struct prefix_ipv4 asbr, p;
+  struct route_node *rn;
+  struct ospf_route *new, *or;
+  int ret;
+  
+  assert (lsa);
+  al = (struct as_external_lsa *) lsa->data;
+
+#ifdef HAVE_NSSA
+  if (lsa->data->type == OSPF_AS_NSSA_LSA)
+    if (IS_DEBUG_OSPF_NSSA)
+      zlog_info ("ospf_ase_calc(): Processing Type-7");
+
+  /* Stay away from any Local Translated Type-7 LSAs */
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+    {
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd");
+      return 0;
+    }
+#endif /* HAVE_NSSA */
+
+  zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d",
+            inet_ntoa (al->header.id), ip_masklen (al->mask));
+  /* (1) If the cost specified by the LSA is LSInfinity, or if the
+         LSA's LS age is equal to MaxAge, then examine the next LSA. */
+  if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
+    {
+      zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY");
+      return 0;
+    }
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      zlog_info ("Route[External]: AS-external-LSA is MAXAGE");
+      return 0;
+    }
+  
+  /* (2) If the LSA was originated by the calculating router itself,
+     examine the next LSA. */
+  if (IS_LSA_SELF (lsa))
+    {
+      zlog_info ("Route[External]: AS-external-LSA is self originated");
+      return 0;
+    }
+
+  /* (3) Call the destination described by the LSA N.  N's address is
+         obtained by masking the LSA's Link State ID with the
+        network/subnet mask contained in the body of the LSA.  Look
+        up the routing table entries (potentially one per attached
+        area) for the AS boundary router (ASBR) that originated the
+        LSA. If no entries exist for router ASBR (i.e., ASBR is
+        unreachable), do nothing with this LSA and consider the next
+        in the list. */
+  
+  asbr.family = AF_INET;
+  asbr.prefix = al->header.adv_router;
+  asbr.prefixlen = IPV4_MAX_BITLEN;
+  apply_mask_ipv4 (&asbr);
+  
+  asbr_route = ospf_find_asbr_route (ospf_top->new_rtrs, &asbr);
+  if (asbr_route == NULL)
+    {
+      zlog_info ("Route[External]: Can't find originating ASBR route");
+      return 0;
+    }
+  if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
+    {
+      zlog_info ("Route[External]: Originating router is not an ASBR");
+      return 0;
+    }
+  
+  /*     Else, this LSA describes an AS external path to destination
+        N.  Examine the forwarding address specified in the AS-
+        external-LSA.  This indicates the IP address to which
+        packets for the destination should be forwarded. */
+  
+  if (al->e[0].fwd_addr.s_addr == 0)
+    {
+      /* If the forwarding address is set to 0.0.0.0, packets should
+        be sent to the ASBR itself. Among the multiple routing table
+        entries for the ASBR, select the preferred entry as follows.
+        If RFC1583Compatibility is set to "disabled", prune the set
+        of routing table entries for the ASBR as described in
+        Section 16.4.1. In any case, among the remaining routing
+        table entries, select the routing table entry with the least
+        cost; when there are multiple least cost routing table
+        entries the entry whose associated area has the largest OSPF
+        Area ID (when considered as an unsigned 32-bit integer) is
+        chosen. */
+
+      /* asbr_route already contains the requested route */
+    }
+  else
+    {
+      /* If the forwarding address is non-zero, look up the
+        forwarding address in the routing table.[24] The matching
+        routing table entry must specify an intra-area or inter-area
+        path; if no such path exists, do nothing with the LSA and
+        consider the next in the list. */
+      if (! ospf_ase_forward_address_check (al->e[0].fwd_addr))
+       {
+         zlog_info ("Route[External]: Forwarding address is our router address");
+         return 0;
+       }
+      
+      asbr.family = AF_INET;
+      asbr.prefix = al->e[0].fwd_addr;
+      asbr.prefixlen = IPV4_MAX_BITLEN;
+
+      rn = route_node_match (ospf_top->new_table, (struct prefix *) &asbr);
+      
+      if (rn == NULL || (asbr_route = rn->info) == NULL)
+       {
+         zlog_info ("Route[External]: Can't find route to forwarding address");
+         if (rn)
+           route_unlock_node (rn);
+         return 0;
+       }
+
+      route_unlock_node (rn);
+    }
+
+  /* (4) Let X be the cost specified by the preferred routing table
+         entry for the ASBR/forwarding address, and Y the cost
+        specified in the LSA.  X is in terms of the link state
+        metric, and Y is a type 1 or 2 external metric. */
+                        
+
+  /* (5) Look up the routing table entry for the destination N.  If
+         no entry exists for N, install the AS external path to N,
+        with next hop equal to the list of next hops to the
+        forwarding address, and advertising router equal to ASBR.
+        If the external metric type is 1, then the path-type is set
+        to type 1 external and the cost is equal to X+Y.  If the
+        external metric type is 2, the path-type is set to type 2
+        external, the link state component of the route's cost is X,
+        and the type 2 cost is Y. */
+  new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
+
+  /* (6) Compare the AS external path described by the LSA with the
+         existing paths in N's routing table entry, as follows. If
+        the new path is preferred, it replaces the present paths in
+        N's routing table entry.  If the new path is of equal
+        preference, it is added to N's routing table entry's list of
+        paths. */
+
+  /* Set prefix. */
+  p.family = AF_INET;
+  p.prefix = al->header.id;
+  p.prefixlen = ip_masklen (al->mask);
+
+  /* if there is a Intra/Inter area route to the N
+     do not install external route */
+  if ((rn = route_node_lookup (ospf_top->new_table,
+                              (struct prefix *) &p)) != NULL
+      && (rn->info != NULL))
+    {
+      if (new)
+       ospf_route_free (new);
+      return 0;
+    }
+  
+  /* Find a route to the same dest */
+  /* If there is no route, create new one. */
+  if ((rn = route_node_lookup (ospf_top->new_external_route,
+                              (struct prefix *) &p)) == NULL 
+      || (or = rn->info) == NULL)
+    {
+      zlog_info ("Route[External]: Adding a new route %s/%d",
+                inet_ntoa (p.prefix), p.prefixlen);
+
+      ospf_route_add (ospf_top->new_external_route, &p, new, asbr_route);
+
+      if (al->e[0].fwd_addr.s_addr)
+       ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
+      return 0;
+    }
+  else
+    {
+      /* (a) Intra-area and inter-area paths are always preferred
+             over AS external paths.
+
+         (b) Type 1 external paths are always preferred over type 2
+             external paths. When all paths are type 2 external
+            paths, the paths with the smallest advertised type 2
+            metric are always preferred. */
+      ret = ospf_route_cmp (new, or);
+  
+  /*     (c) If the new AS external path is still indistinguishable
+             from the current paths in the N's routing table entry,
+            and RFC1583Compatibility is set to "disabled", select
+            the preferred paths based on the intra-AS paths to the
+            ASBR/forwarding addresses, as specified in Section
+            16.4.1.
+
+         (d) If the new AS external path is still indistinguishable
+             from the current paths in the N's routing table entry,
+            select the preferred path based on a least cost
+            comparison.  Type 1 external paths are compared by
+            looking at the sum of the distance to the forwarding
+            address and the advertised type 1 metric (X+Y).  Type 2
+            external paths advertising equal type 2 metrics are
+            compared by looking at the distance to the forwarding
+            addresses.
+  */
+      /* New route is better */
+      if (ret < 0)
+       {
+         zlog_info ("Route[External]: New route is better");
+         ospf_route_subst (rn, new, asbr_route);
+         if (al->e[0].fwd_addr.s_addr)
+           ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
+         or = new;
+         new = NULL;
+       }
+      /* Old route is better */
+      else if (ret > 0)
+       {
+         zlog_info ("Route[External]: Old route is better");
+         /* do nothing */
+       }
+      /* Routes are equal */
+      else
+       {
+         zlog_info ("Route[External]: Routes are equal");
+         ospf_route_copy_nexthops (or, asbr_route->path);
+         if (al->e[0].fwd_addr.s_addr)
+           ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
+       }
+    }
+  /* Make sure setting newly calculated ASBR route.*/
+  or->u.ext.asbr = asbr_route;
+  if (new)
+    ospf_route_free (new);
+
+  lsa->route = or;
+  return 0;
+}
+
+int
+ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
+                          struct ospf_route *newor)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct ospf_path *op;
+  struct ospf_path *newop;
+  listnode n1;
+  listnode n2;
+
+  if (! rt || ! prefix)
+    return 0;
+
+   rn = route_node_lookup (rt, prefix);
+   if (! rn)
+     return 0;
+   route_unlock_node (rn);
+
+   or = rn->info;
+   if (or->path_type != newor->path_type)
+     return 0;
+
+   switch (or->path_type)
+     {
+     case OSPF_PATH_TYPE1_EXTERNAL:
+       if (or->cost != newor->cost)
+        return 0;
+       break;
+     case OSPF_PATH_TYPE2_EXTERNAL:
+       if ((or->cost != newor->cost) ||
+          (or->u.ext.type2_cost != newor->u.ext.type2_cost))
+        return 0;
+       break;
+     default:
+       assert (0);
+       return 0;
+     }
+   
+   if (or->path->count != newor->path->count)
+     return 0;
+       
+   /* Check each path. */
+   for (n1 = listhead (or->path), n2 = listhead (newor->path);
+       n1 && n2; nextnode (n1), nextnode (n2))
+     { 
+       op = getdata (n1);
+       newop = getdata (n2);
+       
+       if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
+        return 0;
+     }
+   return 1;
+}
+
+int
+ospf_ase_compare_tables (struct route_table *new_external_route,
+                        struct route_table *old_external_route)
+{
+  struct route_node *rn, *new_rn;
+  struct ospf_route *or;
+  
+  /* Remove deleted routes */
+  for (rn = route_top (old_external_route); rn; rn = route_next (rn))
+    if ((or = rn->info))
+      {
+       if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
+         ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
+       else
+         route_unlock_node (new_rn);
+      }
+  
+       
+  /* Install new routes */
+  for (rn = route_top (new_external_route); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL)
+      if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
+       ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
+                                      
+  return 0;
+}
+
+int
+ospf_ase_calculate_timer (struct thread *t)
+{
+  struct ospf *ospf;
+
+#ifdef HAVE_NSSA
+      listnode node;
+      struct ospf_area *area;
+#endif /* HAVE_NSSA */
+
+  ospf = THREAD_ARG (t);
+  ospf->t_ase_calc = NULL;
+
+  if (ospf->ase_calc)
+    {
+      ospf->ase_calc = 0;
+
+      /* Calculate external route for each AS-external-LSA */
+      foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0,
+                  ospf_ase_calculate_route);
+
+#ifdef HAVE_NSSA
+      /*  This version simple adds to the table all NSSA areas  */
+      if (ospf_top->anyNSSA)
+       for (node = listhead (ospf_top->areas); node; nextnode (node))
+         {
+           area = getdata (node);
+           if (IS_DEBUG_OSPF_NSSA)
+             zlog_info ("ospf_ase_calculate_timer(): looking at area %s",
+                        inet_ntoa (area->area_id));
+
+           if (area->external_routing == OSPF_AREA_NSSA)
+
+             foreach_lsa (NSSA_LSDB (area), NULL, 0,
+                          ospf_ase_calculate_route);
+         }
+#endif /* HAVE_NSSA */
+
+      /* Compare old and new external routing table and install the
+        difference info zebra/kernel */
+      ospf_ase_compare_tables (ospf_top->new_external_route,
+                              ospf_top->old_external_route);
+
+      /* Delete old external routing table */
+      ospf_route_table_free (ospf_top->old_external_route);
+      ospf_top->old_external_route = ospf_top->new_external_route;
+      ospf_top->new_external_route = route_table_init ();
+    }
+  return 0;
+}
+
+void
+ospf_ase_calculate_schedule ()
+{
+  if (! ospf_top)
+    return;
+
+  ospf_top->ase_calc = 1;
+}
+
+void
+ospf_ase_calculate_timer_add ()
+{
+  if (! ospf_top)
+    return;
+
+  if (! ospf_top->t_ase_calc)
+    ospf_top->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
+                                            ospf_top, OSPF_ASE_CALC_INTERVAL);
+}
+
+void
+ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  list lst;
+  struct as_external_lsa *al;
+
+  al = (struct as_external_lsa *) lsa->data;
+  p.family = AF_INET;
+  p.prefix = lsa->data->id;
+  p.prefixlen = ip_masklen (al->mask);
+  apply_mask_ipv4 (&p);
+
+  rn = route_node_get (top->external_lsas, (struct prefix *) &p);
+  if ((lst = rn->info) == NULL)
+    rn->info = lst = list_new();
+
+  /* We assume that if LSA is deleted from DB
+     is is also deleted from this RT */
+
+  listnode_add (lst, ospf_lsa_lock (lsa));
+}
+
+void
+ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  list lst;
+  struct as_external_lsa *al;
+
+  al = (struct as_external_lsa *) lsa->data;
+  p.family = AF_INET;
+  p.prefix = lsa->data->id;
+  p.prefixlen = ip_masklen (al->mask);
+  apply_mask_ipv4 (&p);
+
+  rn = route_node_get (top->external_lsas, (struct prefix *) &p);
+  lst = rn->info;
+#ifdef ORIGINAL_CODING
+  assert (lst);
+
+  listnode_delete (lst, lsa);
+  ospf_lsa_unlock (lsa);
+#else /* ORIGINAL_CODING */
+  /* XXX lst can be NULL */
+  if (lst) {
+    listnode_delete (lst, lsa);
+    ospf_lsa_unlock (lsa);
+  }
+#endif /* ORIGINAL_CODING */
+}
+
+void
+ospf_ase_external_lsas_finish (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_lsa *lsa;
+  list lst;
+  listnode node;
+  
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((lst = rn->info) != NULL)
+      {
+       for (node = listhead (lst); node; node = nextnode (node))
+         if ((lsa = getdata (node)) != NULL)
+           ospf_lsa_unlock (lsa);
+       list_delete (lst);
+      }
+  
+  route_table_finish (rt);
+}
+
+void
+ospf_ase_incremental_update (struct ospf_lsa *lsa, struct ospf *top)
+{
+  list lsas;
+  listnode node;
+  struct route_node *rn, *rn2;
+  struct prefix_ipv4 p;
+  struct route_table *tmp_old;
+  struct as_external_lsa *al;
+
+  al = (struct as_external_lsa *) lsa->data;
+  p.family = AF_INET;
+  p.prefix = lsa->data->id;
+  p.prefixlen = ip_masklen (al->mask);
+  apply_mask_ipv4 (&p);
+
+  /* if new_table is NULL, there was no spf calculation, thus
+     incremental update is unneeded */
+  if (!top->new_table)
+    return;
+  
+  /* If there is already an intra-area or inter-area route
+     to the destination, no recalculation is necessary
+     (internal routes take precedence). */
+  
+  rn = route_node_lookup (top->new_table, (struct prefix *) &p);
+  if (rn && rn->info)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  rn = route_node_lookup (top->external_lsas, (struct prefix *) &p);
+  assert (rn && rn->info);
+  lsas = rn->info;
+  
+  for (node = listhead (lsas); node; nextnode (node))
+    if ((lsa = getdata (node)) != NULL)
+      ospf_ase_calculate_route (lsa, NULL, 0);
+
+  /* prepare temporary old routing table for compare */
+  tmp_old = route_table_init ();
+  rn = route_node_lookup (top->old_external_route, (struct prefix *) &p);
+  if (rn && rn->info)
+    {
+      rn2 = route_node_get (tmp_old, (struct prefix *) &p);
+      rn2->info = rn->info;
+    }
+
+  /* install changes to zebra */
+  ospf_ase_compare_tables (top->new_external_route, tmp_old);
+
+  /* update top->old_external_route table */
+  if (rn && rn->info)
+    ospf_route_free ((struct ospf_route *) rn->info);
+
+  rn2 = route_node_lookup (top->new_external_route, (struct prefix *) &p);
+  /* if new route exists, install it to top->old_external_route */
+  if (rn2 && rn2->info)
+    {
+      if (!rn)
+       rn = route_node_get (top->old_external_route, (struct prefix *) &p);
+      rn->info = rn2->info;
+    }
+  else
+    {
+      /* remove route node from top->old_external_route */
+      if (rn)
+       {
+         rn->info = NULL;
+         route_unlock_node (rn);
+         route_unlock_node (rn);
+       }
+    }
+
+  if (rn2)
+    {
+      /* rn2->info is stored in route node of top->old_external_route */
+      rn2->info = NULL;
+      route_unlock_node (rn2);
+      route_unlock_node (rn2);
+    }
+
+  route_table_finish (tmp_old);
+}
diff --git a/ospfd/ospf_ase.h b/ospfd/ospf_ase.h
new file mode 100644 (file)
index 0000000..f403e26
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * OSPF AS External route calculation.
+ * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_ASE_H
+#define _ZEBRA_OSPF_ASE_H
+
+
+struct ospf_route *ospf_find_asbr_route (struct route_table *,
+                                        struct prefix_ipv4 *);
+struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *, 
+                                                    struct prefix_ipv4 *, 
+                                                    struct ospf_area *);
+
+int ospf_ase_calculate_route (struct ospf_lsa *, void *, int);
+void ospf_ase_calculate_schedule ();
+void ospf_ase_calculate_timer_add ();
+
+void ospf_ase_external_lsas_finish (struct route_table *);
+void ospf_ase_incremental_update (struct ospf_lsa *, struct ospf *);
+void ospf_ase_register_external_lsa (struct ospf_lsa *, struct ospf *);
+void ospf_ase_unregister_external_lsa (struct ospf_lsa *, struct ospf *);
+
+#endif /* _ZEBRA_OSPF_ASE_H */
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
new file mode 100644 (file)
index 0000000..da2e097
--- /dev/null
@@ -0,0 +1,1673 @@
+/*
+ * OSPFd dump routine.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "thread.h"
+#include "prefix.h"
+#include "command.h"
+#include "stream.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_network.h"
+
+struct message ospf_ism_state_msg[] =
+{
+  { ISM_DependUpon,   "DependUpon" },
+  { ISM_Down,         "Down" },
+  { ISM_Loopback,     "Loopback" },
+  { ISM_Waiting,      "Waiting" },
+  { ISM_PointToPoint, "Point-To-Point" },
+  { ISM_DROther,      "DROther" },
+  { ISM_Backup,       "Backup" },
+  { ISM_DR,           "DR" },
+};
+int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX;
+
+struct message ospf_nsm_state_msg[] =
+{
+  { NSM_DependUpon, "DependUpon" },
+  { NSM_Down,       "Down" },
+  { NSM_Attempt,    "Attempt" },
+  { NSM_Init,       "Init" },
+  { NSM_TwoWay,     "2-Way" },
+  { NSM_ExStart,    "ExStart" },
+  { NSM_Exchange,   "Exchange" },
+  { NSM_Loading,    "Loading" },
+  { NSM_Full,       "Full" },
+};
+int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX;
+
+struct message ospf_lsa_type_msg[] =
+{
+  { OSPF_UNKNOWN_LSA,      "unknown" },
+  { OSPF_ROUTER_LSA,       "router-LSA" },
+  { OSPF_NETWORK_LSA,      "network-LSA" },
+  { OSPF_SUMMARY_LSA,      "summary-LSA" },
+  { OSPF_ASBR_SUMMARY_LSA, "summary-LSA" },
+  { OSPF_AS_EXTERNAL_LSA,  "AS-external-LSA" },
+  { OSPF_GROUP_MEMBER_LSA, "GROUP MEMBER LSA" },
+  { OSPF_AS_NSSA_LSA,      "NSSA-LSA" },
+  { 8,                     "Type-8 LSA" },
+  { OSPF_OPAQUE_LINK_LSA,  "Link-Local Opaque-LSA" },
+  { OSPF_OPAQUE_AREA_LSA,  "Area-Local Opaque-LSA" },
+  { OSPF_OPAQUE_AS_LSA,    "AS-external Opaque-LSA" },
+};
+int ospf_lsa_type_msg_max = OSPF_MAX_LSA;
+
+struct message ospf_link_state_id_type_msg[] =
+{
+  { OSPF_UNKNOWN_LSA,      "(unknown)" },
+  { OSPF_ROUTER_LSA,       "" },
+  { OSPF_NETWORK_LSA,      "(address of Designated Router)" },
+  { OSPF_SUMMARY_LSA,      "(summary Network Number)" },
+  { OSPF_ASBR_SUMMARY_LSA, "(AS Boundary Router address)" },
+  { OSPF_AS_EXTERNAL_LSA,  "(External Network Number)" },
+  { OSPF_GROUP_MEMBER_LSA, "(Group membership information)" },
+  { OSPF_AS_NSSA_LSA,      "(External Network Number for NSSA)" },
+  { 8,                     "(Type-8 LSID)" },
+  { OSPF_OPAQUE_LINK_LSA,  "(Link-Local Opaque-Type/ID)" },
+  { OSPF_OPAQUE_AREA_LSA,  "(Area-Local Opaque-Type/ID)" },
+  { OSPF_OPAQUE_AS_LSA,    "(AS-external Opaque-Type/ID)" },
+};
+int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA;
+
+struct message ospf_redistributed_proto[] =
+{
+  { ZEBRA_ROUTE_SYSTEM,   "System" },
+  { ZEBRA_ROUTE_KERNEL,   "Kernel" },
+  { ZEBRA_ROUTE_CONNECT,  "Connected" },
+  { ZEBRA_ROUTE_STATIC,   "Static" },
+  { ZEBRA_ROUTE_RIP,      "RIP" },
+  { ZEBRA_ROUTE_RIPNG,    "RIPng" },
+  { ZEBRA_ROUTE_OSPF,     "OSPF" },
+  { ZEBRA_ROUTE_OSPF6,    "OSPFv3" },
+  { ZEBRA_ROUTE_BGP,      "BGP" },
+  { ZEBRA_ROUTE_MAX,     "Default" },
+};
+int ospf_redistributed_proto_max = ZEBRA_ROUTE_MAX + 1;
+
+struct message ospf_network_type_msg[] =
+{
+  { OSPF_IFTYPE_NONE,            "NONE" },
+  { OSPF_IFTYPE_POINTOPOINT,      "Point-to-Point" },
+  { OSPF_IFTYPE_BROADCAST,        "Broadcast" },
+  { OSPF_IFTYPE_NBMA,             "NBMA" },
+  { OSPF_IFTYPE_POINTOMULTIPOINT, "Point-to-MultiPoint" },
+  { OSPF_IFTYPE_VIRTUALLINK,      "Virtual-Link" },
+};
+int ospf_network_type_msg_max = OSPF_IFTYPE_MAX;
+
+/* Configuration debug option variables. */
+unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
+unsigned long conf_debug_ospf_event = 0;
+unsigned long conf_debug_ospf_ism = 0;
+unsigned long conf_debug_ospf_nsm = 0;
+unsigned long conf_debug_ospf_lsa = 0;
+unsigned long conf_debug_ospf_zebra = 0;
+unsigned long conf_debug_ospf_nssa = 0;
+
+/* Enable debug option variables -- valid only session. */
+unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
+unsigned long term_debug_ospf_event = 0;
+unsigned long term_debug_ospf_ism = 0;
+unsigned long term_debug_ospf_nsm = 0;
+unsigned long term_debug_ospf_lsa = 0;
+unsigned long term_debug_ospf_zebra = 0;
+unsigned long term_debug_ospf_nssa = 0;
+
+\f
+#define OSPF_AREA_STRING_MAXLEN  16
+char *
+ospf_area_name_string (struct ospf_area *area)
+{
+  static char buf[OSPF_AREA_STRING_MAXLEN] = "";
+  u_int32_t area_id;
+
+  if (!area)
+    return "-";
+
+  area_id = ntohl (area->area_id.s_addr);
+  snprintf (buf, OSPF_AREA_STRING_MAXLEN, "%d.%d.%d.%d",
+            (area_id >> 24) & 0xff, (area_id >> 16) & 0xff,
+            (area_id >> 8) & 0xff, area_id & 0xff);
+  return buf;
+}
+
+#define OSPF_AREA_DESC_STRING_MAXLEN  23
+char *
+ospf_area_desc_string (struct ospf_area *area)
+{
+  static char buf[OSPF_AREA_DESC_STRING_MAXLEN] = "";
+  u_char type;
+
+  if (!area)
+    return "(incomplete)";
+
+  type = area->external_routing;
+  switch (type)
+    {
+    case OSPF_AREA_NSSA:
+      snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [NSSA]",
+                ospf_area_name_string (area));
+      break;
+    case OSPF_AREA_STUB:
+      snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [Stub]",
+                ospf_area_name_string (area));
+      break;
+    default:
+      return ospf_area_name_string (area);
+      break;
+    }
+
+  return buf;
+}
+
+#define OSPF_IF_STRING_MAXLEN  40
+char *
+ospf_if_name_string (struct ospf_interface *oi)
+{
+  static char buf[OSPF_IF_STRING_MAXLEN] = "";
+  u_int32_t ifaddr;
+
+  if (!oi)
+    return "inactive";
+
+  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+    return oi->ifp->name;
+
+  ifaddr = ntohl (oi->address->u.prefix4.s_addr);
+  snprintf (buf, OSPF_IF_STRING_MAXLEN,
+            "%s:%d.%d.%d.%d", oi->ifp->name,
+            (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
+            (ifaddr >> 8) & 0xff, ifaddr & 0xff);
+  return buf;
+}
+
+\f
+void
+ospf_nbr_state_message (struct ospf_neighbor *nbr, char *buf, size_t size)
+{
+  int state;
+  struct ospf_interface *oi = nbr->oi;
+
+  if (IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4))
+    state = ISM_DR;
+  else if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4))
+    state = ISM_Backup;
+  else
+    state = ISM_DROther;
+
+  memset (buf, 0, size);
+
+  snprintf (buf, size, "%s/%s",
+           LOOKUP (ospf_nsm_state_msg, nbr->state),
+           LOOKUP (ospf_ism_state_msg, state));
+}
+
+char *
+ospf_timer_dump (struct thread *t, char *buf, size_t size)
+{
+  struct timeval now;
+  unsigned long h, m, s;
+
+  if (!t)
+    return "inactive";
+
+  h = m = s = 0;
+  memset (buf, 0, size);
+
+  gettimeofday (&now, NULL);
+
+  s = t->u.sands.tv_sec - now.tv_sec;
+  if (s >= 3600)
+    {
+      h = s / 3600;
+      s -= h * 3600;
+    }
+
+  if (s >= 60)
+    {
+      m = s / 60;
+      s -= m * 60;
+    }
+
+  snprintf (buf, size, "%02ld:%02ld:%02ld", h, m, s);
+
+  return buf;
+}
+
+#define OSPF_OPTION_STR_MAXLEN         24
+
+char *
+ospf_options_dump (u_char options)
+{
+  static char buf[OSPF_OPTION_STR_MAXLEN];
+
+  snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*",
+           (options & OSPF_OPTION_O) ? "O" : "-",
+           (options & OSPF_OPTION_DC) ? "DC" : "-",
+           (options & OSPF_OPTION_EA) ? "EA" : "-",
+           (options & OSPF_OPTION_NP) ? "N/P" : "-",
+           (options & OSPF_OPTION_MC) ? "MC" : "-",
+           (options & OSPF_OPTION_E) ? "E" : "-");
+
+  return buf;
+}
+
+void
+ospf_packet_hello_dump (struct stream *s, u_int16_t length)
+{
+  struct ospf_hello *hello;
+  int i;
+
+  hello = (struct ospf_hello *) STREAM_PNT (s);
+
+  zlog_info ("Hello");
+  zlog_info ("  NetworkMask %s", inet_ntoa (hello->network_mask));
+  zlog_info ("  HelloInterval %d", ntohs (hello->hello_interval));
+  zlog_info ("  Options %d (%s)", hello->options,
+            ospf_options_dump (hello->options));
+  zlog_info ("  RtrPriority %d", hello->priority);
+  zlog_info ("  RtrDeadInterval %ld", (u_long)ntohl (hello->dead_interval));
+  zlog_info ("  DRouter %s", inet_ntoa (hello->d_router));
+  zlog_info ("  BDRouter %s", inet_ntoa (hello->bd_router));
+
+  length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE;
+  zlog_info ("  # Neighbors %d", length / 4);
+  for (i = 0; length > 0; i++, length -= sizeof (struct in_addr))
+    zlog_info ("    Neighbor %s", inet_ntoa (hello->neighbors[i]));
+}
+
+char *
+ospf_dd_flags_dump (u_char flags, char *buf, size_t size)
+{
+  memset (buf, 0, size);
+
+  snprintf (buf, size, "%s|%s|%s",
+           (flags & OSPF_DD_FLAG_I) ? "I" : "-",
+           (flags & OSPF_DD_FLAG_M) ? "M" : "-",
+           (flags & OSPF_DD_FLAG_MS) ? "MS" : "-");
+
+  return buf;
+}
+
+void
+ospf_lsa_header_dump (struct lsa_header *lsah)
+{
+  zlog_info ("  LSA Header");
+  zlog_info ("    LS age %d", ntohs (lsah->ls_age));
+  zlog_info ("    Options %d (%s)", lsah->options,
+            ospf_options_dump (lsah->options));
+  zlog_info ("    LS type %d (%s)", lsah->type,
+            LOOKUP (ospf_lsa_type_msg, lsah->type));
+  zlog_info ("    Link State ID %s", inet_ntoa (lsah->id));
+  zlog_info ("    Advertising Router %s", inet_ntoa (lsah->adv_router));
+  zlog_info ("    LS sequence number 0x%lx", (u_long)ntohl (lsah->ls_seqnum));
+  zlog_info ("    LS checksum 0x%x", ntohs (lsah->checksum));
+  zlog_info ("    length %d", ntohs (lsah->length));
+}
+
+char *
+ospf_router_lsa_flags_dump (u_char flags, char *buf, size_t size)
+{
+  memset (buf, 0, size);
+
+  snprintf (buf, size, "%s|%s|%s",
+           (flags & ROUTER_LSA_VIRTUAL) ? "V" : "-",
+           (flags & ROUTER_LSA_EXTERNAL) ? "E" : "-",
+           (flags & ROUTER_LSA_BORDER) ? "B" : "-");
+
+  return buf;
+}
+
+void
+ospf_router_lsa_dump (struct stream *s, u_int16_t length)
+{
+  char buf[BUFSIZ];
+  struct router_lsa *rl;
+  int i, len;
+
+  rl = (struct router_lsa *) STREAM_PNT (s);
+
+  zlog_info ("  Router-LSA");
+  zlog_info ("    flags %s", 
+            ospf_router_lsa_flags_dump (rl->flags, buf, BUFSIZ));
+  zlog_info ("    # links %d", ntohs (rl->links));
+
+  len = ntohs (rl->header.length) - OSPF_LSA_HEADER_SIZE - 4;
+  for (i = 0; len > 0; i++)
+    {
+      zlog_info ("    Link ID %s", inet_ntoa (rl->link[i].link_id));
+      zlog_info ("    Link Data %s", inet_ntoa (rl->link[i].link_data));
+      zlog_info ("    Type %d", (u_char) rl->link[i].type);
+      zlog_info ("    TOS %d", (u_char) rl->link[i].tos);
+      zlog_info ("    metric %d", ntohs (rl->link[i].metric));
+
+      len -= 12;
+    }
+}
+
+void
+ospf_network_lsa_dump (struct stream *s, u_int16_t length)
+{
+  struct network_lsa *nl;
+  int i, cnt;
+
+  nl = (struct network_lsa *) STREAM_PNT (s);
+  cnt = (ntohs (nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4;
+  
+  zlog_info ("  Network-LSA");
+  /*
+  zlog_info ("LSA total size %d", ntohs (nl->header.length));
+  zlog_info ("Network-LSA size %d", 
+  ntohs (nl->header.length) - OSPF_LSA_HEADER_SIZE);
+  */
+  zlog_info ("    Network Mask %s", inet_ntoa (nl->mask));
+  zlog_info ("    # Attached Routers %d", cnt);
+  for (i = 0; i < cnt; i++)
+    zlog_info ("      Attached Router %s", inet_ntoa (nl->routers[i]));
+}
+
+void
+ospf_summary_lsa_dump (struct stream *s, u_int16_t length)
+{
+  struct summary_lsa *sl;
+  int size;
+  int i;
+
+  sl = (struct summary_lsa *) STREAM_PNT (s);
+
+  zlog_info ("  Summary-LSA");
+  zlog_info ("    Network Mask %s", inet_ntoa (sl->mask));
+
+  size = ntohs (sl->header.length) - OSPF_LSA_HEADER_SIZE - 4;
+  for (i = 0; size > 0; size -= 4, i++)
+    zlog_info ("    TOS=%d metric %d", sl->tos,
+              GET_METRIC (sl->metric));
+}
+
+void
+ospf_as_external_lsa_dump (struct stream *s, u_int16_t length)
+{
+  struct as_external_lsa *al;
+  int size;
+  int i;
+
+  al = (struct as_external_lsa *) STREAM_PNT (s);
+
+  zlog_info ("  AS-external-LSA");
+  zlog_info ("    Network Mask %s", inet_ntoa (al->mask));
+
+  size = ntohs (al->header.length) - OSPF_LSA_HEADER_SIZE -4;
+  for (i = 0; size > 0; size -= 12, i++)
+    {
+      zlog_info ("    bit %s TOS=%d metric %d",
+                IS_EXTERNAL_METRIC (al->e[i].tos) ? "E" : "-",
+                al->e[i].tos & 0x7f, GET_METRIC (al->e[i].metric));
+      zlog_info ("    Forwarding address %s", inet_ntoa (al->e[i].fwd_addr));
+      zlog_info ("    External Route Tag %d", al->e[i].route_tag);
+    }
+}
+
+void
+ospf_lsa_header_list_dump (struct stream *s, u_int16_t length)
+{
+  struct lsa_header *lsa;
+
+  zlog_info ("  # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE);
+
+  /* LSA Headers. */
+  while (length > 0)
+    {
+      lsa = (struct lsa_header *) STREAM_PNT (s);
+      ospf_lsa_header_dump (lsa);
+
+      stream_forward (s, OSPF_LSA_HEADER_SIZE);
+      length -= OSPF_LSA_HEADER_SIZE;
+    }
+}
+
+void
+ospf_packet_db_desc_dump (struct stream *s, u_int16_t length)
+{
+  struct ospf_db_desc *dd;
+  char dd_flags[8];
+
+  u_int32_t gp;
+
+  gp = stream_get_getp (s);
+  dd = (struct ospf_db_desc *) STREAM_PNT (s);
+
+  zlog_info ("Database Description");
+  zlog_info ("  Interface MTU %d", ntohs (dd->mtu));
+  zlog_info ("  Options %d (%s)", dd->options,
+            ospf_options_dump (dd->options));
+  zlog_info ("  Flags %d (%s)", dd->flags,
+            ospf_dd_flags_dump (dd->flags, dd_flags, sizeof dd_flags));
+  zlog_info ("  Sequence Number 0x%08lx", (u_long)ntohl (dd->dd_seqnum));
+
+  length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE;
+
+  stream_forward (s, OSPF_DB_DESC_MIN_SIZE);
+
+  ospf_lsa_header_list_dump (s, length);
+
+  stream_set_getp (s, gp);
+}
+
+void
+ospf_packet_ls_req_dump (struct stream *s, u_int16_t length)
+{
+  u_int32_t sp;
+  u_int32_t ls_type;
+  struct in_addr ls_id;
+  struct in_addr adv_router;
+
+  sp = stream_get_getp (s);
+
+  length -= OSPF_HEADER_SIZE;
+
+  zlog_info ("Link State Request");
+  zlog_info ("  # Requests %d", length / 12);
+
+  for (; length > 0; length -= 12)
+    {
+      ls_type = stream_getl (s);
+      ls_id.s_addr = stream_get_ipv4 (s);
+      adv_router.s_addr = stream_get_ipv4 (s);
+
+      zlog_info ("  LS type %d", ls_type);
+      zlog_info ("  Link State ID %s", inet_ntoa (ls_id));
+      zlog_info ("  Advertising Router %s",
+                inet_ntoa (adv_router));
+    }
+
+  stream_set_getp (s, sp);
+}
+
+void
+ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length)
+{
+  u_int32_t sp;
+  struct lsa_header *lsa;
+  int lsa_len;
+  u_int32_t count;
+
+  length -= OSPF_HEADER_SIZE;
+
+  sp = stream_get_getp (s);
+
+  count = stream_getl (s);
+  length -= 4;
+
+  zlog_info ("Link State Update");
+  zlog_info ("  # LSAs %d", count);
+
+  while (length > 0 && count > 0)
+    {
+      if (length < OSPF_HEADER_SIZE || length % 4 != 0)
+       {
+          zlog_info ("  Remaining %d bytes; Incorrect length.", length);
+         break;
+       }
+
+      lsa = (struct lsa_header *) STREAM_PNT (s);
+      lsa_len = ntohs (lsa->length);
+      ospf_lsa_header_dump (lsa);
+
+      switch (lsa->type)
+       {
+       case OSPF_ROUTER_LSA:
+         ospf_router_lsa_dump (s, length);
+         break;
+       case OSPF_NETWORK_LSA:
+         ospf_network_lsa_dump (s, length);
+         break;
+       case OSPF_SUMMARY_LSA:
+       case OSPF_ASBR_SUMMARY_LSA:
+         ospf_summary_lsa_dump (s, length);
+         break;
+       case OSPF_AS_EXTERNAL_LSA:
+         ospf_as_external_lsa_dump (s, length);
+         break;
+#ifdef HAVE_NSSA
+       case OSPF_AS_NSSA_LSA:
+         /* XXX */
+         break;
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+       case OSPF_OPAQUE_LINK_LSA:
+       case OSPF_OPAQUE_AREA_LSA:
+       case OSPF_OPAQUE_AS_LSA:
+         ospf_opaque_lsa_dump (s, length);
+         break;
+#endif /* HAVE_OPAQUE_LSA */
+       default:
+         break;
+       }
+
+      stream_forward (s, lsa_len);
+      length -= lsa_len;
+      count--;
+    }
+
+  stream_set_getp (s, sp);
+}
+
+void
+ospf_packet_ls_ack_dump (struct stream *s, u_int16_t length)
+{
+  u_int32_t sp;
+
+  length -= OSPF_HEADER_SIZE;
+  sp = stream_get_getp (s);
+
+  zlog_info ("Link State Acknowledgment");
+  ospf_lsa_header_list_dump (s, length);
+
+  stream_set_getp (s, sp);
+}
+
+void
+ospf_ip_header_dump (struct stream *s)
+{
+  u_int16_t length;
+  struct ip *iph;
+
+  iph = (struct ip *) STREAM_PNT (s);
+
+#ifdef GNU_LINUX
+  length = ntohs (iph->ip_len);
+#else /* GNU_LINUX */
+  length = iph->ip_len;
+#endif /* GNU_LINUX */
+
+  /* IP Header dump. */
+  zlog_info ("ip_v %d", iph->ip_v);
+  zlog_info ("ip_hl %d", iph->ip_hl);
+  zlog_info ("ip_tos %d", iph->ip_tos);
+  zlog_info ("ip_len %d", length);
+  zlog_info ("ip_id %u", (u_int32_t) iph->ip_id);
+  zlog_info ("ip_off %u", (u_int32_t) iph->ip_off);
+  zlog_info ("ip_ttl %d", iph->ip_ttl);
+  zlog_info ("ip_p %d", iph->ip_p);
+  /* There is a report that Linux 2.0.37 does not have ip_sum.  But
+     I'm not sure.  Temporary commented out by kunihiro. */
+  /* zlog_info ("ip_sum 0x%x", (u_int32_t) ntohs (iph->ip_sum)); */
+  zlog_info ("ip_src %s",  inet_ntoa (iph->ip_src));
+  zlog_info ("ip_dst %s", inet_ntoa (iph->ip_dst));
+}
+
+void
+ospf_header_dump (struct ospf_header *ospfh)
+{
+  char buf[9];
+
+  zlog_info ("Header");
+  zlog_info ("  Version %d", ospfh->version);
+  zlog_info ("  Type %d (%s)", ospfh->type,
+            ospf_packet_type_str[ospfh->type]);
+  zlog_info ("  Packet Len %d", ntohs (ospfh->length));
+  zlog_info ("  Router ID %s", inet_ntoa (ospfh->router_id));
+  zlog_info ("  Area ID %s", inet_ntoa (ospfh->area_id));
+  zlog_info ("  Checksum 0x%x", ntohs (ospfh->checksum));
+  zlog_info ("  AuType %d", ntohs (ospfh->auth_type));
+
+  switch (ntohs (ospfh->auth_type))
+    {
+    case OSPF_AUTH_NULL:
+      break;
+    case OSPF_AUTH_SIMPLE:
+      memset (buf, 0, 9);
+      strncpy (buf, ospfh->u.auth_data, 8);
+      zlog_info ("  Simple Password %s", buf);
+      break;
+    case OSPF_AUTH_CRYPTOGRAPHIC:
+      zlog_info ("  Cryptographic Authentication");
+      zlog_info ("  Key ID %d", ospfh->u.crypt.key_id);
+      zlog_info ("  Auth Data Len %d", ospfh->u.crypt.auth_data_len);
+      zlog_info ("  Sequence number %ld",
+                (u_long)ntohl (ospfh->u.crypt.crypt_seqnum));
+      break;
+    default:
+      zlog_info ("* This is not supported authentication type");
+      break;
+    }
+    
+}
+
+void
+ospf_packet_dump (struct stream *s)
+{
+  struct ospf_header *ospfh;
+  unsigned long gp;
+
+  /* Preserve pointer. */
+  gp = stream_get_getp (s);
+
+  /* OSPF Header dump. */
+  ospfh = (struct ospf_header *) STREAM_PNT (s);
+
+  /* Until detail flag is set, return. */
+  if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL))
+    return;
+
+  /* Show OSPF header detail. */
+  ospf_header_dump (ospfh);
+  stream_forward (s, OSPF_HEADER_SIZE);
+
+  switch (ospfh->type)
+    {
+    case OSPF_MSG_HELLO:
+      ospf_packet_hello_dump (s, ntohs (ospfh->length));
+      break;
+    case OSPF_MSG_DB_DESC:
+      ospf_packet_db_desc_dump (s, ntohs (ospfh->length));
+      break;
+    case OSPF_MSG_LS_REQ:
+      ospf_packet_ls_req_dump (s, ntohs (ospfh->length));
+      break;
+    case OSPF_MSG_LS_UPD:
+      ospf_packet_ls_upd_dump (s, ntohs (ospfh->length));
+      break;
+    case OSPF_MSG_LS_ACK:
+      ospf_packet_ls_ack_dump (s, ntohs (ospfh->length));
+      break;
+    default:
+      break;
+    }
+
+  stream_set_getp (s, gp);
+}
+
+\f
+/*
+   [no] debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)
+                          [send|recv [detail]]
+*/
+DEFUN (debug_ospf_packet,
+       debug_ospf_packet_all_cmd,
+       "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n")
+{
+  int type = 0;
+  int flag = 0;
+  int i;
+
+  assert (argc > 0);
+
+  /* Check packet type. */
+  if (strncmp (argv[0], "h", 1) == 0)
+    type = OSPF_DEBUG_HELLO;
+  else if (strncmp (argv[0], "d", 1) == 0)
+    type = OSPF_DEBUG_DB_DESC;
+  else if (strncmp (argv[0], "ls-r", 4) == 0)
+    type = OSPF_DEBUG_LS_REQ;
+  else if (strncmp (argv[0], "ls-u", 4) == 0)
+    type = OSPF_DEBUG_LS_UPD;
+  else if (strncmp (argv[0], "ls-a", 4) == 0)
+    type = OSPF_DEBUG_LS_ACK;
+  else if (strncmp (argv[0], "a", 1) == 0)
+    type = OSPF_DEBUG_ALL;
+
+  /* Default, both send and recv. */
+  if (argc == 1)
+    flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV;
+
+  /* send or recv. */
+  if (argc >= 2)
+    {
+      if (strncmp (argv[1], "s", 1) == 0)
+       flag = OSPF_DEBUG_SEND;
+      else if (strncmp (argv[1], "r", 1) == 0)
+       flag = OSPF_DEBUG_RECV;
+      else if (strncmp (argv[1], "d", 1) == 0)
+       flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL;
+    }
+
+  /* detail. */
+  if (argc == 3)
+    if (strncmp (argv[2], "d", 1) == 0)
+      flag |= OSPF_DEBUG_DETAIL;
+
+  for (i = 0; i < 5; i++)
+    if (type & (0x01 << i))
+      {
+       if (vty->node == CONFIG_NODE)
+         DEBUG_PACKET_ON (i, flag);
+       else
+         TERM_DEBUG_PACKET_ON (i, flag);
+      }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf_packet,
+       debug_ospf_packet_send_recv_cmd,
+       "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)",
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail information\n")
+
+ALIAS (debug_ospf_packet,
+       debug_ospf_packet_send_recv_detail_cmd,
+       "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)",
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail Information\n")
+       
+
+DEFUN (no_debug_ospf_packet,
+       no_debug_ospf_packet_all_cmd,
+       "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n")
+{
+  int type = 0;
+  int flag = 0;
+  int i;
+
+  assert (argc > 0);
+
+  /* Check packet type. */
+  if (strncmp (argv[0], "h", 1) == 0)
+    type = OSPF_DEBUG_HELLO;
+  else if (strncmp (argv[0], "d", 1) == 0)
+    type = OSPF_DEBUG_DB_DESC;
+  else if (strncmp (argv[0], "ls-r", 4) == 0)
+    type = OSPF_DEBUG_LS_REQ;
+  else if (strncmp (argv[0], "ls-u", 4) == 0)
+    type = OSPF_DEBUG_LS_UPD;
+  else if (strncmp (argv[0], "ls-a", 4) == 0)
+    type = OSPF_DEBUG_LS_ACK;
+  else if (strncmp (argv[0], "a", 1) == 0)
+    type = OSPF_DEBUG_ALL;
+
+  /* Default, both send and recv. */
+  if (argc == 1)
+    flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL ;
+
+  /* send or recv. */
+  if (argc == 2)
+    {
+      if (strncmp (argv[1], "s", 1) == 0)
+       flag = OSPF_DEBUG_SEND | OSPF_DEBUG_DETAIL;
+      else if (strncmp (argv[1], "r", 1) == 0)
+       flag = OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL;
+      else if (strncmp (argv[1], "d", 1) == 0)
+       flag = OSPF_DEBUG_DETAIL;
+    }
+
+  /* detail. */
+  if (argc == 3)
+    if (strncmp (argv[2], "d", 1) == 0)
+      flag = OSPF_DEBUG_DETAIL;
+
+  for (i = 0; i < 5; i++)
+    if (type & (0x01 << i))
+      {
+       if (vty->node == CONFIG_NODE)
+         DEBUG_PACKET_OFF (i, flag);
+       else
+         TERM_DEBUG_PACKET_OFF (i, flag);
+      }
+
+#ifdef DEBUG
+  for (i = 0; i < 5; i++)
+    zlog_info ("flag[%d] = %d", i, ospf_debug_packet[i]);
+#endif /* DEBUG */
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf_packet,
+       no_debug_ospf_packet_send_recv_cmd,
+       "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)",
+       NO_STR
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail Information\n")
+
+ALIAS (no_debug_ospf_packet,
+       no_debug_ospf_packet_send_recv_detail_cmd,
+       "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)",
+       NO_STR
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail Information\n")
+
+\f
+DEFUN (debug_ospf_ism,
+       debug_ospf_ism_cmd,
+       "debug ospf ism",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Interface State Machine\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_ON (ism, ISM);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "s", 1) == 0)
+           DEBUG_ON (ism, ISM_STATUS);
+         else if (strncmp (argv[0], "e", 1) == 0)
+           DEBUG_ON (ism, ISM_EVENTS);
+         else if (strncmp (argv[0], "t", 1) == 0)
+           DEBUG_ON (ism, ISM_TIMERS);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_ON (ism, ISM);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "s", 1) == 0)
+       TERM_DEBUG_ON (ism, ISM_STATUS);
+      else if (strncmp (argv[0], "e", 1) == 0)
+       TERM_DEBUG_ON (ism, ISM_EVENTS);
+      else if (strncmp (argv[0], "t", 1) == 0)
+       TERM_DEBUG_ON (ism, ISM_TIMERS);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf_ism,
+       debug_ospf_ism_sub_cmd,
+       "debug ospf ism (status|events|timers)",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Interface State Machine\n"
+       "ISM Status Information\n"
+       "ISM Event Information\n"
+       "ISM TImer Information\n")
+
+DEFUN (no_debug_ospf_ism,
+       no_debug_ospf_ism_cmd,
+       "no debug ospf ism",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Interface State Machine")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_OFF (ism, ISM);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "s", 1) == 0)
+           DEBUG_OFF (ism, ISM_STATUS);
+         else if (strncmp (argv[0], "e", 1) == 0)
+           DEBUG_OFF (ism, ISM_EVENTS);
+         else if (strncmp (argv[0], "t", 1) == 0)
+           DEBUG_OFF (ism, ISM_TIMERS);
+       }
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_OFF (ism, ISM);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "s", 1) == 0)
+       TERM_DEBUG_OFF (ism, ISM_STATUS);
+      else if (strncmp (argv[0], "e", 1) == 0)
+       TERM_DEBUG_OFF (ism, ISM_EVENTS);
+      else if (strncmp (argv[0], "t", 1) == 0)
+       TERM_DEBUG_OFF (ism, ISM_TIMERS);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf_ism,
+       no_debug_ospf_ism_sub_cmd,
+       "no debug ospf ism (status|events|timers)",
+       NO_STR
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine\n"
+       "ISM Status Information\n"
+       "ISM Event Information\n"
+       "ISM Timer Information\n")
+
+\f
+DEFUN (debug_ospf_nsm,
+       debug_ospf_nsm_cmd,
+       "debug ospf nsm",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Neighbor State Machine\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_ON (nsm, NSM);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "s", 1) == 0)
+           DEBUG_ON (nsm, NSM_STATUS);
+         else if (strncmp (argv[0], "e", 1) == 0)
+           DEBUG_ON (nsm, NSM_EVENTS);
+         else if (strncmp (argv[0], "t", 1) == 0)
+           DEBUG_ON (nsm, NSM_TIMERS);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_ON (nsm, NSM);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "s", 1) == 0)
+       TERM_DEBUG_ON (nsm, NSM_STATUS);
+      else if (strncmp (argv[0], "e", 1) == 0)
+       TERM_DEBUG_ON (nsm, NSM_EVENTS);
+      else if (strncmp (argv[0], "t", 1) == 0)
+       TERM_DEBUG_ON (nsm, NSM_TIMERS);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf_nsm,
+       debug_ospf_nsm_sub_cmd,
+       "debug ospf nsm (status|events|timers)",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Neighbor State Machine\n"
+       "NSM Status Information\n"
+       "NSM Event Information\n"
+       "NSM Timer Information\n")
+
+DEFUN (no_debug_ospf_nsm,
+       no_debug_ospf_nsm_cmd,
+       "no debug ospf nsm",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Neighbor State Machine")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_OFF (nsm, NSM);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "s", 1) == 0)
+           DEBUG_OFF (nsm, NSM_STATUS);
+         else if (strncmp (argv[0], "e", 1) == 0)
+           DEBUG_OFF (nsm, NSM_EVENTS);
+         else if (strncmp (argv[0], "t", 1) == 0)
+           DEBUG_OFF (nsm, NSM_TIMERS);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_OFF (nsm, NSM);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "s", 1) == 0)
+       TERM_DEBUG_OFF (nsm, NSM_STATUS);
+      else if (strncmp (argv[0], "e", 1) == 0)
+       TERM_DEBUG_OFF (nsm, NSM_EVENTS);
+      else if (strncmp (argv[0], "t", 1) == 0)
+       TERM_DEBUG_OFF (nsm, NSM_TIMERS);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf_nsm,
+       no_debug_ospf_nsm_sub_cmd,
+       "no debug ospf nsm (status|events|timers)",
+       NO_STR
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine\n"
+       "NSM Status Information\n"
+       "NSM Event Information\n"
+       "NSM Timer Information\n")
+
+\f
+DEFUN (debug_ospf_lsa,
+       debug_ospf_lsa_cmd,
+       "debug ospf lsa",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Link State Advertisement\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_ON (lsa, LSA);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "g", 1) == 0)
+           DEBUG_ON (lsa, LSA_GENERATE);
+         else if (strncmp (argv[0], "f", 1) == 0)
+           DEBUG_ON (lsa, LSA_FLOODING);
+         else if (strncmp (argv[0], "i", 1) == 0)
+           DEBUG_ON (lsa, LSA_INSTALL);
+         else if (strncmp (argv[0], "r", 1) == 0)
+           DEBUG_ON (lsa, LSA_REFRESH);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_ON (lsa, LSA);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "g", 1) == 0)
+       TERM_DEBUG_ON (lsa, LSA_GENERATE);
+      else if (strncmp (argv[0], "f", 1) == 0)
+       TERM_DEBUG_ON (lsa, LSA_FLOODING);
+      else if (strncmp (argv[0], "i", 1) == 0)
+       TERM_DEBUG_ON (lsa, LSA_INSTALL);
+      else if (strncmp (argv[0], "r", 1) == 0)
+       TERM_DEBUG_ON (lsa, LSA_REFRESH);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf_lsa,
+       debug_ospf_lsa_sub_cmd,
+       "debug ospf lsa (generate|flooding|install|refresh)",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Link State Advertisement\n"
+       "LSA Generation\n"
+       "LSA Flooding\n"
+       "LSA Install/Delete\n"
+       "LSA Refresh\n")
+
+DEFUN (no_debug_ospf_lsa,
+       no_debug_ospf_lsa_cmd,
+       "no debug ospf lsa",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Link State Advertisement\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_OFF (lsa, LSA);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "g", 1) == 0)
+           DEBUG_OFF (lsa, LSA_GENERATE);
+         else if (strncmp (argv[0], "f", 1) == 0)
+           DEBUG_OFF (lsa, LSA_FLOODING);
+         else if (strncmp (argv[0], "i", 1) == 0)
+           DEBUG_OFF (lsa, LSA_INSTALL);
+         else if (strncmp (argv[0], "r", 1) == 0)
+           DEBUG_OFF (lsa, LSA_REFRESH);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_OFF (lsa, LSA);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "g", 1) == 0)
+       TERM_DEBUG_OFF (lsa, LSA_GENERATE);
+      else if (strncmp (argv[0], "f", 1) == 0)
+       TERM_DEBUG_OFF (lsa, LSA_FLOODING);
+      else if (strncmp (argv[0], "i", 1) == 0)
+       TERM_DEBUG_OFF (lsa, LSA_INSTALL);
+      else if (strncmp (argv[0], "r", 1) == 0)
+       TERM_DEBUG_OFF (lsa, LSA_REFRESH);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf_lsa,
+       no_debug_ospf_lsa_sub_cmd,
+       "no debug ospf lsa (generate|flooding|install|refresh)",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Link State Advertisement\n"
+       "LSA Generation\n"
+       "LSA Flooding\n"
+       "LSA Install/Delete\n"
+       "LSA Refres\n")
+
+\f
+DEFUN (debug_ospf_zebra,
+       debug_ospf_zebra_cmd,
+       "debug ospf zebra",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Zebra information\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_ON (zebra, ZEBRA);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "i", 1) == 0)
+           DEBUG_ON (zebra, ZEBRA_INTERFACE);
+         else if (strncmp (argv[0], "r", 1) == 0)
+           DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_ON (zebra, ZEBRA);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "i", 1) == 0)
+       TERM_DEBUG_ON (zebra, ZEBRA_INTERFACE);
+      else if (strncmp (argv[0], "r", 1) == 0)
+       TERM_DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf_zebra,
+       debug_ospf_zebra_sub_cmd,
+       "debug ospf zebra (interface|redistribute)",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Zebra information\n"
+       "Zebra interface\n"
+       "Zebra redistribute\n")
+
+DEFUN (no_debug_ospf_zebra,
+       no_debug_ospf_zebra_cmd,
+       "no debug ospf zebra",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Zebra information\n")
+{
+  if (vty->node == CONFIG_NODE)
+    {
+      if (argc == 0)
+       DEBUG_OFF (zebra, ZEBRA);
+      else if (argc == 1)
+       {
+         if (strncmp (argv[0], "i", 1) == 0)
+           DEBUG_OFF (zebra, ZEBRA_INTERFACE);
+         else if (strncmp (argv[0], "r", 1) == 0)
+           DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE);
+       }
+
+      return CMD_SUCCESS;
+    }
+
+  /* ENABLE_NODE. */
+  if (argc == 0)
+    TERM_DEBUG_OFF (zebra, ZEBRA);
+  else if (argc == 1)
+    {
+      if (strncmp (argv[0], "i", 1) == 0)
+       TERM_DEBUG_OFF (zebra, ZEBRA_INTERFACE);
+      else if (strncmp (argv[0], "r", 1) == 0)
+       TERM_DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf_zebra,
+       no_debug_ospf_zebra_sub_cmd,
+       "no debug ospf zebra (interface|redistribute)",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF Zebra information\n"
+       "Zebra interface\n"
+       "Zebra redistribute\n")
+\f
+DEFUN (debug_ospf_event,
+       debug_ospf_event_cmd,
+       "debug ospf event",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF event information\n")
+{
+  if (vty->node == CONFIG_NODE)
+    CONF_DEBUG_ON (event, EVENT);
+  TERM_DEBUG_ON (event, EVENT);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf_event,
+       no_debug_ospf_event_cmd,
+       "no debug ospf event",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF event information\n")
+{
+  if (vty->node == CONFIG_NODE)
+    CONF_DEBUG_OFF (event, EVENT);
+  TERM_DEBUG_OFF (event, EVENT);
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ospf_nssa,
+       debug_ospf_nssa_cmd,
+       "debug ospf nssa",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF nssa information\n")
+{
+  if (vty->node == CONFIG_NODE)
+    CONF_DEBUG_ON (nssa, NSSA);
+  TERM_DEBUG_ON (nssa, NSSA);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf_nssa,
+       no_debug_ospf_nssa_cmd,
+       "no debug ospf nssa",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF nssa information\n")
+{
+  if (vty->node == CONFIG_NODE)
+    CONF_DEBUG_OFF (nssa, NSSA);
+  TERM_DEBUG_OFF (nssa, NSSA);
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (show_debugging_ospf,
+       show_debugging_ospf_cmd,
+       "show debugging ospf",
+       SHOW_STR
+       DEBUG_STR
+       OSPF_STR)
+{
+  int i;
+
+  vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+  /* Show debug status for ISM. */
+  if (IS_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM)
+    vty_out (vty, "  OSPF ISM debugging is on%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_DEBUG_OSPF (ism, ISM_STATUS))
+       vty_out (vty, "  OSPF ISM status debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
+       vty_out (vty, "  OSPF ISM event debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (ism, ISM_TIMERS))
+       vty_out (vty, "  OSPF ISM timer debugging is on%s", VTY_NEWLINE);
+    }
+
+  /* Show debug status for NSM. */
+  if (IS_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM)
+    vty_out (vty, "  OSPF NSM debugging is on%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
+       vty_out (vty, "  OSPF NSM status debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
+       vty_out (vty, "  OSPF NSM event debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
+       vty_out (vty, "  OSPF NSM timer debugging is on%s", VTY_NEWLINE);
+    }
+
+  /* Show debug status for OSPF Packets. */
+  for (i = 0; i < 5; i++)
+    if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV))
+      {
+       vty_out (vty, "  OSPF packet %s%s debugging is on%s",
+                ospf_packet_type_str[i + 1],
+                IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "",
+                VTY_NEWLINE);
+      }
+    else
+      {
+       if (IS_DEBUG_OSPF_PACKET (i, SEND))
+         vty_out (vty, "  OSPF packet %s send%s debugging is on%s",
+                  ospf_packet_type_str[i + 1],
+                  IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "",
+                  VTY_NEWLINE);
+       if (IS_DEBUG_OSPF_PACKET (i, RECV))
+         vty_out (vty, "  OSPF packet %s receive%s debugging is on%s",
+                  ospf_packet_type_str[i + 1],
+                  IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "",
+                  VTY_NEWLINE);
+      }
+
+  /* Show debug status for OSPF LSAs. */
+  if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+    vty_out (vty, "  OSPF LSA debugging is on%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+       vty_out (vty, "  OSPF LSA generation debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+       vty_out (vty, "  OSPF LSA flooding debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+       vty_out (vty, "  OSPF LSA install debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+       vty_out (vty, "  OSPF LSA refresh debugging is on%s", VTY_NEWLINE);
+    }
+
+  /* Show debug status for Zebra. */
+  if (IS_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA)
+    vty_out (vty, "  OSPF Zebra debugging is on%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+       vty_out (vty, "  OSPF Zebra interface debugging is on%s", VTY_NEWLINE);
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+       vty_out (vty, "  OSPF Zebra redistribute debugging is on%s", VTY_NEWLINE);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  ""
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+  int write = 0;
+  int i, r;
+
+  char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"};
+  char *detail_str[] = {"", " send", " recv", "", " detail",
+                       " send detail", " recv detail", " detail"};
+
+  /* debug ospf ism (status|events|timers). */
+  if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM)
+    vty_out (vty, "debug ospf ism%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS))
+       vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS))
+       vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS))
+       vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE);
+    }
+
+  /* debug ospf nsm (status|events|timers). */
+  if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM)
+    vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS))
+       vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS))
+       vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS))
+       vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE);
+    }
+
+  /* debug ospf lsa (generate|flooding|install|refresh). */
+  if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+    vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE))
+       vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING))
+       vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL))
+       vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH))
+       vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE);
+
+      write = 1;
+    }
+
+  /* debug ospf zebra (interface|redistribute). */
+  if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA)
+    vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+       vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE);
+      if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+       vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE);
+
+      write = 1;
+    }
+
+  /* debug ospf event. */
+  if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT)
+    {
+      vty_out (vty, "debug ospf event%s", VTY_NEWLINE);
+      write = 1;
+    }
+
+  /* debug ospf nssa. */
+  if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA)
+    {
+      vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE);
+      write = 1;
+    }
+  
+  /* debug ospf packet all detail. */
+  r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL;
+  for (i = 0; i < 5; i++)
+    r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL);
+  if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL))
+    {
+      vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE);
+      return 1;
+    }
+
+  /* debug ospf packet all. */
+  r = OSPF_DEBUG_SEND_RECV;
+  for (i = 0; i < 5; i++)
+    r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV;
+  if (r == OSPF_DEBUG_SEND_RECV)
+    {
+      vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE);
+      for (i = 0; i < 5; i++)
+       if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL)
+         vty_out (vty, "debug ospf packet %s detail%s",
+                  type_str[i],
+                  VTY_NEWLINE);
+      return 1;
+    }
+
+  /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack)
+     (send|recv) (detail). */
+  for (i = 0; i < 5; i++)
+    {
+      if (conf_debug_ospf_packet[i] == 0)
+       continue;
+      
+      vty_out (vty, "debug ospf packet %s%s%s",
+              type_str[i], detail_str[conf_debug_ospf_packet[i]],
+              VTY_NEWLINE);
+      write = 1;
+    }
+
+  return write;
+}
+
+/* Initialize debug commands. */
+void
+debug_init ()
+{
+  install_node (&debug_node, config_write_debug);
+
+  install_element (ENABLE_NODE, &show_debugging_ospf_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_ism_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_nsm_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_lsa_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_zebra_cmd);
+  install_element (ENABLE_NODE, &debug_ospf_event_cmd);
+#ifdef HAVE_NSSA
+  install_element (ENABLE_NODE, &debug_ospf_nssa_cmd);
+#endif /* HAVE_NSSA */
+  install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf_event_cmd);
+#ifdef HAVE_NSSA
+  install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd);
+#endif /* HAVE_NSSA */
+
+  install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_ism_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_nsm_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_lsa_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_zebra_cmd);
+  install_element (CONFIG_NODE, &debug_ospf_event_cmd);
+#ifdef HAVE_NSSA
+  install_element (CONFIG_NODE, &debug_ospf_nssa_cmd);
+#endif /* HAVE_NSSA */
+  install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf_event_cmd);
+#ifdef HAVE_NSSA
+  install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd);
+#endif /* HAVE_NSSA */
+}
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
new file mode 100644 (file)
index 0000000..804d5f7
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * OSPFd dump routine.
+ * Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#ifndef _ZEBRA_OSPF_DUMP_H
+#define _ZEBRA_OSPF_DUMP_H
+
+/* Debug Flags. */
+#define OSPF_DEBUG_HELLO       0x01
+#define OSPF_DEBUG_DB_DESC     0x02
+#define OSPF_DEBUG_LS_REQ      0x04
+#define OSPF_DEBUG_LS_UPD      0x08
+#define OSPF_DEBUG_LS_ACK      0x10
+#define OSPF_DEBUG_ALL         0x1f
+
+#define OSPF_DEBUG_SEND                0x01
+#define OSPF_DEBUG_RECV                0x02
+#define OSPF_DEBUG_SEND_RECV    0x03
+#define OSPF_DEBUG_DETAIL      0x04
+
+#define OSPF_DEBUG_ISM_STATUS  0x01
+#define OSPF_DEBUG_ISM_EVENTS  0x02
+#define OSPF_DEBUG_ISM_TIMERS  0x04
+#define OSPF_DEBUG_ISM         0x07
+#define OSPF_DEBUG_NSM_STATUS  0x01
+#define OSPF_DEBUG_NSM_EVENTS  0x02
+#define OSPF_DEBUG_NSM_TIMERS   0x04
+#define OSPF_DEBUG_NSM         0x07
+
+#define OSPF_DEBUG_LSA_GENERATE 0x01
+#define OSPF_DEBUG_LSA_FLOODING        0x02
+#define OSPF_DEBUG_LSA_INSTALL  0x04
+#define OSPF_DEBUG_LSA_REFRESH  0x08
+#define OSPF_DEBUG_LSA         0x0F
+
+#define OSPF_DEBUG_ZEBRA_INTERFACE     0x01
+#define OSPF_DEBUG_ZEBRA_REDISTRIBUTE  0x02
+#define OSPF_DEBUG_ZEBRA              0x03
+
+#define OSPF_DEBUG_EVENT        0x01
+#define OSPF_DEBUG_NSSA                0x02
+
+/* Macro for setting debug option. */
+#define CONF_DEBUG_PACKET_ON(a, b)         conf_debug_ospf_packet[a] |= (b)
+#define CONF_DEBUG_PACKET_OFF(a, b)        conf_debug_ospf_packet[a] &= ~(b)
+#define TERM_DEBUG_PACKET_ON(a, b)         term_debug_ospf_packet[a] |= (b)
+#define TERM_DEBUG_PACKET_OFF(a, b)        term_debug_ospf_packet[a] &= ~(b)
+#define DEBUG_PACKET_ON(a, b) \
+    do { \
+      CONF_DEBUG_PACKET_ON(a, b); \
+      TERM_DEBUG_PACKET_ON(a, b); \
+    } while (0)
+#define DEBUG_PACKET_OFF(a, b) \
+    do { \
+      CONF_DEBUG_PACKET_OFF(a, b); \
+      TERM_DEBUG_PACKET_OFF(a, b); \
+    } while (0)
+
+#define CONF_DEBUG_ON(a, b)     conf_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b)
+#define CONF_DEBUG_OFF(a, b)    conf_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b)
+#define TERM_DEBUG_ON(a, b)     term_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b)
+#define TERM_DEBUG_OFF(a, b)    term_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b)
+#define DEBUG_ON(a, b) \
+     do { \
+       CONF_DEBUG_ON(a, b); \
+       TERM_DEBUG_ON(a, b); \
+     } while (0)
+#define DEBUG_OFF(a, b) \
+     do { \
+       CONF_DEBUG_OFF(a, b); \
+       TERM_DEBUG_OFF(a, b); \
+     } while (0)
+
+/* Macro for checking debug option. */
+#define IS_DEBUG_OSPF_PACKET(a, b) \
+       (term_debug_ospf_packet[a] & OSPF_DEBUG_ ## b)
+#define IS_DEBUG_OSPF(a, b) \
+       (term_debug_ospf_ ## a & OSPF_DEBUG_ ## b)
+#define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event,EVENT)
+
+#define IS_DEBUG_OSPF_NSSA  IS_DEBUG_OSPF(event,NSSA)
+
+#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \
+       (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b)
+#define IS_CONF_DEBUG_OSPF(a, b) \
+       (conf_debug_ospf_ ## a & OSPF_DEBUG_ ## b)
+
+#ifdef ORIGINAL_CODING
+#else /* ORIGINAL_CODING */
+struct stream;
+#endif /* ORIGINAL_CODING */
+
+#define AREA_NAME(A)    ospf_area_name_string ((A))
+#define IF_NAME(I)      ospf_if_name_string ((I))
+
+/* Extern debug flag. */
+extern unsigned long term_debug_ospf_packet[];
+extern unsigned long term_debug_ospf_event;
+extern unsigned long term_debug_ospf_ism;
+extern unsigned long term_debug_ospf_nsm;
+extern unsigned long term_debug_ospf_lsa;
+extern unsigned long term_debug_ospf_zebra;
+extern unsigned long term_debug_ospf_nssa;
+
+/* Message Strings. */
+extern char *ospf_packet_type_str[];
+extern char *ospf_lsa_type_str[];
+
+/* Prototypes. */
+char *ospf_area_name_string (struct ospf_area *);
+char *ospf_area_desc_string (struct ospf_area *);
+char *ospf_if_name_string (struct ospf_interface *);
+void ospf_nbr_state_message (struct ospf_neighbor *, char *, size_t);
+char *ospf_options_dump (u_char);
+char *ospf_timer_dump (struct thread *, char *, size_t);
+void ospf_ip_header_dump (struct stream *);
+void ospf_packet_dump (struct stream *);
+void ospf_lsa_header_dump (struct lsa_header *);
+void debug_init ();
+
+#endif /* _ZEBRA_OSPF_DUMP_H */
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
new file mode 100644 (file)
index 0000000..bd33c34
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * OSPF Flooding -- RFC2328 Section 13.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "command.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+extern struct zclient *zclient;
+\f
+/* Do the LSA acking specified in table 19, Section 13.5, row 2
+ * This get called from ospf_flood_out_interface. Declared inline 
+ * for speed. */
+static void
+ospf_flood_delayed_lsa_ack (struct ospf_neighbor *inbr, struct ospf_lsa *lsa)
+{
+  /* LSA is more recent than database copy, but was not
+     flooded back out receiving interface.  Delayed
+     acknowledgment sent. If interface is in Backup state
+     delayed acknowledgment sent only if advertisement
+     received from Designated Router, otherwise do nothing See
+     RFC 2328 Section 13.5 */
+
+  /* Whether LSA is more recent or not, and whether this is in
+     response to the LSA being sent out recieving interface has been 
+     worked out previously */
+
+  /* Deal with router as BDR */
+  if (inbr->oi->state == ISM_Backup && ! NBR_IS_DR (inbr))
+    return;
+
+  /* Schedule a delayed LSA Ack to be sent */ 
+  listnode_add (inbr->oi->ls_ack, ospf_lsa_lock (lsa));
+}
+
+/* Check LSA is related to external info. */
+struct external_info *
+ospf_external_info_check (struct ospf_lsa *lsa)
+{
+  struct as_external_lsa *al;
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  int type;
+
+  al = (struct as_external_lsa *) lsa->data;
+
+  p.family = AF_INET;
+  p.prefix = lsa->data->id;
+  p.prefixlen = ip_masklen (al->mask);
+
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    {
+      int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type;
+      if (ospf_is_type_redistributed (redist_type))
+       if (EXTERNAL_INFO (type))
+         {
+           rn = route_node_lookup (EXTERNAL_INFO (type),
+                                   (struct prefix *) &p);
+           if (rn)
+             {
+               route_unlock_node (rn);
+               if (rn->info != NULL)
+                 return (struct external_info *) rn->info;
+             }
+         }
+    }
+
+  return NULL;
+}
+
+void
+ospf_process_self_originated_lsa (struct ospf_lsa *new, struct ospf_area *area)
+{
+  struct ospf_interface *oi;
+  struct external_info *ei;
+  listnode node;
+  
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("LSA[Type%d:%s]: Process self-originated LSA",
+              new->data->type, inet_ntoa (new->data->id));
+
+  /* If we're here, we installed a self-originated LSA that we received
+     from a neighbor, i.e. it's more recent.  We must see whether we want
+     to originate it.
+     If yes, we should use this LSA's sequence number and reoriginate
+     a new instance.
+     if not --- we must flush this LSA from the domain. */
+  switch (new->data->type)
+    {
+    case OSPF_ROUTER_LSA:
+      /* Originate a new instance and schedule flooding */
+      /* It shouldn't be necessary, but anyway */
+      ospf_lsa_unlock (area->router_lsa_self);
+      area->router_lsa_self = ospf_lsa_lock (new);
+
+      ospf_router_lsa_timer_add (area);
+      return;
+    case OSPF_NETWORK_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      /* We must find the interface the LSA could belong to.
+        If the interface is no more a broadcast type or we are no more
+        the DR, we flush the LSA otherwise -- create the new instance and
+        schedule flooding. */
+
+      /* Look through all interfaces, not just area, since interface
+        could be moved from one area to another. */
+      for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+       /* These are sanity check. */
+       if ((oi = getdata (node)) != NULL)
+         if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &new->data->id))
+           {
+             if (oi->area != area ||
+                 oi->type != OSPF_IFTYPE_BROADCAST ||
+                 !IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)))
+               {
+                 ospf_schedule_lsa_flush_area (area, new);
+                 return;
+               }
+             
+#ifdef HAVE_OPAQUE_LSA
+              if (new->data->type == OSPF_OPAQUE_LINK_LSA)
+                {
+                  ospf_opaque_lsa_refresh (new);
+                  return;
+                }
+#endif /* HAVE_OPAQUE_LSA */
+
+             ospf_lsa_unlock (oi->network_lsa_self);
+             oi->network_lsa_self = ospf_lsa_lock (new);
+             
+             /* Schedule network-LSA origination. */
+             ospf_network_lsa_timer_add (oi);
+             return;
+           }
+      break;
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+      ospf_schedule_abr_task ();
+      break;
+    case OSPF_AS_EXTERNAL_LSA :
+#ifdef HAVE_NSSA
+    case OSPF_AS_NSSA_LSA:
+#endif /* HAVE_NSSA */
+      ei = ospf_external_info_check (new);
+      if (ei)
+       ospf_external_lsa_refresh (new, ei, LSA_REFRESH_FORCE);
+      else
+       ospf_lsa_flush_as (new);
+      break;
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AREA_LSA:
+      ospf_opaque_lsa_refresh (new);
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default:
+      break;
+    }
+}
+
+/* OSPF LSA flooding -- RFC2328 Section 13.(5). */
+
+/* Now Updated for NSSA operation, as follows:
+
+
+       Type-5's have no change.  Blocked to STUB or NSSA.
+
+       Type-7's can be received, and if a DR
+       they will also flood the local NSSA Area as Type-7's
+
+       If a Self-Originated LSA (now an ASBR), 
+       The LSDB will be updated as Type-5's, (for continual re-fresh)
+
+           If an NSSA-IR it is installed/flooded as Type-7, P-bit on.
+           if an NSSA-ABR it is installed/flooded as Type-7, P-bit off.
+
+       Later, during the ABR TASK, if the ABR is the Elected NSSA
+       translator, then All Type-7s (with P-bit ON) are Translated to
+       Type-5's and flooded to all non-NSSA/STUB areas.
+
+       During ASE Calculations, 
+           non-ABRs calculate external routes from Type-7's
+           ABRs calculate external routes from Type-5's and non-self Type-7s
+*/
+int
+ospf_flood (struct ospf_neighbor *nbr, struct ospf_lsa *current,
+           struct ospf_lsa *new)
+{
+  struct ospf_interface *oi;
+  struct timeval now;
+  int lsa_ack_flag;
+
+  /* Type-7 LSA's will be flooded throughout their native NSSA area,
+     but will also be flooded as Type-5's into ABR capable links.  */
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]",
+               inet_ntoa (nbr->router_id),
+               LOOKUP (ospf_nsm_state_msg, nbr->state),
+               current,
+               dump_lsa_key (new));
+
+  lsa_ack_flag = 0;
+  oi = nbr->oi;
+
+  /* Get current time. */
+  gettimeofday (&now, NULL);
+
+  /* If there is already a database copy, and if the
+     database copy was received via flooding and installed less
+     than MinLSArrival seconds ago, discard the new LSA
+     (without acknowledging it). */
+  if (current != NULL)         /* -- endo. */
+    {
+      if (IS_LSA_SELF (current)
+      && (ntohs (current->data->ls_age)    == 0
+      &&  ntohl (current->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER))
+        {
+          if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("LSA[Flooding]: Got a self-originated LSA, "
+                      "while local one is initial instance.");
+          ; /* Accept this LSA for quick LSDB resynchronization. */
+        }
+      else if (tv_cmp (tv_sub (now, current->tv_recv),
+                      int2tv (OSPF_MIN_LS_ARRIVAL)) < 0)
+        {
+          if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("LSA[Flooding]: LSA is received recently.");
+          return -1;
+        }
+    }
+
+  /* Flood the new LSA out some subset of the router's interfaces.
+     In some cases (e.g., the state of the receiving interface is
+     DR and the LSA was received from a router other than the
+     Backup DR) the LSA will be flooded back out the receiving
+     interface. */
+  lsa_ack_flag = ospf_flood_through (nbr, new);
+
+#ifdef HAVE_OPAQUE_LSA
+  /* Remove the current database copy from all neighbors' Link state
+     retransmission lists.  AS_EXTERNAL and AS_EXTERNAL_OPAQUE does
+                                        ^^^^^^^^^^^^^^^^^^^^^^^
+     not have area ID.
+     All other (even NSSA's) do have area ID.  */
+#else /* HAVE_OPAQUE_LSA */
+  /* Remove the current database copy from all neighbors' Link state
+     retransmission lists.  Only AS_EXTERNAL does not have area ID.
+     All other (even NSSA's) do have area ID.  */
+#endif /* HAVE_OPAQUE_LSA */
+  if (current)
+    {
+      switch (current->data->type)
+        {
+        case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+        case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+          ospf_ls_retransmit_delete_nbr_all (NULL, current);
+          break;
+        default:
+          ospf_ls_retransmit_delete_nbr_all (nbr->oi->area, current);
+          break;
+        }
+    }
+
+  /* Do some internal house keeping that is needed here */
+  SET_FLAG (new->flags, OSPF_LSA_RECEIVED);
+  ospf_lsa_is_self_originated (new); /* Let it set the flag */
+
+  /* Install the new LSA in the link state database
+     (replacing the current database copy).  This may cause the
+     routing table calculation to be scheduled.  In addition,
+     timestamp the new LSA with the current time.  The flooding
+     procedure cannot overwrite the newly installed LSA until
+     MinLSArrival seconds have elapsed. */  
+
+  new = ospf_lsa_install (nbr->oi, new);
+
+#ifdef HAVE_NSSA 
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("LSA[Flooding]: Type-%d installed", new->data->type);
+
+  /* if  (new->data->type == OSPF_AS_NSSA_LSA )
+     return 0;  */
+#endif /* HAVE_NSSA */
+
+  /* Acknowledge the receipt of the LSA by sending a Link State
+     Acknowledgment packet back out the receiving interface. */
+  if (lsa_ack_flag)
+    ospf_flood_delayed_lsa_ack (nbr, new);     
+
+  /* If this new LSA indicates that it was originated by the
+     receiving router itself, the router must take special action,
+     either updating the LSA or in some cases flushing it from
+     the routing domain. */
+  if (ospf_lsa_is_self_originated (new))
+    ospf_process_self_originated_lsa (new, oi->area);
+  else
+    /* Update statistics value for OSPF-MIB. */
+    ospf_top->rx_lsa_count++;
+
+  return 0;
+}
+
+/* OSPF LSA flooding -- RFC2328 Section 13.3. */
+int
+ospf_flood_through_interface (struct ospf_interface *oi,
+                             struct ospf_neighbor *inbr,
+                             struct ospf_lsa *lsa)
+{
+  struct ospf_neighbor *onbr;
+  struct route_node *rn;
+  int retx_flag;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_flood_through_interface(): "
+              "considering int %s, INBR(%s), LSA[%s]",
+              IF_NAME (oi), inbr ? inet_ntoa (inbr->router_id) : "NULL",
+               dump_lsa_key (lsa));
+
+  if (!ospf_if_is_enable (oi))
+    return 0;
+
+  /* Remember if new LSA is aded to a retransmit list. */
+  retx_flag = 0;
+
+  /* Each of the neighbors attached to this interface are examined,
+     to determine whether they must receive the new LSA.  The following
+     steps are executed for each neighbor: */
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    {
+      struct ospf_lsa *ls_req;
+      if (rn->info == NULL)
+       continue;
+
+      onbr = rn->info;
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_flood_through_interface(): considering nbr %s (%s)",
+                  inet_ntoa (onbr->router_id),
+                   LOOKUP (ospf_nsm_state_msg, onbr->state));
+
+      /* If the neighbor is in a lesser state than Exchange, it
+        does not participate in flooding, and the next neighbor
+        should be examined. */
+      if (onbr->state < NSM_Exchange)
+       continue;
+
+      /* If the adjacency is not yet full (neighbor state is
+        Exchange or Loading), examine the Link state request
+        list associated with this adjacency.  If there is an
+        instance of the new LSA on the list, it indicates that
+        the neighboring router has an instance of the LSA
+        already.  Compare the new LSA to the neighbor's copy: */
+      if (onbr->state < NSM_Full)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_flood_through_interface(): nbr adj is not Full");
+         ls_req = ospf_ls_request_lookup (onbr, lsa);
+         if (ls_req != NULL)
+           {
+             int ret;
+
+             ret = ospf_lsa_more_recent (ls_req, lsa);
+             /* The new LSA is less recent. */
+             if (ret > 0)
+               continue;
+             /* The two copies are the same instance, then delete
+                the LSA from the Link state request list. */
+             else if (ret == 0)
+               {
+                 ospf_ls_request_delete (onbr, ls_req);
+                 ospf_check_nbr_loading (onbr);
+                 continue;
+               }
+             /* The new LSA is more recent.  Delete the LSA
+                from the Link state request list. */
+             else
+               {
+                 ospf_ls_request_delete (onbr, ls_req);
+                 ospf_check_nbr_loading (onbr);
+               }
+           }
+       }
+
+#ifdef HAVE_OPAQUE_LSA
+      if (IS_OPAQUE_LSA (lsa->data->type))
+        {
+          if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O))
+            {
+              if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+                zlog_info ("Skip this neighbor: Not Opaque-capable.");
+              continue;
+            }
+
+          if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf_top->opaque)
+          &&  IS_LSA_SELF (lsa)
+          &&  onbr->state == NSM_Full)
+            {
+              /* Small attempt to reduce unnecessary retransmission. */
+              if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+                zlog_info ("Skip this neighbor: Initial flushing done.");
+              continue;
+            }
+        }
+#endif /* HAVE_OPAQUE_LSA */
+
+      /* If the new LSA was received from this neighbor,
+        examine the next neighbor. */
+#ifdef ORIGINAL_CODING
+      if (inbr)
+       if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id))
+         continue;
+#else /* ORIGINAL_CODING */
+      if (inbr)
+        {
+          /*
+           * Triggered by LSUpd message parser "ospf_ls_upd ()".
+           * E.g., all LSAs handling here is received via network.
+           */
+          if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id))
+            {
+              if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+                zlog_info ("Skip this neighbor: inbr == onbr");
+              continue;
+            }
+        }
+      else
+        {
+          /*
+           * Triggered by MaxAge remover, so far.
+           * NULL "inbr" means flooding starts from this node.
+           */
+          if (IPV4_ADDR_SAME (&lsa->data->adv_router, &onbr->router_id))
+            {
+              if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+                zlog_info ("Skip this neighbor: lsah->adv_router == onbr");
+              continue;
+            }
+        }
+#endif /* ORIGINAL_CODING */
+
+      /* Add the new LSA to the Link state retransmission list
+        for the adjacency. The LSA will be retransmitted
+        at intervals until an acknowledgment is seen from
+        the neighbor. */
+      ospf_ls_retransmit_add (onbr, lsa);
+      retx_flag = 1;
+    }
+
+  /* If in the previous step, the LSA was NOT added to any of
+     the Link state retransmission lists, there is no need to
+     flood the LSA out the interface. */
+  if (retx_flag == 0) 
+    {
+      return (inbr && inbr->oi == oi);
+    }
+
+  /* if we've received the lsa on this interface we need to perform
+     additional checking */
+  if (inbr && (inbr->oi == oi))
+    {
+      /* If the new LSA was received on this interface, and it was
+        received from either the Designated Router or the Backup
+        Designated Router, chances are that all the neighbors have
+        received the LSA already. */
+      if (NBR_IS_DR (inbr) || NBR_IS_BDR (inbr))
+       {
+#ifdef HAVE_NSSA
+         if (IS_DEBUG_OSPF_NSSA)
+           zlog_info ("ospf_flood_through_interface(): "
+                      "DR/BDR NOT SEND to int %s", IF_NAME (oi));
+#endif /* HAVE_NSSA */
+         return 1;
+       }
+         
+      /* If the new LSA was received on this interface, and the
+        interface state is Backup, examine the next interface.  The
+        Designated Router will do the flooding on this interface.
+        However, if the Designated Router fails the router will
+        end up retransmitting the updates. */
+
+      if (oi->state == ISM_Backup)
+       {
+#ifdef HAVE_NSSA
+         if (IS_DEBUG_OSPF_NSSA)
+           zlog_info ("ospf_flood_through_interface(): "
+                      "ISM_Backup NOT SEND to int %s", IF_NAME (oi));
+#endif /* HAVE_NSSA */
+         return 1;
+       }
+    }
+
+  /* The LSA must be flooded out the interface. Send a Link State
+     Update packet (including the new LSA as contents) out the
+     interface.  The LSA's LS age must be incremented by InfTransDelay
+     (which    must be > 0) when it is copied into the outgoing Link
+     State Update packet (until the LS age field reaches the maximum
+     value of MaxAge). */
+
+#ifdef HAVE_NSSA
+  if (IS_DEBUG_OSPF_NSSA)
+    zlog_info ("ospf_flood_through_interface(): "
+              "DR/BDR sending upd to int %s", IF_NAME (oi));
+#else /* ! HAVE_NSSA */
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_flood_through_interface(): "
+              "sending upd to int %s", IF_NAME (oi));
+#endif /* HAVE_NSSA */
+
+  /*  RFC2328  Section 13.3
+      On non-broadcast networks, separate      Link State Update
+      packets must be sent, as unicasts, to each adjacent      neighbor
+      (i.e., those in state Exchange or greater).       The destination
+      IP addresses for these packets are the neighbors' IP
+      addresses.   */
+  if (oi->type == OSPF_IFTYPE_NBMA)
+    {
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+        if ((nbr = rn->info) != NULL)
+         if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
+           ospf_ls_upd_send_lsa (nbr, lsa, OSPF_SEND_PACKET_DIRECT);
+    }
+  else
+    ospf_ls_upd_send_lsa (oi->nbr_self, lsa, OSPF_SEND_PACKET_INDIRECT);
+
+  return 0;
+}
+
+int
+ospf_flood_through_area (struct ospf_area * area,struct ospf_neighbor *inbr,
+                        struct ospf_lsa *lsa)
+{
+  listnode node;
+  int lsa_ack_flag = 0;
+
+  /* All other types are specific to a single area (Area A).  The
+     eligible interfaces are all those interfaces attaching to the
+     Area A.  If Area A is the backbone, this includes all the virtual
+     links.  */
+  for (node = listhead (area->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+
+      if (area->area_id.s_addr != OSPF_AREA_BACKBONE &&
+         oi->type ==  OSPF_IFTYPE_VIRTUALLINK) 
+       continue;
+
+#ifdef HAVE_OPAQUE_LSA
+      if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi))
+        {
+          /*
+           * Link local scoped Opaque-LSA should only be flooded
+           * for the link on which the LSA has received.
+           */
+          if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+            zlog_info ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi);
+          continue;
+        }
+#endif /* HAVE_OPAQUE_LSA */
+
+      if (ospf_flood_through_interface (oi, inbr, lsa))
+       lsa_ack_flag = 1;
+    }
+
+  return (lsa_ack_flag);
+}
+
+int
+ospf_flood_through_as (struct ospf_neighbor *inbr, struct ospf_lsa *lsa)
+{
+  listnode node;
+  int lsa_ack_flag;
+
+  lsa_ack_flag = 0;
+
+  /* The incoming LSA is type 5 or type 7  (AS-EXTERNAL or AS-NSSA )
+
+    Divert the Type-5 LSA's to all non-NSSA/STUB areas
+
+    Divert the Type-7 LSA's to all NSSA areas
+
+     AS-external-LSAs are flooded throughout the entire AS, with the
+     exception of stub areas (see Section 3.6).  The eligible
+     interfaces are all the router's interfaces, excluding virtual
+     links and those interfaces attaching to stub areas.  */
+
+#ifdef HAVE_NSSA
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) /* Translated from 7  */
+    if (IS_DEBUG_OSPF_NSSA)
+      zlog_info ("Flood/AS: NSSA TRANSLATED LSA");
+#endif /* HAVE_NSSA */
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      int continue_flag = 0;
+      struct ospf_area *area = getdata (node);
+      listnode if_node;
+
+      switch (area->external_routing)
+       {
+         /* Don't send AS externals into stub areas.  Various types
+             of support for partial stub areas can be implemented
+             here.  NSSA's will receive Type-7's that have areas
+             matching the originl LSA. */
+       case OSPF_AREA_NSSA:    /* Sending Type 5 or 7 into NSSA area */
+#ifdef HAVE_NSSA
+         /* Type-7, flood NSSA area */
+          if (lsa->data->type == OSPF_AS_NSSA_LSA) 
+           /* We will send it. */
+           continue_flag = 0;
+          else
+           continue_flag = 1;  /* Skip this NSSA area for Type-5's et al */
+          break;
+#endif /* HAVE_NSSA */
+
+       case OSPF_AREA_TYPE_MAX:
+       case OSPF_AREA_STUB:
+         continue_flag = 1;    /* Skip this area. */
+         break;
+
+       case OSPF_AREA_DEFAULT:
+       default:
+#ifdef HAVE_NSSA
+         /* No Type-7 into normal area */
+          if (lsa->data->type == OSPF_AS_NSSA_LSA) 
+           continue_flag = 1; /* skip Type-7 */
+          else
+#endif /* HAVE_NSSA */
+           continue_flag = 0;  /* Do this area. */
+         break;
+       }
+      
+      /* Do continue for above switch.  Saves a big if then mess */
+      if (continue_flag) 
+       continue; /* main for-loop */
+      
+      /* send to every interface in this area */
+
+      for (if_node = listhead (area->oiflist); if_node; nextnode (if_node))
+       {
+         struct ospf_interface *oi = getdata (if_node);
+
+         /* Skip virtual links */
+         if (oi->type !=  OSPF_IFTYPE_VIRTUALLINK)
+           if (ospf_flood_through_interface (oi, inbr, lsa)) /* lsa */
+             lsa_ack_flag = 1;
+       }
+    } /* main area for-loop */
+  
+  return (lsa_ack_flag);
+}
+
+int
+ospf_flood_through (struct ospf_neighbor *inbr, struct ospf_lsa *lsa)
+{
+  int lsa_ack_flag = 0;
+  
+  /* Type-7 LSA's for NSSA are flooded throughout the AS here, and
+     upon return are updated in the LSDB for Type-7's.  Later,
+     re-fresh will re-send them (and also, if ABR, packet code will
+     translate to Type-5's)
+  
+     As usual, Type-5 LSA's (if not DISCARDED because we are STUB or
+     NSSA) are flooded throughout the AS, and are updated in the
+     global table.  */
+#ifdef ORIGINAL_CODING
+  switch (lsa->data->type)
+    {
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA:
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */
+    case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa);
+      break;
+    case OSPF_AS_EXTERNAL_LSA: /* Type-5 */
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      lsa_ack_flag = ospf_flood_through_as (inbr, lsa);
+      break;
+#ifdef HAVE_NSSA
+      /* Type-7 Only received within NSSA, then flooded */
+    case OSPF_AS_NSSA_LSA:
+      /* Any P-bit was installed with the Type-7. */
+      lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa);
+
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7.");
+      break;
+#endif /* HAVE_NSSA */
+    default:
+      break;
+    }
+#else /* ORIGINAL_CODING */
+  /*
+   * At the common sub-sub-function "ospf_flood_through_interface()",
+   * a parameter "inbr" will be used to distinguish the called context
+   * whether the given LSA was received from the neighbor, or the
+   * flooding for the LSA starts from this node (e.g. the LSA was self-
+   * originated, or the LSA is going to be flushed from routing domain).
+   *
+   * So, for consistency reasons, this function "ospf_flood_through()"
+   * should also allow the usage that the given "inbr" parameter to be
+   * NULL. If we do so, corresponding AREA parameter should be referred
+   * by "lsa->area", instead of "inbr->oi->area".
+   */
+  switch (lsa->data->type)
+    {
+    case OSPF_AS_EXTERNAL_LSA: /* Type-5 */
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      lsa_ack_flag = ospf_flood_through_as (inbr, lsa);
+      break;
+#ifdef HAVE_NSSA
+      /* Type-7 Only received within NSSA, then flooded */
+    case OSPF_AS_NSSA_LSA:
+      /* Any P-bit was installed with the Type-7. */
+
+      if (IS_DEBUG_OSPF_NSSA)
+       zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7.");
+      /* Fallthrough */
+#endif /* HAVE_NSSA */
+    default:
+      lsa_ack_flag = ospf_flood_through_area (lsa->area, inbr, lsa);
+      break;
+    }
+#endif /* ORIGINAL_CODING */
+  
+  return (lsa_ack_flag);
+}
+
+\f
+
+/* Management functions for neighbor's Link State Request list. */
+void
+ospf_ls_request_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  /*
+   * We cannot make use of the newly introduced callback function
+   * "lsdb->new_lsa_hook" to replace debug output below, just because
+   * it seems no simple and smart way to pass neighbor information to
+   * the common function "ospf_lsdb_add()" -- endo.
+   */
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+      zlog_info ("RqstL(%lu)++, NBR(%s), LSA[%s]",
+                  ospf_ls_request_count (nbr),
+                  inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+
+  ospf_lsdb_add (&nbr->ls_req, lsa);
+}
+
+unsigned long
+ospf_ls_request_count (struct ospf_neighbor *nbr)
+{
+  return ospf_lsdb_count_all (&nbr->ls_req);
+}
+
+int
+ospf_ls_request_isempty (struct ospf_neighbor *nbr)
+{
+  return ospf_lsdb_isempty (&nbr->ls_req);
+}
+
+/* Remove LSA from neighbor's ls-request list. */
+void
+ospf_ls_request_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  if (nbr->ls_req_last == lsa)
+    {
+      ospf_lsa_unlock (nbr->ls_req_last);
+      nbr->ls_req_last = NULL;
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))       /* -- endo. */
+      zlog_info ("RqstL(%lu)--, NBR(%s), LSA[%s]",
+                  ospf_ls_request_count (nbr),
+                  inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+
+  ospf_lsdb_delete (&nbr->ls_req, lsa);
+}
+
+/* Remove all LSA from neighbor's ls-requenst list. */
+void
+ospf_ls_request_delete_all (struct ospf_neighbor *nbr)
+{
+  ospf_lsa_unlock (nbr->ls_req_last);
+  nbr->ls_req_last = NULL;
+  ospf_lsdb_delete_all (&nbr->ls_req);
+}
+
+/* Lookup LSA from neighbor's ls-request list. */
+struct ospf_lsa *
+ospf_ls_request_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  return ospf_lsdb_lookup (&nbr->ls_req, lsa);
+}
+
+struct ospf_lsa *
+ospf_ls_request_new (struct lsa_header *lsah)
+{
+  struct ospf_lsa *new;
+
+  new = ospf_lsa_new ();
+  new->data = ospf_lsa_data_new (OSPF_LSA_HEADER_SIZE);
+  memcpy (new->data, lsah, OSPF_LSA_HEADER_SIZE);
+
+  return new;
+}
+
+\f
+/* Management functions for neighbor's ls-retransmit list. */
+unsigned long
+ospf_ls_retransmit_count (struct ospf_neighbor *nbr)
+{
+  return ospf_lsdb_count_all (&nbr->ls_rxmt);
+}
+
+unsigned long
+ospf_ls_retransmit_count_self (struct ospf_neighbor *nbr, int lsa_type)
+{
+  return ospf_lsdb_count_self (&nbr->ls_rxmt, lsa_type);
+}
+
+int
+ospf_ls_retransmit_isempty (struct ospf_neighbor *nbr)
+{
+  return ospf_lsdb_isempty (&nbr->ls_rxmt);
+}
+
+/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */
+void
+ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *old;
+
+  old = ospf_ls_retransmit_lookup (nbr, lsa);
+
+  if (ospf_lsa_more_recent (old, lsa) < 0)
+    {
+      if (old)
+       {
+         old->retransmit_counter--;
+         ospf_lsdb_delete (&nbr->ls_rxmt, old);
+       }
+      lsa->retransmit_counter++;
+      /*
+       * We cannot make use of the newly introduced callback function
+       * "lsdb->new_lsa_hook" to replace debug output below, just because
+       * it seems no simple and smart way to pass neighbor information to
+       * the common function "ospf_lsdb_add()" -- endo.
+       */
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+         zlog_info ("RXmtL(%lu)++, NBR(%s), LSA[%s]",
+                     ospf_ls_retransmit_count (nbr),
+                    inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+      ospf_lsdb_add (&nbr->ls_rxmt, lsa);
+    }
+}
+
+/* Remove LSA from neibghbor's ls-retransmit list. */
+void
+ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  if (ospf_ls_retransmit_lookup (nbr, lsa))
+    {
+      lsa->retransmit_counter--;  
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))           /* -- endo. */
+         zlog_info ("RXmtL(%lu)--, NBR(%s), LSA[%s]",
+                     ospf_ls_retransmit_count (nbr),
+                    inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+      ospf_lsdb_delete (&nbr->ls_rxmt, lsa);
+    }
+}
+
+/* Clear neighbor's ls-retransmit list. */
+void
+ospf_ls_retransmit_clear (struct ospf_neighbor *nbr)
+{
+  struct ospf_lsdb *lsdb;
+  int i;
+
+  lsdb = &nbr->ls_rxmt;
+
+  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+    {
+      struct route_table *table = lsdb->type[i].db;
+      struct route_node *rn;
+      struct ospf_lsa *lsa;
+
+      for (rn = route_top (table); rn; rn = route_next (rn))
+       if ((lsa = rn->info) != NULL)
+         ospf_ls_retransmit_delete (nbr, lsa);
+    }
+
+  ospf_lsa_unlock (nbr->ls_req_last);
+  nbr->ls_req_last = NULL;
+}
+
+/* Lookup LSA from neighbor's ls-retransmit list. */
+struct ospf_lsa *
+ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  return ospf_lsdb_lookup (&nbr->ls_rxmt, lsa);
+}
+
+/* Remove All neighbor/interface's Link State Retransmit list in area. */
+void
+ospf_ls_retransmit_delete_nbr_all (struct ospf_area *area,
+                                  struct ospf_lsa *lsa)
+{
+  listnode node;
+  list oiflist = area ? area->oiflist : ospf_top->oiflist;
+  
+  for (node = listhead (oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+      struct ospf_lsa *lsr;
+      
+      if (ospf_if_is_enable (oi))
+       for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+         /* If LSA find in LS-retransmit list, then remove it. */
+         if ((nbr = rn->info) != NULL)
+           {
+             lsr = ospf_ls_retransmit_lookup (nbr, lsa);
+            
+             /* If LSA find in ls-retransmit list, remove it. */
+             if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
+               ospf_ls_retransmit_delete (nbr, lsr);
+           }
+    }
+}
+
+/* Add LSA to the current database copy of all neighbors'
+   Link state retransmission lists. */
+void
+ospf_ls_retransmit_add_nbr_all (struct ospf_interface *ospfi,
+                               struct ospf_lsa *lsa)
+{
+  listnode node;
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+      struct ospf_lsa *old;
+
+      if (ospf_if_is_enable (oi))
+       if (OSPF_AREA_SAME (&ospfi->area, &oi->area))
+         for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+           if ((nbr = rn->info) != NULL)
+             if (nbr->state == NSM_Full)
+               {
+                 if ((old = ospf_ls_retransmit_lookup (nbr, lsa)))
+                   ospf_ls_retransmit_delete (nbr, old);
+
+                 ospf_ls_retransmit_add (nbr, lsa);
+               }
+    }
+}
+
+\f
+/* Sets ls_age to MaxAge and floods throu the area. 
+   When we implement ASE routing, there will be anothe function
+   flushing an LSA from the whole domain. */
+void
+ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area)
+{
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+  ospf_flood_through_area (area, NULL, lsa);
+  ospf_lsa_maxage (lsa);
+}
+
+void
+ospf_lsa_flush_as (struct ospf_lsa *lsa)
+{
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+  ospf_flood_through_as (NULL, lsa);
+  ospf_lsa_maxage (lsa);
+}
+
+/* Flush LSA through AS -- used for AS-external-LSAs. */
+void
+ospf_flush_through_as (struct ospf_lsa *lsa)
+{
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+  ospf_flood_through_as (NULL, lsa);
+  ospf_lsa_maxage (lsa);
+}
diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h
new file mode 100644 (file)
index 0000000..1a6ab97
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * OSPF Flooding -- RFC2328 Section 13.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_FLOODING_H
+#define _ZEBRA_OSPF_FLOODING_H
+
+int ospf_flood (struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *);
+int ospf_flood_through (struct ospf_neighbor *, struct ospf_lsa *);
+int ospf_flood_through_area (struct ospf_area *, struct ospf_neighbor *,
+                            struct ospf_lsa *);
+int ospf_flood_through_as (struct ospf_neighbor *, struct ospf_lsa *);
+
+unsigned long ospf_ls_request_count (struct ospf_neighbor *);
+int ospf_ls_request_isempty (struct ospf_neighbor *);
+struct ospf_lsa *ospf_ls_request_new (struct lsa_header *);
+void ospf_ls_request_free (struct ospf_lsa *);
+void ospf_ls_request_add (struct ospf_neighbor *, struct ospf_lsa *);
+void ospf_ls_request_delete (struct ospf_neighbor *, struct ospf_lsa *);
+void ospf_ls_request_delete_all (struct ospf_neighbor *);
+struct ospf_lsa *ospf_ls_request_lookup (struct ospf_neighbor *,
+                                        struct ospf_lsa *);
+
+unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *);
+unsigned long ospf_ls_retransmit_count_self (struct ospf_neighbor *, int);
+int ospf_ls_retransmit_isempty (struct ospf_neighbor *);
+void ospf_ls_retransmit_add (struct ospf_neighbor *, struct ospf_lsa *);
+void ospf_ls_retransmit_delete (struct ospf_neighbor *, struct ospf_lsa *);
+void ospf_ls_retransmit_clear (struct ospf_neighbor *);
+struct ospf_lsa *ospf_ls_retransmit_lookup (struct ospf_neighbor *,
+                                           struct ospf_lsa *);
+void ospf_ls_retransmit_delete_nbr_all (struct ospf_area *, struct ospf_lsa *);
+void ospf_ls_retransmit_add_nbr_all (struct ospf_interface *,
+                                    struct ospf_lsa *);
+
+void ospf_flood_lsa_area (struct ospf_lsa *, struct ospf_area *);
+void ospf_flood_lsa_as (struct ospf_lsa *);
+void ospf_lsa_flush_area (struct ospf_lsa *, struct ospf_area *);
+void ospf_lsa_flush_as (struct ospf_lsa *);
+void ospf_flush_through_as (struct ospf_lsa *);
+struct external_info *ospf_external_info_check (struct ospf_lsa *);
+
+void debug_ospf_ls_retransmit (struct ospf_neighbor *);
+
+void ospf_lsdb_init (struct ospf_lsdb *);
+
+#endif /* _ZEBRA_OSPF_FLOODING_H */
diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c
new file mode 100644 (file)
index 0000000..32c8d86
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * OSPF inter-area routing.
+ * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_ia.h"
+#include "ospfd/ospf_dump.h"
+
+#define DEBUG
+
+struct ospf_route *
+ospf_find_abr_route (struct route_table *rtrs, 
+                     struct prefix_ipv4 *abr,
+                     struct ospf_area *area)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  listnode node;
+
+  if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL)
+    return NULL;
+
+  route_unlock_node (rn);
+
+  for (node = listhead ((list) rn->info); node; nextnode (node))
+    if ((or = getdata (node)) != NULL)
+      if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id) && (or->u.std.flags & ROUTER_LSA_BORDER))
+       return or;
+
+  return NULL;
+}
+
+void
+ospf_ia_network_route (struct route_table *rt, struct prefix_ipv4 *p,
+                       struct ospf_route *new_or, struct ospf_route *abr_or)
+{
+  struct route_node *rn1;
+  struct ospf_route *or;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_ia_network_route(): processing summary route to %s/%d", 
+              inet_ntoa (p->prefix), p->prefixlen);
+
+  /* Find a route to the same dest */
+  if ((rn1 = route_node_lookup (rt, (struct prefix *) p)))
+    {
+      int res;
+
+      route_unlock_node (rn1);
+
+      if ((or = rn1->info))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_ia_network_route(): "
+                      "Found a route to the same network");
+         /* Check the existing route. */
+         if ((res = ospf_route_cmp (new_or, or)) < 0)
+           {
+             /* New route is better, so replace old one. */
+             ospf_route_subst (rn1, new_or, abr_or);
+           }
+         else if (res == 0)
+           {
+             /* New and old route are equal, so next hops can be added. */
+             route_lock_node (rn1);
+             ospf_route_copy_nexthops (or, abr_or->path);
+             route_unlock_node (rn1);
+
+             /* new route can be deleted, because existing route has been updated. */
+             ospf_route_free (new_or);
+           }
+         else
+           {
+             /* New route is worse, so free it. */
+             ospf_route_free (new_or);
+             return;
+           }
+       } /* if (or)*/
+    } /*if (rn1)*/
+  else
+    { /* no route */
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_ia_network_route(): add new route to %s/%d",
+                  inet_ntoa (p->prefix), p->prefixlen);
+      ospf_route_add (rt, p, new_or, abr_or);
+    }
+}
+
+void
+ospf_ia_router_route (struct route_table *rt, struct prefix_ipv4 *p,
+                      struct ospf_route *new_or, struct ospf_route *abr_or)
+{
+  struct route_node *rn;
+  struct ospf_route *or = NULL;
+  int ret;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_ia_router_route(): considering %s/%d", 
+              inet_ntoa (p->prefix), p->prefixlen);
+  /* Find a route to the same dest */
+  rn = route_node_get (rt,(struct prefix *) p);
+   
+  if (rn->info == NULL)
+    /* This is a new route */
+    rn->info = list_new ();
+  else
+    {
+      struct ospf_area *or_area;
+      or_area = ospf_area_lookup_by_area_id (new_or->u.std.area_id);
+      assert (or_area);
+      /* This is an additional route */
+      route_unlock_node (rn);
+      or = ospf_find_asbr_route_through_area (rt, p, or_area);
+    }
+
+  if (or)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_ia_router_route(): "
+                  "a route to the same ABR through the same area exists");
+      /* New route is better */
+      if ((ret = ospf_route_cmp (new_or, or)) < 0)
+       {
+         listnode_delete (rn->info, or);
+         ospf_route_free (or);
+         /* proceed down */
+       }
+      /* Routes are the same */
+      else if (ret == 0)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_ia_router_route(): merging the new route");
+
+         ospf_route_copy_nexthops (or, abr_or->path);
+         ospf_route_free (new_or);
+         return;
+       }
+      /* New route is worse */
+      else
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_ia_router_route(): skipping the new route");
+         ospf_route_free (new_or);
+         return;
+       }
+    }
+
+  ospf_route_copy_nexthops (new_or, abr_or->path);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_ia_router_route(): adding the new route"); 
+
+  listnode_add (rn->info, new_or);
+}
+
+\f
+struct ia_args
+{
+  struct route_table *rt;
+  struct route_table *rtrs;
+  struct ospf_area *area;
+};
+
+int
+process_summary_lsa (struct ospf_lsa *l, void *v, int i)
+{
+  struct ospf_area_range *range;
+  struct ospf_route *abr_or, *new_or;
+  struct summary_lsa *sl;
+  struct prefix_ipv4 p, abr;
+  u_int32_t metric;
+  struct ia_args *args;
+
+  if (l == NULL)
+    return 0;
+
+  args = (struct ia_args *) v;
+  sl = (struct summary_lsa *) l->data;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id));
+
+  metric = GET_METRIC (sl->metric);
+   
+  if (metric == OSPF_LS_INFINITY)
+    return 0;
+
+  if (IS_LSA_MAXAGE (l))
+    return 0;
+
+  if (ospf_lsa_is_self_originated (l))
+    return 0;
+
+  p.family = AF_INET;
+  p.prefix = sl->header.id;
+   
+  if (sl->header.type == OSPF_SUMMARY_LSA)
+    p.prefixlen = ip_masklen (sl->mask);
+  else
+    p.prefixlen = IPV4_MAX_BITLEN;
+      
+  apply_mask_ipv4 (&p);
+
+  if (sl->header.type == OSPF_SUMMARY_LSA &&
+      (range = ospf_area_range_match_any (ospf_top, &p)) &&
+      ospf_area_range_active (range))
+    return 0;
+
+  if (ospf_top->abr_type != OSPF_ABR_STAND &&
+      args->area->external_routing != OSPF_AREA_DEFAULT &&
+      p.prefix.s_addr == OSPF_DEFAULT_DESTINATION &&
+      p.prefixlen == 0)
+    return 0; /* Ignore summary default from a stub area */
+
+  abr.family = AF_INET;
+  abr.prefix = sl->header.adv_router;
+  abr.prefixlen = IPV4_MAX_BITLEN;
+  apply_mask_ipv4 (&abr);
+
+  abr_or = ospf_find_abr_route (args->rtrs, &abr, args->area);
+
+  if (abr_or == NULL)
+    return 0;
+
+  new_or = ospf_route_new ();
+  new_or->type = OSPF_DESTINATION_NETWORK;
+  new_or->id = sl->header.id;
+  new_or->mask = sl->mask;
+  new_or->u.std.options = sl->header.options;
+  new_or->u.std.origin = (struct lsa_header *) sl;
+  new_or->cost = abr_or->cost + metric;
+  new_or->u.std.area_id = args->area->area_id;
+#ifdef HAVE_NSSA
+  new_or->u.std.external_routing = args->area->external_routing;
+#endif /* HAVE_NSSA */
+  new_or->path_type = OSPF_PATH_INTER_AREA;
+
+  if (sl->header.type == OSPF_SUMMARY_LSA)
+    ospf_ia_network_route (args->rt, &p, new_or, abr_or);
+  else 
+    {
+      new_or->type = OSPF_DESTINATION_ROUTER;
+      new_or->u.std.flags = ROUTER_LSA_EXTERNAL;
+      ospf_ia_router_route (args->rtrs, &p, new_or, abr_or);
+    }
+
+  return 0;
+}
+
+void
+ospf_examine_summaries (struct ospf_area * area,
+                       struct route_table *lsdb_rt,
+                        struct route_table *rt,
+                        struct route_table *rtrs)
+{
+  struct ia_args args = {rt, rtrs, area};
+  foreach_lsa (lsdb_rt, &args, 0, process_summary_lsa);
+}
+
+int
+ospf_area_is_transit (struct ospf_area *area)
+{
+  return (area->transit == OSPF_TRANSIT_TRUE) ||
+    ospf_full_virtual_nbrs(area); /* Cisco forgets to set the V-bit :( */
+}
+
+void
+ospf_update_network_route (struct route_table *rt, 
+                           struct route_table *rtrs,
+                           struct summary_lsa *lsa,
+                           struct prefix_ipv4 *p,
+                           struct ospf_area *area)
+{
+  struct route_node *rn;
+  struct ospf_route *or, *abr_or, *new_or;
+  struct prefix_ipv4 abr;
+  u_int32_t cost;
+
+  abr.family = AF_INET;
+  abr.prefix =lsa->header.adv_router;
+  abr.prefixlen = IPV4_MAX_BITLEN;
+  apply_mask_ipv4 (&abr);
+
+  abr_or = ospf_find_abr_route (rtrs, &abr, area);
+
+  if (abr_or == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_network_route(): can't find a route to the ABR");
+      return;
+    }
+
+  cost = abr_or->cost + GET_METRIC (lsa->metric);
+
+  rn = route_node_lookup (rt, (struct prefix *) p);
+
+  if (! rn)
+    {
+      if (ospf_top->abr_type != OSPF_ABR_SHORTCUT)
+        return; /* Standard ABR can update only already installed
+                   backbone paths                                       */
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_network_route(): "
+                  "Allowing Shortcut ABR to add new route");
+      new_or = ospf_route_new ();
+      new_or->type = OSPF_DESTINATION_NETWORK;
+      new_or->id = lsa->header.id;
+      new_or->mask = lsa->mask;
+      new_or->u.std.options = lsa->header.options;
+      new_or->u.std.origin = (struct lsa_header *) lsa;
+      new_or->cost = cost;
+      new_or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+      new_or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+      new_or->path_type = OSPF_PATH_INTER_AREA;
+      ospf_route_add (rt, p, new_or, abr_or);
+
+      return;
+    }
+  else
+    {
+      route_unlock_node (rn);
+      if (rn->info == NULL)
+        return;
+    }
+
+  or = rn->info;
+
+  if (or->path_type != OSPF_PATH_INTRA_AREA &&
+      or->path_type != OSPF_PATH_INTER_AREA)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_network_route(): ERR: path type is wrong");
+      return;
+    }
+
+  if (ospf_top->abr_type == OSPF_ABR_SHORTCUT)
+    {
+      if (or->path_type == OSPF_PATH_INTRA_AREA &&
+         !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_update_network_route(): Shortcut: "
+                      "this intra-area path is not backbone");
+         return;
+       }
+    }
+  else   /* Not Shortcut ABR */
+    {
+      if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_update_network_route(): "
+                      "route is not BB-associated");
+         return; /* We can update only BB routes */
+       }
+    }
+
+  if (or->cost < cost)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_network_route(): new route is worse");
+      return;
+    }
+
+  if (or->cost == cost)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_network_route(): "
+                  "new route is same distance, adding nexthops");
+      ospf_route_copy_nexthops (or, abr_or->path);
+    }
+
+  if (or->cost > cost)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_network_route(): "
+                  "new route is better, overriding nexthops");
+      ospf_route_subst_nexthops (or, abr_or->path);
+      or->cost = cost;
+
+      if ((ospf_top->abr_type == OSPF_ABR_SHORTCUT) &&
+         !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id))
+       {
+         or->path_type = OSPF_PATH_INTER_AREA;
+         or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+         or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+          /* Note that we can do this only in Shortcut ABR mode,
+             because standard ABR must leave the route type and area
+             unchanged
+          */
+        }
+    }
+}
+
+void
+ospf_update_router_route (struct route_table *rtrs, 
+                          struct summary_lsa *lsa,
+                          struct prefix_ipv4 *p,
+                          struct ospf_area *area)
+{
+  struct ospf_route *or, *abr_or, *new_or;
+  struct prefix_ipv4 abr;
+  u_int32_t cost;
+
+  abr.family = AF_INET;
+  abr.prefix = lsa->header.adv_router;
+  abr.prefixlen = IPV4_MAX_BITLEN;
+  apply_mask_ipv4 (&abr);
+
+  abr_or = ospf_find_abr_route (rtrs, &abr, area);
+
+  if (abr_or == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_update_router_route(): can't find a route to the ABR");
+      return;
+    }
+
+  cost = abr_or->cost + GET_METRIC (lsa->metric);
+
+  /* First try to find a backbone path,
+     because standard ABR can update only BB-associated paths */
+
+  if ((ospf_top->backbone == NULL) &&
+      (ospf_top->abr_type != OSPF_ABR_SHORTCUT))
+
+     /* no BB area, not Shortcut ABR, exiting */
+     return;
+  or = ospf_find_asbr_route_through_area (rtrs, p, ospf_top->backbone);
+
+  if (or == NULL)
+    {
+      if (ospf_top->abr_type != OSPF_ABR_SHORTCUT)
+
+         /* route to ASBR through the BB not found
+            the router is not Shortcut ABR, exiting */
+
+          return;
+      else
+       /* We're a Shortcut ABR*/
+       {
+         /* Let it either add a new router or update the route
+            through the same (non-BB) area. */
+
+         new_or = ospf_route_new ();
+         new_or->type = OSPF_DESTINATION_ROUTER;
+         new_or->id = lsa->header.id;
+         new_or->mask = lsa->mask;
+         new_or->u.std.options = lsa->header.options;
+         new_or->u.std.origin = (struct lsa_header *)lsa;
+         new_or->cost = cost;
+         new_or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+         new_or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+         new_or->path_type = OSPF_PATH_INTER_AREA;
+         new_or->u.std.flags = ROUTER_LSA_EXTERNAL;
+         ospf_ia_router_route (rtrs, p, new_or, abr_or);
+
+          return;
+        }
+    }
+
+  /* At this point the "or" is always bb-associated */
+
+  if (!(or->u.std.flags & ROUTER_LSA_EXTERNAL))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_upd_router_route(): the remote router is not an ASBR");
+      return;
+    }
+
+  if (or->path_type != OSPF_PATH_INTRA_AREA &&
+      or->path_type != OSPF_PATH_INTER_AREA)
+    return;
+
+  if (or->cost < cost)
+    return;
+
+  else if (or->cost == cost)
+    ospf_route_copy_nexthops (or, abr_or->path);
+
+  else if (or->cost > cost)
+    {
+      ospf_route_subst_nexthops (or, abr_or->path);
+      or->cost = cost;
+
+      /* Even if the ABR runs in Shortcut mode, we can't change
+         the path type and area, because the "or" is always bb-associated
+         at this point and even Shortcut ABR can't change these attributes */
+    }
+}
+
+int
+process_transit_summary_lsa (struct ospf_lsa *l, void *v, int i)
+{
+  struct summary_lsa *sl;
+  struct prefix_ipv4 p;
+  u_int32_t metric;
+  struct ia_args *args;
+
+  if (l == NULL)
+    return 0;
+
+  args = (struct ia_args *) v;
+  sl = (struct summary_lsa *) l->data;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("process_transit_summaries(): LS ID: %s",
+              inet_ntoa (l->data->id));
+  metric = GET_METRIC (sl->metric);
+   
+  if (metric == OSPF_LS_INFINITY)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("process_transit_summaries(): metric is infinity, skip");
+      return 0;
+    }
+
+  if (IS_LSA_MAXAGE (l))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("process_transit_summaries(): This LSA is too old");
+      return 0;
+    }
+
+  if (ospf_lsa_is_self_originated (l))
+    { 
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("process_transit_summaries(): This LSA is mine, skip");
+      return 0;
+    }
+
+  p.family = AF_INET;
+  p.prefix = sl->header.id;
+   
+  if (sl->header.type == OSPF_SUMMARY_LSA)
+    p.prefixlen = ip_masklen (sl->mask);
+  else
+    p.prefixlen = IPV4_MAX_BITLEN;
+      
+  apply_mask_ipv4 (&p);
+
+  if (sl->header.type == OSPF_SUMMARY_LSA)
+    ospf_update_network_route (args->rt, args->rtrs, sl, &p, args->area);
+  else
+    ospf_update_router_route (args->rtrs, sl, &p, args->area);
+  return 0;
+}
+
+void
+ospf_examine_transit_summaries (struct ospf_area *area,
+                                /* struct ospf_lsdb *lsdb, */
+                               struct route_table *lsdb_rt,
+                                struct route_table *rt,
+                                struct route_table *rtrs)
+{
+  struct ia_args args = {rt, rtrs, area};
+
+  /* ospf_lsdb_iterator (lsdb, &args, 0, process_transit_summary_lsa); */
+  foreach_lsa (lsdb_rt, &args, 0, process_transit_summary_lsa);
+}
+
+void
+ospf_ia_routing (struct route_table *rt,
+                 struct route_table *rtrs)
+{
+  struct ospf_area * area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_ia_routing():start");
+
+  if (OSPF_IS_ABR)
+    {
+      listnode node; 
+      struct ospf_area *area;
+
+      switch (ospf_top->abr_type)
+        {
+        case OSPF_ABR_STAND:
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_ia_routing():Standard ABR");
+
+          if ((area = ospf_top->backbone))
+            {
+              listnode node;
+
+             if (IS_DEBUG_OSPF_EVENT)
+               {
+                 zlog_info ("ospf_ia_routing():backbone area found");
+                 zlog_info ("ospf_ia_routing():examining summaries");
+               }
+
+              OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs);
+
+             for (node = listhead (ospf_top->areas); node; nextnode (node))
+                if ((area = getdata (node)) != NULL)
+                  if (area != ospf_top->backbone)
+                   if (ospf_area_is_transit (area))
+                     OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs);
+            }
+          else
+           if (IS_DEBUG_OSPF_EVENT)
+             zlog_info ("ospf_ia_routing():backbone area NOT found");
+          break;
+        case OSPF_ABR_IBM:
+        case OSPF_ABR_CISCO:
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_ia_routing():Alternative Cisco/IBM ABR");
+          area = ospf_top->backbone; /* Find the BB */
+
+          /* If we have an active BB connection */
+          if (area && ospf_act_bb_connection ())
+            {
+             if (IS_DEBUG_OSPF_EVENT)
+               {
+                 zlog_info ("ospf_ia_routing(): backbone area found");
+                 zlog_info ("ospf_ia_routing(): examining BB summaries");
+               }
+
+              OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs);
+
+             for (node = listhead (ospf_top->areas); node; nextnode (node))
+                if ((area = getdata (node)) != NULL)
+                  if (area != ospf_top->backbone)
+                   if (ospf_area_is_transit (area))
+                     OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs);
+            }
+          else
+            { /* No active BB connection--consider all areas */
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("ospf_ia_routing(): "
+                          "Active BB connection not found");
+             for (node = listhead (ospf_top->areas); node; nextnode (node))
+                if ((area = getdata (node)) != NULL)
+                  OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs);
+            }
+          break;
+        case OSPF_ABR_SHORTCUT:
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_ia_routing():Alternative Shortcut");
+          area = ospf_top->backbone; /* Find the BB */
+
+          /* If we have an active BB connection */
+          if (area && ospf_act_bb_connection ())
+            {
+             if (IS_DEBUG_OSPF_EVENT)
+               {
+                 zlog_info ("ospf_ia_routing(): backbone area found");
+                 zlog_info ("ospf_ia_routing(): examining BB summaries");
+               }
+              OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs);
+            }
+
+         for (node = listhead (ospf_top->areas); node; nextnode (node))
+            if ((area = getdata (node)) != NULL)
+              if (area != ospf_top->backbone)
+               if (ospf_area_is_transit (area) ||
+                   ((area->shortcut_configured != OSPF_SHORTCUT_DISABLE) &&
+                    ((ospf_top->backbone == NULL) ||
+                      ((area->shortcut_configured == OSPF_SHORTCUT_ENABLE) &&
+                      area->shortcut_capability))))
+                 OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs);
+          break;
+        default:
+          break;
+        }
+    }
+  else 
+    {
+      listnode node;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_ia_routing():not ABR, considering all areas");
+
+      for (node = listhead (ospf_top->areas); node; nextnode (node))
+        if ((area = getdata (node)) != NULL)
+          OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs);
+    }
+}
diff --git a/ospfd/ospf_ia.h b/ospfd/ospf_ia.h
new file mode 100644 (file)
index 0000000..afb2d4d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * OSPF inter-area routing.
+ * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_IA_H
+#define _ZEBRA_OSPF_IA_H
+
+/* Macros. */
+#define OSPF_EXAMINE_SUMMARIES_ALL(A,N,R) \
+       { \
+         ospf_examine_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \
+         ospf_examine_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \
+       }
+
+#define OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL(A,N,R) \
+       { \
+         ospf_examine_transit_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \
+         ospf_examine_transit_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \
+       }
+
+void ospf_ia_routing (struct route_table *, struct route_table *);
+int ospf_area_is_transit (struct ospf_area *);
+
+#endif /* _ZEBRA_OSPF_IA_H */
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
new file mode 100644 (file)
index 0000000..ddae980
--- /dev/null
@@ -0,0 +1,1045 @@
+/*
+ * OSPF Interface functions.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "stream.h"
+#include "log.h"
+
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_dump.h"
+#ifdef HAVE_SNMP
+#include "ospfd/ospf_snmp.h"
+#endif /* HAVE_SNMP */
+
+\f
+int
+ospf_if_get_output_cost (struct ospf_interface *oi)
+{
+  /* If all else fails, use default OSPF cost */
+  u_int32_t cost;
+  u_int32_t bw, refbw;
+
+  bw = oi->ifp->bandwidth ? oi->ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH;
+  refbw = ospf_top ? ospf_top->ref_bandwidth : OSPF_DEFAULT_REF_BANDWIDTH;
+
+  /* A specifed ip ospf cost overrides a calculated one. */
+  if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), output_cost_cmd) ||
+      OSPF_IF_PARAM_CONFIGURED (oi->params, output_cost_cmd))
+    cost = OSPF_IF_PARAM (oi, output_cost_cmd);
+  /* See if a cost can be calculated from the zebra processes
+     interface bandwidth field. */
+  else
+    {
+      cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5);
+      if (cost < 1)
+       cost = 1;
+      else if (cost > 65535)
+       cost = 65535;
+    }
+
+  return cost;
+}
+
+void
+ospf_if_recalculate_output_cost (struct interface *ifp)
+{
+  u_int32_t newcost;
+  struct route_node *rn;
+  
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      struct ospf_interface *oi;
+      
+      if ( (oi = rn->info) == NULL)
+       continue;
+
+      newcost = ospf_if_get_output_cost (oi);
+
+      /* Is actual output cost changed? */
+      if (oi->output_cost != newcost)
+       {
+         oi->output_cost = newcost;
+         ospf_router_lsa_timer_add (oi->area);
+       }
+    }
+}
+
+void
+ospf_if_reset_variables (struct ospf_interface *oi)
+{
+  /* Set default values. */
+  /* don't clear this flag.  oi->flag = OSPF_IF_DISABLE; */
+
+  if (oi->vl_data)
+    oi->type = OSPF_IFTYPE_VIRTUALLINK;
+  else 
+  /* preserve network-type */
+  if (oi->type != OSPF_IFTYPE_NBMA)
+    oi->type = OSPF_IFTYPE_BROADCAST;
+
+  oi->state = ISM_Down;
+
+  oi->crypt_seqnum = 0;
+
+  /* This must be short, (less than RxmtInterval) 
+     - RFC 2328 Section 13.5 para 3.  Set to 1 second to avoid Acks being
+       held back for too long - MAG */
+  oi->v_ls_ack = 1;  
+}
+
+void
+ospf_add_to_if (struct interface *ifp, struct ospf_interface *oi)
+{
+  struct route_node *rn;
+  struct prefix p;
+
+  p = *oi->address;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+  rn = route_node_get (IF_OIFS (ifp), &p);
+  assert (! rn->info);
+  rn->info = oi;
+}
+
+void
+ospf_delete_from_if (struct interface *ifp, struct ospf_interface *oi)
+{
+  struct route_node *rn;
+  struct prefix p;
+
+  p = *oi->address;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+  rn = route_node_lookup (IF_OIFS (oi->ifp), &p);
+  assert (rn);
+  assert (rn->info);
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+}
+
+struct ospf_interface *
+ospf_if_new (struct interface *ifp, struct prefix *p)
+{
+  struct ospf_interface *oi;
+
+  oi = XCALLOC (MTYPE_OSPF_IF, sizeof (struct ospf_interface));
+  memset (oi, 0, sizeof (struct ospf_interface));
+
+  /* Set zebra interface pointer. */
+  oi->ifp = ifp;
+  oi->address = p;
+  
+  ospf_add_to_if (ifp, oi);
+  listnode_add (ospf_top->oiflist, oi);
+  
+  /* Clear self-originated network-LSA. */
+  oi->network_lsa_self = NULL;
+
+  /* Initialize neighbor list. */
+  oi->nbrs = route_table_init ();
+
+  /* Initialize static neighbor list. */
+  oi->nbr_nbma = list_new ();
+
+  /* Initialize Link State Acknowledgment list. */
+  oi->ls_ack = list_new ();
+  oi->ls_ack_direct.ls_ack = list_new ();
+
+  /* Set default values. */
+  ospf_if_reset_variables (oi);
+
+  /* Add pseudo neighbor. */
+  oi->nbr_self = ospf_nbr_new (oi);
+  oi->nbr_self->state = NSM_TwoWay;
+  /*  oi->nbr_self->router_id = ospf_top->router_id; */
+  oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority);
+  oi->nbr_self->options = OSPF_OPTION_E;
+
+  oi->ls_upd_queue = route_table_init ();
+  oi->t_ls_upd_event = NULL;
+  oi->t_ls_ack_direct = NULL;
+
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_type9_lsa_init (oi);
+#endif /* HAVE_OPAQUE_LSA */
+
+  oi->ospf = ospf_top;
+  
+  return oi;
+}
+
+/* Restore an interface to its pre UP state
+   Used from ism_interface_down only */
+void
+ospf_if_cleanup (struct ospf_interface *oi)
+{
+  struct route_node *rn;
+  listnode node;
+  struct ospf_neighbor *nbr;
+
+  /* oi->nbrs and oi->nbr_nbma should be deletete on InterafceDown event */
+  /* delete all static neighbors attached to this interface */
+  for (node = listhead (oi->nbr_nbma); node; )
+    {
+      struct ospf_nbr_nbma *nbr_nbma = getdata (node);
+      nextnode (node);
+
+      OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll);
+
+      if (nbr_nbma->nbr)
+       {
+         nbr_nbma->nbr->nbr_nbma = NULL;
+         nbr_nbma->nbr = NULL;
+       }
+
+      nbr_nbma->oi = NULL;
+      
+      listnode_delete (oi->nbr_nbma, nbr_nbma);
+    }
+
+  /* send Neighbor event KillNbr to all associated neighbors. */
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info) != NULL)
+      if (nbr != oi->nbr_self)
+       OSPF_NSM_EVENT_EXECUTE (nbr, NSM_KillNbr);
+
+  /* Cleanup Link State Acknowlegdment list. */
+  for (node = listhead (oi->ls_ack); node; nextnode (node))
+    ospf_lsa_unlock (node->data);
+  list_delete_all_node (oi->ls_ack);
+
+  oi->crypt_seqnum = 0;
+  
+  /* Empty link state update queue */
+  ospf_ls_upd_queue_empty (oi);
+  
+ /* Handle pseudo neighbor. */
+  ospf_nbr_delete (oi->nbr_self);
+  oi->nbr_self = ospf_nbr_new (oi);
+  oi->nbr_self->state = NSM_TwoWay;
+  oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority);
+  oi->nbr_self->options = OSPF_OPTION_E;
+
+  ospf_lsa_unlock (oi->network_lsa_self);
+  oi->network_lsa_self = NULL;
+  OSPF_TIMER_OFF (oi->t_network_lsa_self);
+}
+
+void
+ospf_if_free (struct ospf_interface *oi)
+{
+  ospf_if_down (oi);
+
+  assert (oi->state == ISM_Down);
+
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_type9_lsa_term (oi);
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Free Pseudo Neighbour */
+  ospf_nbr_delete (oi->nbr_self);
+  
+  route_table_finish (oi->nbrs);
+  route_table_finish (oi->ls_upd_queue);
+  
+  /* Free any lists that should be freed */
+  list_free (oi->nbr_nbma);
+  
+  list_free (oi->ls_ack);
+  list_free (oi->ls_ack_direct.ls_ack);
+  
+  ospf_delete_from_if (oi->ifp, oi);
+
+  listnode_delete (ospf_top->oiflist, oi);
+  listnode_delete (oi->area->oiflist, oi);
+
+  memset (oi, 0, sizeof (*oi));
+  XFREE (MTYPE_OSPF_IF, oi);
+}
+
+\f
+/*
+*  check if interface with given address is configured and
+*  return it if yes.
+*/
+struct ospf_interface *
+ospf_if_is_configured (struct in_addr *address)
+{
+  listnode node;
+  struct ospf_interface *oi;
+  struct prefix *addr;
+  
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+      {
+       if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+         addr = oi->connected->destination;
+       else
+         addr = oi->address;
+       
+       if (IPV4_ADDR_SAME (address, &addr->u.prefix4))
+         return oi;
+      }
+
+  return NULL;
+}
+
+int
+ospf_if_is_up (struct ospf_interface *oi)
+{
+  return if_is_up (oi->ifp);
+}
+
+struct ospf_interface *
+ospf_if_lookup_by_local_addr (struct interface *ifp, struct in_addr address)
+{
+  listnode node;
+  struct ospf_interface *oi;
+  
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+      {
+       if (ifp && oi->ifp != ifp)
+         continue;
+       
+       if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4))
+         return oi;
+      }
+
+  return NULL;
+}
+
+struct ospf_interface *
+ospf_if_lookup_by_prefix (struct prefix_ipv4 *p)
+{
+  listnode node;
+  struct ospf_interface *oi;
+  struct prefix ptmp;
+  
+  /* Check each Interface. */
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node)) {
+    if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+      {
+       if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
+         prefix_copy (&ptmp, oi->connected->destination);
+         ptmp.prefixlen = IPV4_MAX_BITLEN;
+       }
+       else
+         prefix_copy (&ptmp, oi->address);
+       
+       apply_mask (&ptmp);
+       if (prefix_same (&ptmp, (struct prefix *) p))
+         return oi;
+      }
+  }
+  return NULL;
+}
+
+/* determine receiving interface by source of packet */
+struct ospf_interface *
+ospf_if_lookup_recv_interface (struct in_addr src)
+{
+  listnode node;
+  struct prefix_ipv4 addr;
+  struct ospf_interface *oi, *match;
+
+  addr.family = AF_INET;
+  addr.prefix = src;
+  addr.prefixlen = IPV4_MAX_BITLEN;
+
+  match = NULL;
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      oi = getdata (node);
+      
+      if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+       continue;
+      
+      if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+       {
+         if (IPV4_ADDR_SAME (&oi->connected->destination->u.prefix4, &src))
+           return oi;
+       }
+      else
+       {
+         if (prefix_match (oi->address, (struct prefix *) &addr))
+           match = oi;
+       }
+    }
+
+  return match;
+}
+\f
+void
+ospf_if_stream_set (struct ospf_interface *oi)
+{
+  /* set output fifo queue. */
+  if (oi->obuf == NULL) 
+    oi->obuf = ospf_fifo_new ();
+}
+
+void
+ospf_if_stream_unset (struct ospf_interface *oi)
+{
+  if (oi->obuf)
+    {
+     ospf_fifo_free (oi->obuf);
+     oi->obuf = NULL;
+
+     if (oi->on_write_q)
+       {
+        listnode_delete (ospf_top->oi_write_q, oi);
+         if (list_isempty(ospf_top->oi_write_q))
+           OSPF_TIMER_OFF (ospf_top->t_write);
+        oi->on_write_q = 0;
+       }
+    }
+}
+\f
+struct ospf_if_params *
+ospf_new_if_params ()
+{
+  struct ospf_if_params *oip;
+
+  oip = XMALLOC (MTYPE_OSPF_IF_PARAMS, sizeof (struct ospf_if_params));
+  memset (oip, 0, sizeof (struct ospf_if_params));
+
+  if (!oip)
+    return NULL;
+
+  memset (oip, 0, sizeof (struct ospf_if_params));
+
+  UNSET_IF_PARAM (oip, output_cost_cmd);
+  UNSET_IF_PARAM (oip, transmit_delay);
+  UNSET_IF_PARAM (oip, retransmit_interval);
+  UNSET_IF_PARAM (oip, passive_interface);
+  UNSET_IF_PARAM (oip, v_hello);
+  UNSET_IF_PARAM (oip, v_wait);
+  UNSET_IF_PARAM (oip, priority);
+  UNSET_IF_PARAM (oip, type);
+  UNSET_IF_PARAM (oip, auth_simple);
+  UNSET_IF_PARAM (oip, auth_crypt);
+  UNSET_IF_PARAM (oip, auth_type);
+  
+  oip->auth_crypt = list_new ();
+
+  return oip;
+}
+
+void
+ospf_del_if_params (struct ospf_if_params *oip)
+{
+  list_delete (oip->auth_crypt);
+  XFREE (MTYPE_OSPF_IF_PARAMS, oip);
+}
+
+void
+ospf_free_if_params (struct interface *ifp, struct in_addr addr)
+{
+  struct ospf_if_params *oip;
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = addr;
+  rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p);
+  if (!rn || !rn->info)
+    return;
+
+  oip = rn->info;
+  route_unlock_node (rn);
+  
+  if (!OSPF_IF_PARAM_CONFIGURED (oip, output_cost_cmd) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, transmit_delay) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, retransmit_interval) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, passive_interface) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, v_hello) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, v_wait) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, priority) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, type) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, auth_simple) &&
+      !OSPF_IF_PARAM_CONFIGURED (oip, auth_type) &&
+      listcount (oip->auth_crypt) == 0)
+    {
+      ospf_del_if_params (oip);
+      rn->info = NULL;
+      route_unlock_node (rn);
+    }
+}
+
+struct ospf_if_params *
+ospf_lookup_if_params (struct interface *ifp, struct in_addr addr)
+{
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = addr;
+
+  rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p);
+  
+  if (rn)
+    {
+      route_unlock_node (rn);
+      return rn->info;
+    }
+
+  return NULL;
+}
+
+struct ospf_if_params *
+ospf_get_if_params (struct interface *ifp, struct in_addr addr)
+{
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = addr;
+
+  rn = route_node_get (IF_OIFS_PARAMS (ifp), (struct prefix*)&p);
+  
+  if (rn->info == NULL)
+    rn->info = ospf_new_if_params ();
+  else
+    route_unlock_node (rn);
+  
+  return rn->info;
+}
+
+void
+ospf_if_update_params (struct interface *ifp, struct in_addr addr)
+{
+  struct route_node *rn;
+  struct ospf_interface *oi;
+  
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      if ((oi = rn->info) == NULL)
+       continue;
+
+      if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &addr))
+       oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4);
+    }
+}
+
+int
+ospf_if_new_hook (struct interface *ifp)
+{
+  int rc = 0;
+
+  ifp->info = XMALLOC (MTYPE_OSPF_IF_INFO, sizeof (struct ospf_if_info));
+  memset (ifp->info, 0, sizeof (struct ospf_if_info));
+  
+  IF_OIFS (ifp) = route_table_init ();
+  IF_OIFS_PARAMS (ifp) = route_table_init ();
+  
+  IF_DEF_PARAMS (ifp) = ospf_new_if_params ();
+  
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay);
+  IF_DEF_PARAMS (ifp)->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT;
+  
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval);
+  IF_DEF_PARAMS (ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT;
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), priority);
+  IF_DEF_PARAMS (ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT;
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), passive_interface);
+  IF_DEF_PARAMS (ifp)->passive_interface = OSPF_IF_ACTIVE;
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
+  IF_DEF_PARAMS (ifp)->v_hello = OSPF_HELLO_INTERVAL_DEFAULT;
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
+  IF_DEF_PARAMS (ifp)->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_simple);
+  memset (IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE);
+  
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_crypt);
+  IF_DEF_PARAMS (ifp)->auth_crypt = list_new ();
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
+  IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET;
+  
+#ifdef HAVE_OPAQUE_LSA
+  rc = ospf_opaque_new_if (ifp);
+#endif /* HAVE_OPAQUE_LSA */
+  return rc;
+}
+
+int
+ospf_if_delete_hook (struct interface *ifp)
+{
+  int rc = 0;
+#ifdef HAVE_OPAQUE_LSA
+  rc = ospf_opaque_del_if (ifp);
+#endif /* HAVE_OPAQUE_LSA */
+  route_table_finish (IF_OIFS (ifp));
+  route_table_finish (IF_OIFS_PARAMS (ifp));
+  XFREE (MTYPE_OSPF_IF_INFO, ifp->info);
+  ifp->info = NULL;
+
+  return rc;
+}
+
+int
+ospf_if_is_enable (struct ospf_interface *oi)
+{
+  if (!if_is_loopback (oi->ifp))
+    if (if_is_up (oi->ifp))
+       return 1;
+
+  return 0;
+}
+
+int
+ospf_if_up (struct ospf_interface *oi)
+{
+  if (oi == NULL)
+    return 0;
+
+  if (oi->type == OSPF_IFTYPE_LOOPBACK)
+    OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd);
+  else
+    {
+      if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+       ospf_if_add_allspfrouters (ospf_top, oi->address, oi->ifp->ifindex);
+      ospf_if_stream_set (oi);
+      OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp);
+    }
+
+  return 1;
+}
+
+int
+ospf_if_down (struct ospf_interface *oi)
+{
+  if (oi == NULL)
+    return 0;
+
+  OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
+  /* Shutdown packet reception and sending */
+  ospf_if_stream_unset (oi);
+  if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+    ospf_if_drop_allspfrouters (ospf_top, oi->address, oi->ifp->ifindex);
+
+
+  return 1;
+}
+
+\f
+/* Virtual Link related functions. */
+
+struct ospf_vl_data *
+ospf_vl_data_new (struct ospf_area *area, struct in_addr vl_peer)
+{
+  struct ospf_vl_data *vl_data;
+
+  vl_data = XMALLOC (MTYPE_OSPF_VL_DATA, sizeof (struct ospf_vl_data));
+  memset (vl_data, 0, sizeof (struct ospf_vl_data));
+
+  vl_data->vl_peer.s_addr = vl_peer.s_addr;
+  vl_data->vl_area_id = area->area_id;
+  vl_data->format = area->format;
+
+  return vl_data;
+}
+
+void
+ospf_vl_data_free (struct ospf_vl_data *vl_data)
+{
+  XFREE (MTYPE_OSPF_VL_DATA, vl_data);
+}
+
+u_int vlink_count = 0;
+
+struct ospf_interface * 
+ospf_vl_new (struct ospf_vl_data *vl_data)
+{
+  struct ospf_interface * voi;
+  struct interface * vi;
+  char   ifname[INTERFACE_NAMSIZ + 1];
+  struct ospf_area *area;
+  struct in_addr area_id;
+  struct connected *co;
+  struct prefix_ipv4 *p;
+  
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_vl_new(): Start");
+  if (vlink_count == OSPF_VL_MAX_COUNT)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_vl_new(): Alarm: "
+                  "cannot create more than OSPF_MAX_VL_COUNT virtual links");
+      return NULL;
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_vl_new(): creating pseudo zebra interface");
+
+  vi = if_create ();
+  co = connected_new ();
+  co->ifp = vi;
+  listnode_add (vi->connected, co);
+
+  p = prefix_ipv4_new ();
+  p->family = AF_INET;
+  p->prefix.s_addr = 0;
+  p->prefixlen = 0;
+  co->address = (struct prefix *)p;
+  
+  voi = ospf_if_new (vi, co->address);
+  if (voi == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_vl_new(): Alarm: OSPF int structure is not created");
+      return NULL;
+    }
+  voi->connected = co;
+  voi->vl_data = vl_data;
+  voi->ifp->mtu = OSPF_VL_MTU;
+  voi->type = OSPF_IFTYPE_VIRTUALLINK;
+
+  sprintf (ifname, "VLINK%d", vlink_count++);
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_vl_new(): Created name: %s", ifname);
+  strncpy (vi->name, ifname, IFNAMSIZ);
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_vl_new(): set if->name to %s", vi->name);
+
+  area_id.s_addr = 0;
+  area = ospf_area_get (area_id, OSPF_AREA_ID_FORMAT_ADDRESS);
+  voi->area = area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_vl_new(): set associated area to the backbone");
+
+  ospf_area_add_if (voi->area, voi);
+
+  ospf_if_stream_set (voi);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_vl_new(): Stop");
+  return voi;
+}
+
+void
+ospf_vl_if_delete (struct ospf_vl_data *vl_data)
+{
+  struct interface *ifp = vl_data->vl_oi->ifp;
+  vl_data->vl_oi->address->u.prefix4.s_addr = 0;
+  vl_data->vl_oi->address->prefixlen = 0;
+  ospf_if_free (vl_data->vl_oi);
+  if_delete (ifp);
+  vlink_count--;
+}
+
+struct ospf_vl_data *
+ospf_vl_lookup (struct ospf_area *area, struct in_addr vl_peer)
+{
+  struct ospf_vl_data *vl_data;
+  listnode node;
+
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    if ((vl_data = getdata (node)) != NULL)
+      if (vl_data->vl_peer.s_addr == vl_peer.s_addr &&
+          IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
+        return vl_data;
+
+  return NULL;
+}
+
+void 
+ospf_vl_shutdown (struct ospf_vl_data *vl_data)
+{
+  struct ospf_interface *oi;
+
+  if ((oi = vl_data->vl_oi) == NULL)
+    return;
+
+  oi->address->u.prefix4.s_addr = 0;
+  oi->address->prefixlen = 0;
+
+  UNSET_FLAG (oi->ifp->flags, IFF_UP);
+  /* OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceDown); */
+  OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
+}
+
+void
+ospf_vl_add (struct ospf_vl_data *vl_data)
+{
+  listnode_add (ospf_top->vlinks, vl_data);
+#ifdef HAVE_SNMP
+  ospf_snmp_vl_add (vl_data);
+#endif /* HAVE_SNMP */
+}
+
+void
+ospf_vl_delete (struct ospf_vl_data *vl_data)
+{
+  ospf_vl_shutdown (vl_data);
+  ospf_vl_if_delete (vl_data);
+
+#ifdef HAVE_SNMP
+  ospf_snmp_vl_delete (vl_data);
+#endif /* HAVE_SNMP */
+  listnode_delete (ospf_top->vlinks, vl_data);
+
+  ospf_vl_data_free (vl_data);
+}
+
+void
+ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v)
+{
+  int changed = 0;
+  struct ospf_interface *voi;
+  listnode node;
+  struct vertex_nexthop *nh;
+  int i;
+  struct router_lsa *rl;
+
+  voi = vl_data->vl_oi;
+
+  if (voi->output_cost != v->distance)
+    {
+      voi->output_cost = v->distance;
+      changed = 1;
+    }
+
+  for (node = listhead (v->nexthop); node; nextnode (node))
+    if ((nh = getdata (node)) != NULL)
+      {
+       vl_data->out_oi = (struct ospf_interface *) nh->oi;
+
+       voi->address->u.prefix4 = vl_data->out_oi->address->u.prefix4;
+       voi->address->prefixlen = vl_data->out_oi->address->prefixlen;
+
+       break; /* We take the first interface. */
+      }
+
+  rl = (struct router_lsa *)v->lsa;
+  
+  for (i = 0; i < ntohs (rl->links); i++)
+    {
+      switch (rl->link[i].type)
+       {
+       case LSA_LINK_TYPE_VIRTUALLINK:
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("found back link through VL");
+       case LSA_LINK_TYPE_TRANSIT:
+       case LSA_LINK_TYPE_POINTOPOINT:
+         vl_data->peer_addr = rl->link[i].link_data;
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("%s peer address is %s\n",
+                      vl_data->vl_oi->ifp->name, inet_ntoa(vl_data->peer_addr));
+         return;
+       }
+    }
+}
+
+
+void
+ospf_vl_up_check (struct ospf_area * area, struct in_addr rid,
+                  struct vertex *v)
+{
+  listnode node;
+  struct ospf_vl_data *vl_data;
+  struct ospf_interface *oi;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    {
+      zlog_info ("ospf_vl_up_check(): Start");
+      zlog_info ("ospf_vl_up_check(): Router ID is %s", inet_ntoa (rid));
+      zlog_info ("ospf_vl_up_check(): Area is %s", inet_ntoa (area->area_id));
+    }
+
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    {
+      if ((vl_data = getdata (node)) == NULL)
+        continue;
+  
+      if (IS_DEBUG_OSPF_EVENT)
+       {
+         zlog_info ("ospf_vl_up_check(): considering VL, name: %s", 
+                    vl_data->vl_oi->ifp->name);
+         zlog_info ("ospf_vl_up_check(): VL area: %s, peer ID: %s", 
+                    inet_ntoa (vl_data->vl_area_id),
+                    inet_ntoa (vl_data->vl_peer));
+       }
+
+      if (IPV4_ADDR_SAME (&vl_data->vl_peer, &rid) &&
+          IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
+        {
+          oi = vl_data->vl_oi;
+          SET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED);
+
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_vl_up_check(): this VL matched");
+
+          if (oi->state == ISM_Down)
+            {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("ospf_vl_up_check(): VL is down, waking it up");
+              SET_FLAG (oi->ifp->flags, IFF_UP);
+              OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp);
+            }
+
+          ospf_vl_set_params (vl_data, v);
+        }
+    }
+}
+
+void
+ospf_vl_unapprove ()
+{
+  listnode node;
+  struct ospf_vl_data *vl_data;
+
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    if ((vl_data = getdata (node)) != NULL)
+      UNSET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED);
+}
+
+void
+ospf_vl_shut_unapproved ()
+{
+  listnode node;
+  struct ospf_vl_data *vl_data;
+
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    if ((vl_data = getdata (node)) != NULL)
+      if (!CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED))
+        ospf_vl_shutdown (vl_data);
+}
+
+int
+ospf_full_virtual_nbrs (struct ospf_area *area)
+{
+  if (IS_DEBUG_OSPF_EVENT)
+    {
+      zlog_info ("counting fully adjacent virtual neighbors in area %s",
+                inet_ntoa (area->area_id));
+      zlog_info ("there are %d of them", area->full_vls);
+    }
+
+  return area->full_vls;
+}
+
+int
+ospf_vls_in_area (struct ospf_area *area)
+{
+  listnode node;
+  struct ospf_vl_data *vl_data;
+  int c = 0;
+
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    if ((vl_data = getdata (node)) != NULL)
+      if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
+        c++;
+
+  return c;
+}
+
+\f
+struct crypt_key *
+ospf_crypt_key_new ()
+{
+  struct crypt_key *ck;
+
+  ck = XMALLOC (MTYPE_OSPF_CRYPT_KEY, sizeof (struct crypt_key));
+  memset (ck, 0, sizeof (struct crypt_key));
+
+  return ck;
+}
+
+void
+ospf_crypt_key_add (list crypt, struct crypt_key *ck)
+{
+  listnode_add (crypt, ck);
+}
+
+struct crypt_key *
+ospf_crypt_key_lookup (list auth_crypt, u_char key_id)
+{
+  listnode node;
+  struct crypt_key *ck;
+
+  for (node = listhead (auth_crypt); node; nextnode (node))
+    {
+      ck = getdata (node);
+      if (ck->key_id == key_id)
+        return ck;
+    }
+
+  return NULL;
+}
+
+int
+ospf_crypt_key_delete (list auth_crypt, u_char key_id)
+{
+  listnode node;
+  struct crypt_key *ck;
+
+  for (node = listhead (auth_crypt); node; nextnode (node))
+    {
+      ck = getdata (node);
+      if (ck->key_id == key_id)
+        {
+          listnode_delete (auth_crypt, ck);
+          return 1;
+        }
+    }
+
+  return 0;
+}
+
+void
+ospf_if_init ()
+{
+  /* Initialize Zebra interface data structure. */
+  if_init ();
+  if_add_hook (IF_NEW_HOOK, ospf_if_new_hook);
+  if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook);
+}
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
new file mode 100644 (file)
index 0000000..6dc01ae
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * OSPF Interface functions.
+ * Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_INTERFACE_H
+#define _ZEBRA_OSPF_INTERFACE_H
+
+#define OSPF_AUTH_SIMPLE_SIZE           8
+#define OSPF_AUTH_MD5_SIZE             16
+
+#define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info))
+#define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params)
+#define IF_OIFS(I)  (IF_OSPF_IF_INFO (I)->oifs)
+#define IF_OIFS_PARAMS(I) (IF_OSPF_IF_INFO (I)->params)
+                           
+#define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config)
+#define OSPF_IF_PARAM(O, P) \
+        (OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\
+                        (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P)
+
+#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1
+#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0
+#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1
+
+struct ospf_if_params
+{
+  DECLARE_IF_PARAM (u_int32_t, transmit_delay); /* Interface Transmisson Delay */
+  DECLARE_IF_PARAM (u_int32_t, output_cost_cmd);/* Command Interface Output Cost */
+  DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */
+  DECLARE_IF_PARAM (u_char, passive_interface);      /* OSPF Interface is passive */
+  DECLARE_IF_PARAM (u_char, priority);               /* OSPF Interface priority */
+  DECLARE_IF_PARAM (u_char, type);                   /* type of interface */
+#define OSPF_IF_ACTIVE                  0
+#define OSPF_IF_PASSIVE                        1
+  
+  DECLARE_IF_PARAM (u_int32_t, v_hello);             /* Hello Interval */
+  DECLARE_IF_PARAM (u_int32_t, v_wait);              /* Router Dead Interval */
+
+  /* Authentication data. */
+  u_char auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1];       /* Simple password. */
+  u_char auth_simple__config:1;
+  
+  DECLARE_IF_PARAM (list, auth_crypt);                 /* List of Auth cryptographic data. */
+  DECLARE_IF_PARAM (int, auth_type);               /* OSPF authentication type */
+};
+
+struct ospf_if_info
+{
+  struct ospf_if_params *def_params;
+  struct route_table *params;
+  struct route_table *oifs;
+};
+
+struct ospf_interface;
+
+struct ospf_vl_data
+{
+  struct in_addr    vl_peer;      /* Router-ID of the peer for VLs. */
+  struct in_addr    vl_area_id;           /* Transit area for this VL. */
+  int format;                      /* area ID format */
+  struct ospf_interface *vl_oi;           /* Interface data structure for the VL. */
+  struct ospf_interface *out_oi;   /* The interface to go out. */
+  struct in_addr    peer_addr;    /* Address used to reach the peer. */
+  u_char flags;
+};
+
+
+#define OSPF_VL_MAX_COUNT 256
+#define OSPF_VL_MTU      1500
+
+#define OSPF_VL_FLAG_APPROVED 0x01
+
+struct crypt_key
+{
+  u_char key_id;
+  u_char auth_key[OSPF_AUTH_MD5_SIZE + 1];
+};
+
+/* OSPF interface structure. */
+struct ospf_interface
+{
+  /* This interface's parent ospf instance. */
+  struct ospf *ospf;
+
+  /* OSPF Area. */
+  struct ospf_area *area;
+
+  /* Interface data from zebra. */
+  struct interface *ifp;
+  struct ospf_vl_data *vl_data;                /* Data for Virtual Link */
+  
+  /* Packet send buffer. */
+  struct ospf_fifo *obuf;              /* Output queue */
+
+  /* OSPF Network Type. */
+  u_char type;
+#define OSPF_IFTYPE_NONE               0
+#define OSPF_IFTYPE_POINTOPOINT                1
+#define OSPF_IFTYPE_BROADCAST          2
+#define OSPF_IFTYPE_NBMA               3
+#define OSPF_IFTYPE_POINTOMULTIPOINT   4
+#define OSPF_IFTYPE_VIRTUALLINK                5
+#define OSPF_IFTYPE_LOOPBACK            6
+#define OSPF_IFTYPE_MAX                        7
+
+  /* State of Interface State Machine. */
+  u_char state;
+
+  struct prefix *address;              /* Interface prefix */
+  struct connected *connected;          /* Pointer to connected */ 
+
+  /* Configured varables. */
+  struct ospf_if_params *params;
+  u_int32_t crypt_seqnum;              /* Cryptographic Sequence Number */ 
+  u_int32_t output_cost;               /* Acutual Interface Output Cost */
+
+  /* Neighbor information. */
+  struct route_table *nbrs;             /* OSPF Neighbor List */
+  struct ospf_neighbor *nbr_self;      /* Neighbor Self */
+#define DR(I)                  ((I)->nbr_self->d_router)
+#define BDR(I)                 ((I)->nbr_self->bd_router)
+#define OPTIONS(I)             ((I)->nbr_self->options)
+#define PRIORITY(I)            ((I)->nbr_self->priority)
+
+  /* List of configured NBMA neighbor. */
+  list nbr_nbma;
+
+  /* self-originated LSAs. */
+  struct ospf_lsa *network_lsa_self;   /* network-LSA. */
+#ifdef HAVE_OPAQUE_LSA
+  list opaque_lsa_self;                        /* Type-9 Opaque-LSAs */
+#endif /* HAVE_OPAQUE_LSA */
+
+  struct route_table *ls_upd_queue;
+
+  list ls_ack;                         /* Link State Acknowledgment list. */
+  
+  struct
+  {
+    list ls_ack;
+    struct in_addr dst;
+  } ls_ack_direct;
+
+  /* Timer values. */
+  u_int32_t v_ls_ack;                  /* Delayed Link State Acknowledgment */
+
+  /* Threads. */
+  struct thread *t_hello;               /* timer */
+  struct thread *t_wait;                /* timer */
+  struct thread *t_ls_ack;              /* timer */
+  struct thread *t_ls_ack_direct;       /* event */
+  struct thread *t_ls_upd_event;        /* event */
+  struct thread *t_network_lsa_self;    /* self-originated network-LSA
+                                           reflesh thread. timer */
+#ifdef HAVE_OPAQUE_LSA
+  struct thread *t_opaque_lsa_self;     /* Type-9 Opaque-LSAs */
+#endif /* HAVE_OPAQUE_LSA */
+
+  int on_write_q;
+  
+  /* Statistics fields. */
+  u_int32_t hello_in;          /* Hello message input count. */
+  u_int32_t hello_out;         /* Hello message output count. */
+  u_int32_t db_desc_in;         /* database desc. message input count. */
+  u_int32_t db_desc_out;        /* database desc. message output count. */
+  u_int32_t ls_req_in;          /* LS request message input count. */
+  u_int32_t ls_req_out;         /* LS request message output count. */
+  u_int32_t ls_upd_in;          /* LS update message input count. */
+  u_int32_t ls_upd_out;         /* LS update message output count. */
+  u_int32_t ls_ack_in;          /* LS Ack message input count. */
+  u_int32_t ls_ack_out;         /* LS Ack message output count. */
+  u_int32_t discarded;         /* discarded input count by error. */
+  u_int32_t state_change;      /* Number of status change. */
+
+  u_int full_nbrs;
+};
+
+/* Prototypes. */
+char *ospf_if_name (struct ospf_interface *);
+struct ospf_interface *ospf_if_new ();
+void ospf_if_cleanup (struct ospf_interface *);
+void ospf_if_free (struct ospf_interface *);
+int ospf_if_up (struct ospf_interface *);
+int ospf_if_down (struct ospf_interface *);
+
+int ospf_if_is_up (struct ospf_interface *);
+struct ospf_interface *ospf_if_lookup_by_name (char *);
+struct ospf_interface *ospf_if_lookup_by_local_addr (struct interface *, struct in_addr);
+struct ospf_interface *ospf_if_lookup_by_prefix (struct prefix_ipv4 *);
+struct ospf_interface *ospf_if_addr_local (struct in_addr src);
+struct ospf_interface *ospf_if_lookup_recv_interface (struct in_addr src);
+struct ospf_interface *ospf_if_is_configured (struct in_addr *);
+
+struct ospf_if_params *ospf_lookup_if_params (struct interface *, struct in_addr);
+struct ospf_if_params *ospf_get_if_params (struct interface *, struct in_addr);
+void ospf_del_if_params (struct ospf_if_params *);
+void ospf_free_if_params (struct interface *, struct in_addr);
+void ospf_if_update_params (struct interface *, struct in_addr);
+
+int ospf_if_new_hook (struct interface *);
+void ospf_if_init ();
+void ospf_if_stream_set (struct ospf_interface *);
+void ospf_if_stream_unset (struct ospf_interface *);
+void ospf_if_reset_variables (struct ospf_interface *);
+int ospf_if_is_enable (struct ospf_interface *);
+int ospf_if_get_output_cost (struct ospf_interface *);
+void ospf_if_recalculate_output_cost (struct interface *);
+
+struct ospf_interface *ospf_vl_new (struct ospf_vl_data *);
+struct ospf_vl_data *ospf_vl_data_new (struct ospf_area *, struct in_addr);
+struct ospf_vl_data *ospf_vl_lookup (struct ospf_area *, struct in_addr);
+void ospf_vl_data_free (struct ospf_vl_data *);
+void ospf_vl_add (struct ospf_vl_data *);
+void ospf_vl_delete (struct ospf_vl_data *);
+void ospf_vl_up_check (struct ospf_area *, struct in_addr, struct vertex *);
+void ospf_vl_unapprove ();
+void ospf_vl_shut_unapproved ();
+int ospf_full_virtual_nbrs (struct ospf_area *);
+int ospf_vls_in_area (struct ospf_area *);
+
+struct crypt_key *ospf_crypt_key_lookup (list, u_char);
+struct crypt_key *ospf_crypt_key_new ();
+void ospf_crypt_key_add (list, struct crypt_key *);
+int ospf_crypt_key_delete (list, u_char key_id);
+
+
+#endif /* _ZEBRA_OSPF_INTERFACE_H */
diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h
new file mode 100644 (file)
index 0000000..b04865a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * OSPF version 2  Interface State Machine.
+ *   From RFC2328 [OSPF Version 2]
+ * Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_ISM_H
+#define _ZEBRA_OSPF_ISM_H
+
+/* OSPF Interface State Machine Status. */
+#define ISM_DependUpon                    0
+#define ISM_Down                          1
+#define ISM_Loopback                      2
+#define ISM_Waiting                       3
+#define ISM_PointToPoint                  4
+#define ISM_DROther                       5
+#define ISM_Backup                        6
+#define ISM_DR                            7
+#define OSPF_ISM_STATE_MAX               8
+
+/* OSPF Interface State Machine Event. */
+#define ISM_NoEvent                       0
+#define ISM_InterfaceUp                   1
+#define ISM_WaitTimer                     2
+#define ISM_BackupSeen                    3
+#define ISM_NeighborChange                4
+#define ISM_LoopInd                       5
+#define ISM_UnloopInd                     6
+#define ISM_InterfaceDown                 7
+#define OSPF_ISM_EVENT_MAX                8
+
+#define OSPF_ISM_WRITE_ON()                                                   \
+      do                                                                      \
+        {                                                                     \
+          if (oi->on_write_q == 0)                                            \
+           {                                                                 \
+              listnode_add (ospf_top->oi_write_q, oi);                        \
+             oi->on_write_q = 1;                                             \
+           }                                                                 \
+         if (ospf_top->t_write == NULL)                                      \
+           ospf_top->t_write =                                               \
+             thread_add_write (master, ospf_write, ospf_top, ospf_top->fd);  \
+        } while (0)
+     
+/* Macro for OSPF ISM timer turn on. */
+#define OSPF_ISM_TIMER_ON(T,F,V) \
+      if (!(T)) \
+        (T) = thread_add_timer (master, (F), oi, (V))
+
+/* Macro for OSPF ISM timer turn off. */
+#define OSPF_ISM_TIMER_OFF(X) \
+      if (X) \
+        { \
+          thread_cancel (X); \
+          (X) = NULL; \
+        }
+
+/* Macro for OSPF schedule event. */
+#define OSPF_ISM_EVENT_SCHEDULE(I,E) \
+      thread_add_event (master, ospf_ism_event, (I), (E))
+
+/* Macro for OSPF execute event. */
+#define OSPF_ISM_EVENT_EXECUTE(I,E) \
+      thread_execute (master, ospf_ism_event, (I), (E))
+
+/* Prototypes. */
+int ospf_ism_event (struct thread *);
+void ism_change_status (struct ospf_interface *, int);
+int ospf_hello_timer (struct thread *thread);
+
+#endif /* _ZEBRA_OSPF_ISM_H */
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
new file mode 100644 (file)
index 0000000..5b63a76
--- /dev/null
@@ -0,0 +1,3315 @@
+/*
+ * OSPF Link State Advertisement
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h"         /* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+
+\f
+u_int32_t
+get_metric (u_char *metric)
+{
+  u_int32_t m;
+  m = metric[0];
+  m = (m << 8) + metric[1];
+  m = (m << 8) + metric[2];
+  return m;
+}
+
+\f
+struct timeval
+tv_adjust (struct timeval a)
+{
+  while (a.tv_usec >= 1000000)
+    {
+      a.tv_usec -= 1000000;
+      a.tv_sec++;
+    }
+
+  while (a.tv_usec < 0)
+    {
+      a.tv_usec += 1000000;
+      a.tv_sec--;
+    }
+
+  return a;
+}
+
+int
+tv_ceil (struct timeval a)
+{
+  a = tv_adjust (a);
+
+  return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec);
+}
+
+int
+tv_floor (struct timeval a)
+{
+  a = tv_adjust (a);
+
+  return a.tv_sec;
+}
+
+struct timeval
+int2tv (int a)
+{
+  struct timeval ret;
+
+  ret.tv_sec = a;
+  ret.tv_usec = 0;
+
+  return ret;
+}
+
+struct timeval
+tv_add (struct timeval a, struct timeval b)
+{
+  struct timeval ret;
+
+  ret.tv_sec = a.tv_sec + b.tv_sec;
+  ret.tv_usec = a.tv_usec + b.tv_usec;
+
+  return tv_adjust (ret);
+}
+
+struct timeval
+tv_sub (struct timeval a, struct timeval b)
+{
+  struct timeval ret;
+
+  ret.tv_sec = a.tv_sec - b.tv_sec;
+  ret.tv_usec = a.tv_usec - b.tv_usec;
+
+  return tv_adjust (ret);
+}
+
+int
+tv_cmp (struct timeval a, struct timeval b)
+{
+  return (a.tv_sec == b.tv_sec ?
+         a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
+}
+
+int
+ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
+{
+  struct timeval delta, now;
+  int delay = 0;
+
+  gettimeofday (&now, NULL);
+  delta = tv_sub (now, lsa->tv_orig);
+
+  if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0)
+    {
+      delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta));
+
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+        zlog_info ("LSA[Type%d:%s]: Refresh timer delay %d seconds",
+                  lsa->data->type, inet_ntoa (lsa->data->id), delay);
+
+      assert (delay > 0);
+    }
+
+  return delay;
+}
+
+\f
+int
+get_age (struct ospf_lsa *lsa)
+{
+  int age;
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (now, lsa->tv_recv));
+
+  return age;
+}
+
+\f
+/* Fletcher Checksum -- Refer to RFC1008. */
+#define MODX                 4102
+#define LSA_CHECKSUM_OFFSET    15
+
+u_int16_t
+ospf_lsa_checksum (struct lsa_header *lsa)
+{
+  u_char *sp, *ep, *p, *q;
+  int c0 = 0, c1 = 0;
+  int x, y;
+  u_int16_t length;
+
+  lsa->checksum = 0;
+  length = ntohs (lsa->length) - 2;
+  sp = (char *) &lsa->options;
+
+  for (ep = sp + length; sp < ep; sp = q)
+    {
+      q = sp + MODX;
+      if (q > ep)
+        q = ep;
+      for (p = sp; p < q; p++)
+        {
+          c0 += *p;
+          c1 += c0;
+        }
+      c0 %= 255;
+      c1 %= 255;
+    }
+
+  x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
+  if (x <= 0)
+    x += 255;
+  y = 510 - c0 - x;
+  if (y > 255)
+    y -= 255;
+
+  /* take care endian issue. */
+  lsa->checksum = htons ((x << 8) + y);
+
+  return (lsa->checksum);
+}
+
+
+\f
+/* Create OSPF LSA. */
+struct ospf_lsa *
+ospf_lsa_new ()
+{
+  struct ospf_lsa *new;
+
+  new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa));
+  memset (new, 0, sizeof (struct ospf_lsa));
+
+  new->flags = 0;
+  new->lock = 1;
+  new->retransmit_counter = 0;
+  gettimeofday (&new->tv_recv, NULL);
+  new->tv_orig = new->tv_recv;
+  new->refresh_list = -1;
+  
+  return new;
+}
+
+/* Duplicate OSPF LSA. */
+struct ospf_lsa *
+ospf_lsa_dup (struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new;
+
+  if (lsa == NULL)
+    return NULL;
+
+  new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa));
+
+  memcpy (new, lsa, sizeof (struct ospf_lsa));
+  UNSET_FLAG (new->flags, OSPF_LSA_DISCARD);
+  new->lock = 1;
+  new->retransmit_counter = 0;
+  new->data = ospf_lsa_data_dup (lsa->data);
+
+  return new;
+}
+
+/* Free OSPF LSA. */
+void
+ospf_lsa_free (struct ospf_lsa *lsa)
+{
+  assert (lsa->lock == 0);
+  
+  if (IS_DEBUG_OSPF (lsa, LSA))
+    zlog_info ("LSA: freed %p", lsa);
+
+  /* Delete LSA data. */
+  if (lsa->data != NULL)
+    ospf_lsa_data_free (lsa->data);
+
+  assert (lsa->refresh_list < 0);
+
+  memset (lsa, 0, sizeof (struct ospf_lsa)); 
+  XFREE (MTYPE_OSPF_LSA, lsa);
+}
+
+/* Lock LSA. */
+struct ospf_lsa *
+ospf_lsa_lock (struct ospf_lsa *lsa)
+{
+  lsa->lock++;
+  return lsa;
+}
+
+/* Unlock LSA. */
+void
+ospf_lsa_unlock (struct ospf_lsa *lsa)
+{
+  /* This is sanity check. */
+  if (!lsa)
+    return;
+  
+  lsa->lock--;
+
+  assert (lsa->lock >= 0);
+
+  if (lsa->lock == 0)
+    {
+      assert (CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD));
+      ospf_lsa_free (lsa);
+    }
+}
+
+/* Check discard flag. */
+void
+ospf_lsa_discard (struct ospf_lsa *lsa)
+{
+  if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD))
+    {
+      SET_FLAG (lsa->flags, OSPF_LSA_DISCARD);
+      ospf_lsa_unlock (lsa);
+    }
+}
+
+/* Create LSA data. */
+struct lsa_header *
+ospf_lsa_data_new (size_t size)
+{
+  struct lsa_header *new;
+
+  new = (struct lsa_header *) XMALLOC (MTYPE_OSPF_LSA_DATA, size);
+  memset (new, 0, size);
+
+  return new;
+}
+
+/* Duplicate LSA data. */
+struct lsa_header *
+ospf_lsa_data_dup (struct lsa_header *lsah)
+{
+  struct lsa_header *new;
+
+  new = ospf_lsa_data_new (ntohs (lsah->length));
+  memcpy (new, lsah, ntohs (lsah->length));
+
+  return new;
+}
+
+/* Free LSA data. */
+void
+ospf_lsa_data_free (struct lsa_header *lsah)
+{
+  if (IS_DEBUG_OSPF (lsa, LSA))
+    zlog_info ("LSA[Type%d:%s]: data freed %p",
+              lsah->type, inet_ntoa (lsah->id), lsah);
+
+  XFREE (MTYPE_OSPF_LSA_DATA, lsah);
+}
+
+\f
+/* LSA general functions. */
+
+const char *
+dump_lsa_key (struct ospf_lsa *lsa)
+{
+  static char buf[] = {
+    "Type255,id(255.255.255.255),ar(255.255.255.255)",
+  };
+  struct lsa_header *lsah;
+
+  if (lsa != NULL && (lsah = lsa->data) != NULL)
+    {
+      char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN];
+      strcpy (id, inet_ntoa (lsah->id));
+      strcpy (ar, inet_ntoa (lsah->adv_router));
+
+      sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar);
+    }
+  else
+    strcpy (buf, "NULL");
+
+  return buf;
+}
+
+u_int32_t
+lsa_seqnum_increment (struct ospf_lsa *lsa)
+{
+  u_int32_t seqnum;
+
+  seqnum = ntohl (lsa->data->ls_seqnum) + 1;
+
+  return htonl (seqnum);
+}
+
+void
+lsa_header_set (struct stream *s, u_char options,
+               u_char type, struct in_addr id)
+{
+  struct lsa_header *lsah;
+
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsah->ls_age = htons (0);
+  lsah->options = options;
+  lsah->type = type;
+  lsah->id = id;
+  lsah->adv_router = ospf_top->router_id;
+  lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER);
+
+  ospf_output_forward (s, OSPF_LSA_HEADER_SIZE);
+}
+\f
+/* router-LSA related functions. */
+/* Get router-LSA flags. */
+u_char
+router_lsa_flags (struct ospf_area *area)
+{
+  u_char flags;
+
+  flags = ospf_top->flags;
+
+  /* Set virtual link flag. */
+  if (ospf_full_virtual_nbrs (area))
+    SET_FLAG (flags, ROUTER_LSA_VIRTUAL);
+  else
+    /* Just sanity check */
+    UNSET_FLAG (flags, ROUTER_LSA_VIRTUAL);
+
+  /* Set Shortcut ABR behabiour flag. */
+  UNSET_FLAG (flags, ROUTER_LSA_SHORTCUT);
+  if (ospf_top->abr_type == OSPF_ABR_SHORTCUT)
+    if (!OSPF_IS_AREA_BACKBONE (area))
+      if ((area->shortcut_configured == OSPF_SHORTCUT_DEFAULT &&
+          !ospf_top->backbone) ||
+         area->shortcut_configured == OSPF_SHORTCUT_ENABLE)
+       SET_FLAG (flags, ROUTER_LSA_SHORTCUT);
+
+  /* ASBR can't exit in stub area. */
+  if (area->external_routing == OSPF_AREA_STUB)
+    UNSET_FLAG (flags, OSPF_FLAG_ASBR);
+
+  return flags;
+}
+
+/* Lookup neighbor other than myself.
+   And check neighbor count,
+   Point-to-Point link must have only 1 neighbor. */
+struct ospf_neighbor *
+ospf_nbr_lookup_ptop (struct route_table *nbrs, struct in_addr router_id)
+{
+  struct route_node *rn;
+  struct ospf_neighbor *nbr = NULL;
+
+  /* Search neighbor, there must be one of two nbrs. */
+  for (rn = route_top (nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info) != NULL)
+      /* Ignore myself. */
+      if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf_top->router_id))
+       if (nbr->state == NSM_Full)
+         break;
+
+  /* PtoP link must have only 1 neighbor. */
+  if (ospf_nbr_count (nbrs, 0) > 1)
+    zlog_warn ("Point-to-Point link has more than 1 neighobrs.");
+
+  return nbr;
+}
+
+/* Set a link information. */
+void
+link_info_set (struct stream *s, struct in_addr id,
+              struct in_addr data, u_char type, u_char tos, u_int16_t cost)
+{
+  /* TOS based routing is not supported. */
+  stream_put_ipv4 (s, id.s_addr);              /* Link ID. */
+  stream_put_ipv4 (s, data.s_addr);            /* Link Data. */
+  stream_putc (s, type);                       /* Link Type. */
+  stream_putc (s, tos);                                /* TOS = 0. */
+  stream_putw (s, cost);                       /* Link Cost. */
+}
+
+/* Describe Point-to-Point link. */
+int
+lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi)
+{
+  int links = 0;
+  struct ospf_neighbor *nbr;
+  struct in_addr id, mask;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Set link Point-to-Point");
+
+  if ((nbr = ospf_nbr_lookup_ptop (oi->nbrs, ospf_top->router_id)))
+    if (nbr->state == NSM_Full)
+      {
+       /* For unnumbered point-to-point networks, the Link Data field
+          should specify the interface's MIB-II ifIndex value. */
+       link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+                      LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost);
+       links++;
+      }
+
+  if (oi->connected->destination != NULL)
+    {
+      /* Option 1:
+        link_type = LSA_LINK_TYPE_STUB;
+        link_id = nbr->address.u.prefix4;
+        link_data.s_addr = 0xffffffff;
+        link_cost = o->output_cost; */
+      
+      id.s_addr = oi->connected->destination->u.prefix4.s_addr;
+      mask.s_addr = 0xffffffff;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+    }
+  else
+    {
+       /* Option 2:  We need to include link to a stub
+        network regardless of the state of the neighbor */
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+    }
+  links++;
+
+  return links;
+}
+
+/* Describe Broadcast Link. */
+int
+lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct ospf_neighbor *dr;
+  struct in_addr id, mask;
+
+  /* Describe Type 3 Link. */
+  if (oi->state == ISM_Waiting)
+    {
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+      return 1;
+    }
+
+  dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi));
+  /* Describe Type 2 link. */
+  if (dr && (dr->state == NSM_Full ||
+            IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) &&
+      ospf_nbr_count (oi->nbrs, NSM_Full) > 0)
+    {
+      link_info_set (s, DR (oi), oi->address->u.prefix4,
+                    LSA_LINK_TYPE_TRANSIT, 0, oi->output_cost);
+    }
+  /* Describe type 3 link. */
+  else
+    {
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+    }
+  return 1;
+}
+
+int
+lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct in_addr id, mask;
+
+  /* Describe Type 3 Link. */
+  if (oi->state != ISM_Loopback)
+    return 0;
+
+  mask.s_addr = 0xffffffff;
+  id.s_addr = oi->address->u.prefix4.s_addr;
+  link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+  return 1;
+}
+
+/* Describe Virtual Link. */
+int
+lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct ospf_neighbor *nbr;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Set link type VL, state %d", oi->state);
+
+  if (oi->state == ISM_PointToPoint)
+    if ((nbr = ospf_nbr_lookup_ptop (oi->nbrs, ospf_top->router_id)))
+      if (nbr->state == NSM_Full)
+       {
+         link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+                        LSA_LINK_TYPE_VIRTUALLINK, 0, oi->output_cost);
+         return 1;
+       }
+
+  return 0;
+}
+
+#define lsa_link_nbma_set(S,O)  lsa_link_broadcast_set (S, O)
+
+/* Set router-LSA link information. */
+int
+router_lsa_link_set (struct stream *s, struct ospf_area *area)
+{
+  listnode node;
+  int links = 0;
+
+  for (node = listhead (area->oiflist); node; node = nextnode (node))
+    {
+      struct ospf_interface *oi = node->data;
+      struct interface *ifp = oi->ifp;
+
+      /* Check interface is up, OSPF is enable. */
+      if (if_is_up (ifp))
+       {
+         if (oi->state != ISM_Down)
+           {
+             /* Describe each link. */
+             switch (oi->type)
+               {
+               case OSPF_IFTYPE_POINTOPOINT:
+                 links += lsa_link_ptop_set (s, oi);
+                 break;
+               case OSPF_IFTYPE_BROADCAST:
+                 links += lsa_link_broadcast_set (s, oi);
+                 break;
+               case OSPF_IFTYPE_NBMA:
+                 links += lsa_link_nbma_set (s, oi);
+                 break;
+               case OSPF_IFTYPE_POINTOMULTIPOINT:
+                 /* Not supproted yet. */
+                 break;
+               case OSPF_IFTYPE_VIRTUALLINK:
+                 links += lsa_link_virtuallink_set (s, oi);
+                 break;
+               case OSPF_IFTYPE_LOOPBACK:
+                 links += lsa_link_loopback_set (s, oi); 
+               }
+           }
+       }
+    }
+
+  return links;
+}
+
+/* Set router-LSA body. */
+void
+ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area)
+{
+  unsigned long putp;
+  u_int16_t cnt;
+
+  /* Set flags. */
+  stream_putc (s, router_lsa_flags (area));
+
+  /* Set Zero fields. */
+  stream_putc (s, 0);
+
+  /* Keep pointer to # links. */
+  putp = s->putp;
+
+  /* Forward word */
+  stream_putw(s, 0);
+
+  /* Set all link information. */
+  cnt = router_lsa_link_set (s, area);
+
+  /* Set # of links here. */
+  stream_putw_at (s, putp, cnt);
+}
+
+/* Create new router-LSA. */
+struct ospf_lsa *
+ospf_router_lsa_new (struct ospf_area *area)
+{
+  struct stream *s;
+  struct lsa_header *lsah;
+  struct ospf_lsa *new;
+  int length;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Create router-LSA instance");
+
+  /* Create a stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+#ifdef HAVE_NSSA
+  /* Set LSA common header fields. */
+  lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_NSSA_GET (area),
+                 OSPF_ROUTER_LSA, ospf_top->router_id);
+#else /* ! HAVE_NSSA */
+  /* Set LSA common header fields. */
+  lsa_header_set (s, LSA_OPTIONS_GET (area),
+                 OSPF_ROUTER_LSA, ospf_top->router_id);
+#endif /* HAVE_NSSA */
+
+  /* Set router-LSA body fields. */
+  ospf_router_lsa_body_set (s, area);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Now, create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA data to store, discard stream. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate Router-LSA. */
+struct ospf_lsa *
+ospf_router_lsa_originate (struct ospf_area *area)
+{
+  struct ospf_lsa *new;
+
+  /* Create new router-LSA instance. */
+  new = ospf_router_lsa_new (area);
+
+  /* Sanity check. */
+  if (new->data->adv_router.s_addr == 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("LSA[Type1]: AdvRouter is 0, discard");
+      ospf_lsa_discard (new);
+      return NULL;
+    }
+
+  /* Install LSA to LSDB. */
+  new = ospf_lsa_install (NULL, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate router-LSA %p",
+                new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+/* Refresh router-LSA. */
+struct ospf_lsa *
+ospf_router_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_area *area = lsa->area;
+  struct ospf_lsa *new;
+
+  /* Sanity check. */
+  assert (lsa->data);
+
+  /* Delete LSA from neighbor retransmit-list. */
+  ospf_ls_retransmit_delete_nbr_all (area, lsa);
+
+  /* Create new router-LSA instance. */
+  new = ospf_router_lsa_new (area);
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  ospf_lsa_install (NULL, new);
+
+  /* Flood LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: router-LSA refresh",
+                new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return NULL;
+}
+
+int
+ospf_router_lsa_timer (struct thread *t)
+{
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[router-LSA]: (router-LSA Refresh expire)");
+
+  area = THREAD_ARG (t);
+  area->t_router_lsa_self = NULL;
+
+  /* Now refresh router-LSA. */
+  if (area->router_lsa_self)
+    ospf_router_lsa_refresh (area->router_lsa_self);
+  /* Newly originate router-LSA. */
+  else
+    ospf_router_lsa_originate (area);
+
+  return 0;
+}
+
+void
+ospf_router_lsa_timer_add (struct ospf_area *area)
+{
+  /* Keep area's self-originated router-LSA. */
+  struct ospf_lsa *lsa = area->router_lsa_self;
+
+  /* Cancel previously scheduled router-LSA timer. */
+  if (area->t_router_lsa_self)
+    if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+      zlog_info ("LSA[Type1]: Cancel previous router-LSA timer");
+
+  OSPF_TIMER_OFF (area->t_router_lsa_self);
+
+  /* If router-LSA is originated previously, check the interval time. */
+  if (lsa)
+    {
+      int delay;
+      if ((delay = ospf_lsa_refresh_delay (lsa)) > 0)
+        {
+         OSPF_AREA_TIMER_ON (area->t_router_lsa_self,
+                             ospf_router_lsa_timer, delay);
+         return;
+        }
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Scheduling router-LSA origination right away");
+
+  /* Immediately refresh router-LSA. */
+  OSPF_AREA_TIMER_ON (area->t_router_lsa_self, ospf_router_lsa_timer, 0);
+}
+
+int
+ospf_router_lsa_update_timer (struct thread *t)
+{
+  listnode node;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("Timer[router-LSA Update]: (timer expire)");
+
+  ospf_top->t_router_lsa_update = NULL;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = getdata (node);
+      struct ospf_lsa *lsa = area->router_lsa_self;
+      struct router_lsa *rl;
+      char *area_str;
+
+      /* Keep Area ID string. */
+      area_str = AREA_NAME (area);
+
+      /* If LSA not exist in this Area, originate new. */
+      if (lsa == NULL)
+        {
+         if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+           zlog_info("LSA[Type1]: Create router-LSA for Area %s", area_str);
+
+         ospf_router_lsa_originate (area);
+        }
+      /* If router-ID is changed, Link ID must change.
+        First flush old LSA, then originate new. */
+      else if (!IPV4_ADDR_SAME (&lsa->data->id, &ospf_top->router_id))
+       {
+         if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+           zlog_info("LSA[Type%d:%s]: Refresh router-LSA for Area %s",
+                     lsa->data->type, inet_ntoa (lsa->data->id), area_str);
+         ospf_lsa_flush_area (lsa, area);
+         ospf_lsa_unlock (area->router_lsa_self);
+         area->router_lsa_self = NULL;
+
+         /* Refresh router-LSA, (not install) and flood through area. */
+         ospf_router_lsa_timer_add (area);
+       }
+      else
+       {
+         rl = (struct router_lsa *) lsa->data;
+         /* Refresh router-LSA, (not install) and flood through area. */
+         if (rl->flags != ospf_top->flags)
+           ospf_router_lsa_timer_add (area);
+       }
+    }
+
+  return 0;
+}
+
+\f
+/* network-LSA related functions. */
+/* Originate Network-LSA. */
+void
+ospf_network_lsa_body_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct in_addr mask;
+  struct route_node *rn;
+  struct ospf_neighbor *nbr;
+
+  masklen2ip (oi->address->prefixlen, &mask);
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* The network-LSA lists those routers that are fully adjacent to
+    the Designated Router; each fully adjacent router is identified by
+    its OSPF Router ID.  The Designated Router includes itself in this
+    list. RFC2328, Section 12.4.2 */
+
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info) != NULL)
+      if (nbr->state == NSM_Full || nbr == oi->nbr_self)
+       stream_put_ipv4 (s, nbr->router_id.s_addr);
+}
+
+struct ospf_lsa *
+ospf_network_lsa_new (struct ospf_interface *oi)
+{
+  struct stream *s;
+  struct ospf_lsa *new;
+  struct lsa_header *lsah;
+  int length;
+
+  /* If there are no neighbours on this network (the net is stub),
+     the router does not originate network-LSA (see RFC 12.4.2) */
+  if (oi->full_nbrs == 0)
+    return NULL;
+  
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type2]: Create network-LSA instance");
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsa_header_set (s, (OPTIONS (oi) | LSA_OPTIONS_GET (oi->area)),
+                 OSPF_NETWORK_LSA, DR (oi));
+
+  /* Set network-LSA body fields. */
+  ospf_network_lsa_body_set (s, oi);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = oi->area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA to store. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate network-LSA. */
+struct ospf_lsa *
+ospf_network_lsa_originate (struct ospf_interface *oi)
+{
+  struct ospf_lsa *new;
+
+  /* Create new network-LSA instance. */
+  new = ospf_network_lsa_new (oi);
+  if (new == NULL)
+    return NULL;
+
+  /* Install LSA to LSDB. */
+  new = ospf_lsa_install (oi, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (oi->area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate network-LSA %p",
+                new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+int
+ospf_network_lsa_refresh (struct ospf_lsa *lsa, struct ospf_interface *oi)
+{
+  struct ospf_area *area = lsa->area;
+  struct ospf_lsa *new;
+
+  assert (lsa->data);
+
+  /* Delete LSA from neighbor retransmit-list. */
+  ospf_ls_retransmit_delete_nbr_all (area, lsa);
+
+  /* Create new network-LSA instance. */
+  new = ospf_network_lsa_new (oi);
+  if (new == NULL)
+    return -1;
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  ospf_lsa_install (oi, new);
+
+  /* Flood LSA through aera. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: network-LSA refresh",
+                new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return 0;
+}
+
+int
+ospf_network_lsa_refresh_timer (struct thread *t)
+{
+  struct ospf_interface *oi;
+
+  oi = THREAD_ARG (t);
+  oi->t_network_lsa_self = NULL;
+
+  if (oi->network_lsa_self)
+    /* Now refresh network-LSA. */
+    ospf_network_lsa_refresh (oi->network_lsa_self, oi);
+  else
+    /* Newly create network-LSA. */
+    ospf_network_lsa_originate (oi);
+
+  return 0;
+}
+
+void
+ospf_network_lsa_timer_add (struct ospf_interface *oi)
+{
+  /* Keep interface's self-originated network-LSA. */
+  struct ospf_lsa *lsa = oi->network_lsa_self;
+
+  /* Cancel previously schedules network-LSA timer. */
+  if (oi->t_network_lsa_self)
+    if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+      zlog_info ("LSA[Type2]: Cancel previous network-LSA timer");
+  OSPF_TIMER_OFF (oi->t_network_lsa_self);
+
+  /* If network-LSA is originated previously, check the interval time. */
+  if (lsa)
+    {
+      int delay;
+      if ((delay = ospf_lsa_refresh_delay (lsa)) > 0)
+        {
+          oi->t_network_lsa_self =
+            thread_add_timer (master, ospf_network_lsa_refresh_timer,
+                             oi, delay);
+          return;
+        }
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("Scheduling network-LSA origination right away");
+
+  /* Immediately refresh network-LSA. */
+  oi->t_network_lsa_self =
+    thread_add_event (master, ospf_network_lsa_refresh_timer, oi, 0);
+}
+
+\f
+void
+stream_put_ospf_metric (struct stream *s, u_int32_t metric_value)
+{
+  u_int32_t metric;
+  char *mp;
+
+  /* Put 0 metric. TOS metric is not supported. */
+  metric = htonl (metric_value);
+  mp = (char *) &metric;
+  mp++;
+  stream_put (s, mp, 3);
+}
+
+/* summary-LSA related functions. */
+void
+ospf_summary_lsa_body_set (struct stream *s, struct prefix *p,
+                          u_int32_t metric)
+{
+  struct in_addr mask;
+
+  masklen2ip (p->prefixlen, &mask);
+
+  /* Put Network Mask. */
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* Set # TOS. */
+  stream_putc (s, (u_char) 0);
+
+  /* Set metric. */
+  stream_put_ospf_metric (s, metric);
+}
+
+struct ospf_lsa *
+ospf_summary_lsa_new (struct ospf_area *area, struct prefix *p,
+                     u_int32_t metric, struct in_addr id)
+{
+  struct stream *s;
+  struct ospf_lsa *new;
+  struct lsa_header *lsah;
+  int length;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type3]: Create summary-LSA instance");
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_SUMMARY_LSA, id);
+
+  /* Set summary-LSA body fields. */
+  ospf_summary_lsa_body_set (s, p, metric);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA to store. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate Summary-LSA. */
+struct ospf_lsa *
+ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, 
+                           struct ospf_area *area)
+{
+  struct ospf_lsa *new;
+  struct in_addr id;
+  
+  id = ospf_lsa_unique_id (area->lsdb, OSPF_SUMMARY_LSA, p);
+
+  /* Create new summary-LSA instance. */
+  new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id);
+
+  /* Instlal LSA to LSDB. */
+  new = ospf_lsa_install (NULL, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate summary-LSA %p",
+                new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+struct ospf_lsa*
+ospf_summary_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new;
+  struct summary_lsa *sl;
+  struct prefix p;
+  
+  /* Sanity check. */
+  assert (lsa->data);
+
+  sl = (struct summary_lsa *)lsa->data;
+  p.prefixlen = ip_masklen (sl->mask);
+  new = ospf_summary_lsa_new (lsa->area, &p, GET_METRIC (sl->metric),
+                             sl->header.id);
+
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+  
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new->data);
+
+  ospf_lsa_install (NULL, new);
+  
+  /* Flood LSA through AS. */
+  ospf_flood_through_area (new->area, NULL, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: summary-LSA refresh",
+                new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+  
+  return new;
+}
+
+\f
+/* summary-ASBR-LSA related functions. */
+void
+ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p,
+                               u_int32_t metric)
+{
+  struct in_addr mask;
+
+  masklen2ip (p->prefixlen, &mask);
+
+  /* Put Network Mask. */
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* Set # TOS. */
+  stream_putc (s, (u_char) 0);
+
+  /* Set metric. */
+  stream_put_ospf_metric (s, metric);
+}
+
+struct ospf_lsa *
+ospf_summary_asbr_lsa_new (struct ospf_area *area, struct prefix *p,
+                          u_int32_t metric, struct in_addr id)
+{
+  struct stream *s;
+  struct ospf_lsa *new;
+  struct lsa_header *lsah;
+  int length;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type3]: Create summary-LSA instance");
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_ASBR_SUMMARY_LSA, id);
+
+  /* Set summary-LSA body fields. */
+  ospf_summary_asbr_lsa_body_set (s, p, metric);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA to store. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate summary-ASBR-LSA. */
+struct ospf_lsa *
+ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, 
+                                struct ospf_area *area)
+{
+  struct ospf_lsa *new;
+  struct in_addr id;
+  
+  id = ospf_lsa_unique_id (area->lsdb, OSPF_ASBR_SUMMARY_LSA, p);
+
+  /* Create new summary-LSA instance. */
+  new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id);
+
+  /* Install LSA to LSDB. */
+  new = ospf_lsa_install (NULL, new);
+  
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p",
+                new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+struct ospf_lsa*
+ospf_summary_asbr_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new;
+  struct summary_lsa *sl;
+  struct prefix p;
+
+  /* Sanity check. */
+  assert (lsa->data);
+
+  sl = (struct summary_lsa *)lsa->data;
+  p.prefixlen = ip_masklen (sl->mask);
+  new = ospf_summary_asbr_lsa_new (lsa->area, &p, GET_METRIC (sl->metric),
+                                  sl->header.id);
+  
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+  
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new->data);
+
+  ospf_lsa_install (NULL, new);
+  
+  /* Flood LSA through area. */
+  ospf_flood_through_area (new->area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: summary-ASBR-LSA refresh",
+                new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+/* AS-external-LSA related functions. */
+
+/* Get nexthop for AS-external-LSAs.  Return nexthop if its interface
+   is connected, else 0*/
+struct in_addr
+ospf_external_lsa_nexthop_get (struct in_addr nexthop)
+{
+  struct in_addr fwd;
+  struct prefix nh;
+  /* struct route_node *rn; */
+  listnode n1;
+
+  fwd.s_addr = 0;
+
+  if (!nexthop.s_addr)
+    return fwd;
+
+  /* Check whether nexthop is covered by OSPF network. */
+  nh.family = AF_INET;
+  nh.u.prefix4 = nexthop;
+  nh.prefixlen = IPV4_MAX_BITLEN;
+
+  for (n1 = listhead (ospf_top->oiflist); n1; nextnode (n1))
+    {
+      struct ospf_interface *oi = getdata (n1);
+
+      if (if_is_up (oi->ifp))
+       if (oi->address->family == AF_INET)
+         if (prefix_match (oi->address, &nh))
+           return nexthop;
+    }
+
+  return fwd;
+}
+
+#ifdef HAVE_NSSA
+/* NSSA-external-LSA related functions. */
+
+/* Get 1st IP connection for Forward Addr */
+          
+struct in_addr
+ospf_get_ip_from_ifp (struct ospf_interface *oi)
+{
+  struct in_addr fwd;
+
+  fwd.s_addr = 0;
+
+  if (if_is_up (oi->ifp))
+    return oi->address->u.prefix4;
+  
+  return fwd;
+}
+
+/* Get 1st IP connection for Forward Addr */
+struct in_addr
+ospf_get_nssa_ip (void)
+{
+  struct in_addr fwd;
+  listnode n1;
+
+  fwd.s_addr = 0;
+
+
+  for (n1 = listhead (ospf_top->oiflist); n1; nextnode (n1))
+    {
+      struct ospf_interface *oi = getdata (n1);
+
+      if (if_is_up (oi->ifp))
+       if (oi->area->external_routing == OSPF_AREA_NSSA)
+         if (oi->address && oi->address->family == AF_INET)
+           return (oi->address->u.prefix4 );
+    }
+
+  return fwd;
+}
+#endif /* HAVE_NSSA */
+\f
+#define DEFAULT_DEFAULT_METRIC              20
+#define DEFAULT_DEFAULT_ORIGINATE_METRIC     10
+#define DEFAULT_DEFAULT_ALWAYS_METRIC        1
+
+#define DEFAULT_METRIC_TYPE                 EXTERNAL_METRIC_TYPE_2
+
+int
+metric_type (u_char src)
+{
+  return (ospf_top->dmetric[src].type < 0 ?
+         DEFAULT_METRIC_TYPE : ospf_top->dmetric[src].type);
+}
+
+int
+metric_value (u_char src)
+{
+  if (ospf_top->dmetric[src].value < 0)
+    {
+      if (src == DEFAULT_ROUTE)
+       {
+         if (ospf_top->default_originate == DEFAULT_ORIGINATE_ZEBRA)
+           return DEFAULT_DEFAULT_ORIGINATE_METRIC;
+         else
+           return DEFAULT_DEFAULT_ALWAYS_METRIC;
+       }
+      else if (ospf_top->default_metric < 0)
+       return DEFAULT_DEFAULT_METRIC;
+      else
+       return ospf_top->default_metric;
+    }
+
+  return ospf_top->dmetric[src].value;
+}
+
+/* Set AS-external-LSA body. */
+void
+ospf_external_lsa_body_set (struct stream *s, struct external_info *ei)
+{
+  struct prefix_ipv4 *p = &ei->p;
+  struct in_addr mask, fwd_addr;
+  u_int32_t mvalue;
+  int mtype;
+  int type;
+
+  /* Put Network Mask. */
+  masklen2ip (p->prefixlen, &mask);
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* If prefix is default, specify DEFAULT_ROUTE. */
+  type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
+  
+  mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ?
+    ROUTEMAP_METRIC_TYPE (ei) : metric_type (type);
+
+  mvalue = (ROUTEMAP_METRIC (ei) != -1) ?
+    ROUTEMAP_METRIC (ei) : metric_value (type);
+
+  /* Put type of external metric. */
+  stream_putc (s, (mtype == EXTERNAL_METRIC_TYPE_2 ? 0x80 : 0));
+
+  /* Put 0 metric. TOS metric is not supported. */
+  stream_put_ospf_metric (s, mvalue);
+  
+  /* Get forwarding address to nexthop if on the Connection List, else 0. */
+  fwd_addr = ospf_external_lsa_nexthop_get (ei->nexthop);
+
+  /* Put forwarding address. */
+  stream_put_ipv4 (s, fwd_addr.s_addr);
+  
+  /* Put route tag -- This value should be introduced from configuration. */
+  stream_putl (s, 0);
+}
+
+/* Create new external-LSA. */
+struct ospf_lsa *
+ospf_external_lsa_new (struct external_info *ei, struct in_addr *old_id)
+{
+  struct stream *s;
+  struct lsa_header *lsah;
+  struct ospf_lsa *new;
+  struct in_addr id;
+  int length;
+
+  if (ei == NULL)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+       zlog_warn ("LSA[Type5]: External info is NULL, could not originated");
+      return NULL;
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type5]: Originate AS-external-LSA instance");
+
+  /* If old Link State ID is specified, refresh LSA with same ID. */
+  if (old_id)
+    id = *old_id;
+  /* Get Link State with unique ID. */
+  else
+    {
+      id = ospf_lsa_unique_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA, &ei->p);
+      if (id.s_addr == 0xffffffff)
+       {
+         /* Maybe Link State ID not available. */
+         if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+           zlog_info ("LSA[Type5]: Link ID not available, can't originate");
+         return NULL;
+       }
+    }
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  /* Set LSA common header fields. */
+  lsa_header_set (s, OSPF_OPTION_E, OSPF_AS_EXTERNAL_LSA, id);
+
+  /* Set AS-external-LSA body fields. */
+  ospf_external_lsa_body_set (s, ei);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Now, create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = NULL;
+  SET_FLAG (new->flags, OSPF_LSA_SELF|OSPF_LSA_APPROVED);
+
+  /* Copy LSA data to store, discard stream. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+#ifdef HAVE_NSSA
+/* Set AS-external-LSA body test. */
+void
+ospf_external_lsa_body_test (struct stream *s)
+{
+  struct in_addr mask, fwd_addr;
+  u_int32_t mvalue = 0;
+  /* int mtype;
+     int type; */
+
+  mask.s_addr = 0;
+  fwd_addr.s_addr = 0;
+
+  /* Put Network Mask. */
+  /* masklen2ip (p->prefixlen, &mask); */
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* If prefix is default, specify DEFAULT_ROUTE. */
+  /* type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
+  
+  mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ?
+  ROUTEMAP_METRIC_TYPE (ei) : metric_type (type);
+
+  mvalue = (ROUTEMAP_METRIC (ei) != -1) ?
+  ROUTEMAP_METRIC (ei) : metric_value (type); */
+
+  /* Put type of external metric. */
+  stream_putc (s,  0);
+
+  /* Put 0 metric. TOS metric is not supported. */
+  stream_put_ospf_metric (s, mvalue);
+  
+  /*  fwd_addr = ospf_top->router_id; */
+       
+  /* OLD == ospf_external_lsa_nexthop_get (ei->nexthop); */
+
+  /* Put forwarding address. */
+  /* stream_put_ipv4 (s, fwd_addr.s_addr); */
+  stream_put_ipv4 (s, ospf_top->router_id.s_addr);
+  
+  /* Put route tag -- This value should be introduced from configuration. */
+  stream_putl (s, 0);
+}
+
+/* As Type-7 */
+void
+ospf_install_flood_nssa (struct ospf_lsa *lsa, struct external_info *ei)
+{
+  struct ospf_lsa *new2;
+  struct as_external_lsa *extlsa;
+
+  /* NSSA Originate or Refresh (If anyNSSA)
+
+  LSA is self-originated. And just installed as Type-5.
+  Additionally, install as Type-7 LSDB for every attached NSSA.
+
+  P-Bit controls which ABR performs translation to outside world; If
+  we are an ABR....do not set the P-bit, because we send the Type-5,
+  not as the ABR Translator, but as the ASBR owner within the AS!
+
+  If we are NOT ABR, Flood through NSSA as Type-7 w/P-bit set.  The
+  elected ABR Translator will see the P-bit, Translate, and re-flood.
+
+  Later, ABR_TASK and P-bit will scan Type-7 LSDB and translate to
+  Type-5's to non-NSSA Areas.  (it will also attempt a re-install) */
+
+  /* make lsa duplicate, lock=1 */
+  new2 = ospf_lsa_dup(lsa);
+
+  /* make type-7 */
+  new2->data->type  = OSPF_AS_NSSA_LSA;
+
+  /* set P-bit if not ABR */
+  if (! OSPF_IS_ABR)
+    {
+      SET_FLAG(new2->data->options, OSPF_OPTION_NP);
+
+      /* set non-zero FWD ADDR 
+
+      draft-ietf-ospf-nssa-update-09.txt
+
+      if the network between the NSSA AS boundary router and the
+      adjacent AS is advertised into OSPF as an internal OSPF route, 
+      the forwarding address should be the next op address as is cu
+      currently done with type-5 LSAs.  If the intervening network is 
+      not adversited into OSPF as an internal OSPF route and the 
+      type-7 LSA's P-bit is set a forwarding address should be 
+      selected from one of the router's active OSPF inteface addresses
+      which belong to the NSSA.  If no such addresses exist, then
+      no type-7 LSA's with the P-bit set should originate from this
+      router.   */
+
+      extlsa = (struct as_external_lsa *)(lsa->data);
+
+      if (extlsa->e[0].fwd_addr.s_addr == 0) 
+       extlsa->e[0].fwd_addr = ospf_get_nssa_ip(); /* this NSSA area in ifp */
+
+      if (IS_DEBUG_OSPF_NSSA)
+       if (extlsa->e[0].fwd_addr.s_addr == 0) 
+         {
+           zlog_info ("LSA[Type-7]: Could not build FWD-ADDR");
+           ospf_lsa_discard(new2);
+           return;
+         }
+    }
+
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new2->data);
+
+  /* install also as Type-7 */
+  ospf_lsa_install (NULL, new2);   /* Remove Old, Lock New = 2 */
+
+  /* will send each copy, lock=2+n */
+  ospf_flood_through_as (NULL, new2); /* all attached NSSA's, no AS/STUBs */
+
+  /* last send, lock=2 LSA is now permanent in Type-7 LSDB */
+  /* It has the same ID as it's Type-5 Counter-Part */
+}
+#endif /* HAVE_NSSA */
+
+int
+is_prefix_default (struct prefix_ipv4 *p)
+{
+  struct prefix_ipv4 q;
+
+  q.family = AF_INET;
+  q.prefix.s_addr = 0;
+  q.prefixlen = 0;
+
+  return prefix_same ((struct prefix *) p, (struct prefix *) &q);
+}
+
+/* Originate an AS-external-LSA, install and flood. */
+struct ospf_lsa *
+ospf_external_lsa_originate (struct external_info *ei)
+{
+  struct ospf_lsa *new;
+
+  /* Added for NSSA project....
+
+       External LSAs are originated in ASBRs as usual, but for NSSA systems.
+     there is the global Type-5 LSDB and a Type-7 LSDB installed for
+     every area.  The Type-7's are flooded to every IR and every ABR; We
+     install the Type-5 LSDB so that the normal "refresh" code operates
+     as usual, and flag them as not used during ASE calculations.  The
+     Type-7 LSDB is used for calculations.  Each Type-7 has a Forwarding
+     Address of non-zero.
+
+     If an ABR is the elected NSSA translator, following SPF and during
+     the ABR task it will translate all the scanned Type-7's, with P-bit
+     ON and not-self generated, and translate to Type-5's throughout the
+     non-NSSA/STUB AS.
+
+     A difference in operation depends whether this ASBR is an ABR
+     or not.  If not an ABR, the P-bit is ON, to indicate that any
+     elected NSSA-ABR can perform its translation.
+
+     If an ABR, the P-bit is OFF;  No ABR will perform translation and
+     this ASBR will flood the Type-5 LSA as usual.
+
+     For the case where this ASBR is not an ABR, the ASE calculations
+     are based on the Type-5 LSDB;  The Type-7 LSDB exists just to
+     demonstrate to the user that there are LSA's that belong to any
+     attached NSSA.
+
+     Finally, it just so happens that when the ABR is translating every
+     Type-7 into Type-5, it installs it into the Type-5 LSDB as an
+     approved Type-5 (translated from Type-7);  at the end of translation
+     if any Translated Type-5's remain unapproved, then they must be
+     flushed from the AS.
+
+     */
+  
+  /* Check the AS-external-LSA should be originated. */
+  if (!ospf_redistribute_check (ei, NULL))
+    return NULL;
+  
+  /* Create new AS-external-LSA instance. */
+  if ((new = ospf_external_lsa_new (ei, NULL)) == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("LSA[Type5:%s]: Could not originate AS-external-LSA",
+                  inet_ntoa (ei->p.prefix));
+      return NULL;
+    }
+
+  /* Install newly created LSA into Type-5 LSDB, lock = 1. */
+  ospf_lsa_install (NULL, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA. only to AS (non-NSSA/STUB) */
+  ospf_flood_through_as (NULL, new);
+
+#ifdef HAVE_NSSA
+  /* If there is any attached NSSA, do special handling */
+  if (ospf_top->anyNSSA)
+    ospf_install_flood_nssa (new, ei); /* Install/Flood Type-7 to all NSSAs */
+#endif /* HAVE_NSSA */
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate AS-external-LSA %p",
+                new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+/* Originate AS-external-LSA from external info with initial flag. */
+int
+ospf_external_lsa_originate_timer (struct thread *t)
+{
+  struct route_node *rn;
+  struct external_info *ei;
+  struct route_table *rt;
+  int type;
+
+  ospf_top->t_external_lsa = NULL;
+  type = THREAD_VAL (t);
+
+  /* Originate As-external-LSA from all type of distribute source. */
+  if ((rt = EXTERNAL_INFO (type)))
+    for (rn = route_top (rt); rn; rn = route_next (rn))
+      if ((ei = rn->info) != NULL)
+       if (!is_prefix_default ((struct prefix_ipv4 *)&ei->p))
+         if (!ospf_external_lsa_originate (ei))
+           zlog_warn ("LSA: AS-external-LSA was not originated.");
+  
+  return 0;
+}
+
+struct external_info *
+ospf_default_external_info ()
+{
+  int type;
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  
+  p.family = AF_INET;
+  p.prefix.s_addr = 0;
+  p.prefixlen = 0;
+
+  /* First, lookup redistributed default route. */
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    if (EXTERNAL_INFO (type) && type != ZEBRA_ROUTE_OSPF)
+      {
+       rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p);
+       if (rn != NULL)
+         {
+           route_unlock_node (rn);
+           assert (rn->info);
+           if (ospf_redistribute_check (rn->info, NULL))
+             return rn->info;
+         }
+      }
+
+  return NULL;
+}
+
+int
+ospf_default_originate_timer (struct thread *t)
+{
+  int *origin;
+  struct prefix_ipv4 p;
+  struct in_addr nexthop;
+  struct external_info *ei;
+  
+  /* Get originate flags. */
+  origin = THREAD_ARG (t);
+
+  p.family = AF_INET;
+  p.prefix.s_addr = 0;
+  p.prefixlen = 0;
+
+  if (*origin == DEFAULT_ORIGINATE_ALWAYS)
+    {
+      /* If there is no default route via redistribute,
+        then originate AS-external-LSA with nexthop 0 (self). */
+      nexthop.s_addr = 0;
+      ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop);
+    }
+
+  if ((ei = ospf_default_external_info ()))
+    ospf_external_lsa_originate (ei);
+  
+  return 0;
+}
+
+/* Flush an AS-external-LSA from LSDB and routing domain. */
+void
+ospf_external_lsa_flush (u_char type, struct prefix_ipv4 *p,
+                        unsigned int ifindex, struct in_addr nexthop)
+{
+  struct ospf_lsa *lsa;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("LSA: Flushing AS-external-LSA %s/%d",
+              inet_ntoa (p->prefix), p->prefixlen);
+
+  /* First lookup LSA from LSDB. */
+  if (!(lsa = ospf_external_info_find_lsa (p)))
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+       zlog_warn ("LSA: There is no such AS-external-LSA %s/%d in LSDB",
+                  inet_ntoa (p->prefix), p->prefixlen);
+      return;
+    }
+
+  /* Sweep LSA from Link State Retransmit List. */
+  ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+
+  /* There must be no self-originated LSA in rtrs_external. */
+#if 0
+  /* Remove External route from Zebra. */
+  ospf_zebra_delete ((struct prefix_ipv4 *) p, &nexthop);
+#endif
+
+  if (!IS_LSA_MAXAGE (lsa))
+    {
+      /* Unregister LSA from Refresh queue. */
+      ospf_refresher_unregister_lsa (ospf_top, lsa);
+
+      /* Flush AS-external-LSA through AS. */
+      ospf_flush_through_as (lsa);
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("ospf_external_lsa_flush(): stop");
+}
+
+void
+ospf_external_lsa_refresh_default ()
+{
+  struct prefix_ipv4 p;
+  struct external_info *ei;
+  struct ospf_lsa *lsa;
+
+  p.family = AF_INET;
+  p.prefixlen = 0;
+  p.prefix.s_addr = 0;
+
+  ei = ospf_default_external_info ();
+  lsa = ospf_external_info_find_lsa (&p);
+
+  if (ei)
+    {
+      if (lsa)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", lsa);
+         ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_FORCE);
+       }
+      else
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("LSA[Type5:0.0.0.0]: Originate AS-external-LSA");
+         ospf_external_lsa_originate (ei);
+       }
+    }
+  else
+    {
+      if (lsa)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA");
+         ospf_lsa_flush_as (lsa);
+       }
+    }
+}
+
+void
+ospf_external_lsa_refresh_type (u_char type, int force)
+{
+  struct route_node *rn;
+  struct external_info *ei;
+
+  if (type != DEFAULT_ROUTE)
+    if (EXTERNAL_INFO(type))
+      /* Refresh each redistributed AS-external-LSAs. */
+      for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn))
+       if ((ei = rn->info))
+         if (!is_prefix_default (&ei->p))
+           {
+             struct ospf_lsa *lsa;
+
+             if ((lsa = ospf_external_info_find_lsa (&ei->p)))
+               ospf_external_lsa_refresh (lsa, ei, force);
+             else
+               ospf_external_lsa_originate (ei);
+           }
+}
+
+/* Refresh AS-external-LSA. */
+void
+ospf_external_lsa_refresh (struct ospf_lsa *lsa,
+                          struct external_info *ei, int force)
+{
+  struct ospf_lsa *new;
+  int changed;
+  
+  /* Check the AS-external-LSA should be originated. */
+  if (!ospf_redistribute_check (ei, &changed))
+    {
+      ospf_external_lsa_flush (ei->type, &ei->p, ei->ifindex, ei->nexthop);
+      return;
+    }
+
+  if (!changed && !force)
+    return;
+
+  /* Delete LSA from neighbor retransmit-list. */
+  ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+
+  /* Unregister AS-external-LSA from refresh-list. */
+  ospf_refresher_unregister_lsa (ospf_top, lsa);
+
+  new = ospf_external_lsa_new (ei, &lsa->data->id);
+  
+  if (new == NULL)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+       zlog_warn ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type,
+                  inet_ntoa (lsa->data->id));
+      return;
+    }
+  
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  /* Record timestamp. */
+  gettimeofday (&new->tv_orig, NULL);
+
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new->data);
+
+  ospf_lsa_install (NULL, new);        /* As type-5. */
+
+  /* Flood LSA through AS. */
+  ospf_flood_through_as (NULL, new);
+
+#ifdef HAVE_NSSA
+  /* If any attached NSSA, install as Type-7, flood to all NSSA Areas */
+  if (ospf_top->anyNSSA)
+    ospf_install_flood_nssa (new, ei); /* Install/Flood per new rules */
+#endif /* HAVE_NSSA */
+
+  /* Register slef-originated LSA to refresh queue. */
+  ospf_refresher_register_lsa (ospf_top, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: AS-external-LSA refresh",
+                new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return;
+}
+
+\f
+/* LSA installation functions. */
+
+/* Install router-LSA to an area. */
+struct ospf_lsa *
+ospf_router_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+  struct ospf_area *area = new->area;
+
+  /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
+     The entire routing table must be recalculated, starting with
+     the shortest path calculations for each area (not just the
+     area whose link-state database has changed). 
+  */
+  if (rt_recalc)
+    ospf_spf_calculate_schedule();
+
+  if (IS_LSA_SELF (new))
+    {
+      /* Set router-LSA refresh timer. */
+      OSPF_TIMER_OFF (area->t_router_lsa_self);
+      OSPF_AREA_TIMER_ON (area->t_router_lsa_self,
+                         ospf_router_lsa_timer, OSPF_LS_REFRESH_TIME);
+      
+      /* Set self-originated router-LSA. */
+      ospf_lsa_unlock (area->router_lsa_self);
+      area->router_lsa_self = ospf_lsa_lock (new);
+
+      if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+       zlog_info("LSA[Type%d]: ID %s is self-originated",
+                 new->data->type, inet_ntoa (new->data->id));
+    }
+
+  return new;
+}
+
+#define OSPF_INTERFACE_TIMER_ON(T,F,V) \
+       if (!(T)) \
+         (T) = thread_add_timer (master, (F), oi, (V))
+
+/* Install network-LSA to an area. */
+struct ospf_lsa *
+ospf_network_lsa_install (struct ospf_interface *oi, 
+                         struct ospf_lsa *new,
+                         int rt_recalc)
+{
+
+  /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
+     The entire routing table must be recalculated, starting with
+     the shortest path calculations for each area (not just the
+     area whose link-state database has changed). 
+  */
+  if (rt_recalc)
+    ospf_spf_calculate_schedule();
+
+  /* We supposed that when LSA is originated by us, we pass the int
+     for which it was originated. If LSA was received by flooding,
+     the RECEIVED flag is set, so we do not link the LSA to the int. */
+  if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))
+    {
+      /* Set LSRefresh timer. */
+      OSPF_TIMER_OFF (oi->t_network_lsa_self);
+
+      OSPF_INTERFACE_TIMER_ON (oi->t_network_lsa_self,
+                              ospf_network_lsa_refresh_timer,
+                              OSPF_LS_REFRESH_TIME);
+
+      ospf_lsa_unlock (oi->network_lsa_self);
+      oi->network_lsa_self = ospf_lsa_lock (new);
+    }
+
+  return new;
+}
+
+/* Install summary-LSA to an area. */
+struct ospf_lsa *
+ospf_summary_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+
+  if (rt_recalc && !IS_LSA_SELF (new))
+    {
+      /* RFC 2328 Section 13.2 Summary-LSAs
+        The best route to the destination described by the summary-
+        LSA must be recalculated (see Section 16.5).  If this
+        destination is an AS boundary router, it may also be
+        necessary to re-examine all the AS-external-LSAs.
+      */
+
+#if 0
+      /* This doesn't exist yet... */
+      ospf_summary_incremental_update(new); */
+#else /* #if 0 */
+      ospf_spf_calculate_schedule();
+#endif /* #if 0 */
+      if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+       zlog_info ("ospf_summary_lsa_install(): SPF scheduled");
+    }
+
+  if (IS_LSA_SELF (new))
+    ospf_refresher_register_lsa (ospf_top, new);
+
+  return new;
+}
+
+/* Install ASBR-summary-LSA to an area. */
+struct ospf_lsa *
+ospf_summary_asbr_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+  if (rt_recalc && !IS_LSA_SELF (new))
+    {
+      /* RFC 2328 Section 13.2 Summary-LSAs
+        The best route to the destination described by the summary-
+        LSA must be recalculated (see Section 16.5).  If this
+        destination is an AS boundary router, it may also be
+        necessary to re-examine all the AS-external-LSAs.
+      */
+#if 0
+      /* These don't exist yet... */
+      ospf_summary_incremental_update(new);
+      /* Isn't this done by the above call? 
+        - RFC 2328 Section 16.5 implies it should be */
+      /* ospf_ase_calculate_schedule(); */
+#else  /* #if 0 */
+      ospf_spf_calculate_schedule();
+#endif /* #if 0 */
+    }
+
+  /* register LSA to refresh-list. */
+  if (IS_LSA_SELF (new))
+    ospf_refresher_register_lsa (ospf_top, new);
+
+  return new;
+}
+
+/* Install AS-external-LSA. */
+struct ospf_lsa *
+ospf_external_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+  ospf_ase_register_external_lsa (new, ospf_top);
+  /* If LSA is not self-originated, calculate an external route. */
+  if (rt_recalc)
+    {
+      /* RFC 2328 Section 13.2 AS-external-LSAs
+            The best route to the destination described by the AS-
+            external-LSA must be recalculated (see Section 16.6).
+      */
+
+      if (!IS_LSA_SELF (new))
+       ospf_ase_incremental_update (new, ospf_top);
+    }
+
+  /* Register self-originated LSA to refresh queue. */
+  if (IS_LSA_SELF (new))
+    ospf_refresher_register_lsa (ospf_top, new);
+
+  return new;
+}
+
+void
+ospf_discard_from_db (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *old;
+  
+  old = ospf_lsdb_lookup (lsdb, lsa);
+
+  if (!old)
+    return;
+
+  if (old->refresh_list >= 0)
+    ospf_refresher_unregister_lsa (ospf_top, old);
+
+  ospf_ls_retransmit_delete_nbr_all (old->area, old);
+
+  switch (old->data->type)
+    {
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      ospf_ase_unregister_external_lsa (old, ospf_top);
+      break;
+    default:
+      break;
+    }
+
+  ospf_lsa_maxage_delete (old);
+  ospf_lsa_discard (old);
+}
+
+/* callback for foreach_lsa */
+int
+ospf_lsa_discard_callback (struct ospf_lsa *lsa, void *p, int i)
+{
+#ifdef HAVE_NSSA
+  /* Removed: Stay away from any Local Translated Type-7 LSAs */
+  /* if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+     return 0; */
+#endif /* HAVE_NSSA */
+  ospf_discard_from_db ((struct ospf_lsdb *)p, lsa);
+  return 0;
+}
+
+struct ospf_lsa *
+ospf_lsa_install (struct ospf_interface *oi, struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new = NULL;
+  struct ospf_lsa *old = NULL;
+  struct ospf_lsdb *lsdb = NULL;
+  int rt_recalc;
+
+  /* Set LSDB. */
+  switch (lsa->data->type)
+    {
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      lsdb = ospf_top->lsdb;
+      break;
+    default:
+      lsdb = lsa->area->lsdb;
+      break;
+    }
+
+#ifdef HAVE_NSSA
+  if (IS_DEBUG_OSPF_NSSA)
+    {
+      zlog_info ("LSA[Installing]: Type-%d ", lsa->data->type);
+
+      if  (lsa->data->type == OSPF_AS_NSSA_LSA )
+       zlog_info ("NSSA LSA AREA = %s", inet_ntoa (lsa->area->area_id));
+    }
+#endif /* HAVE_NSSA */
+
+  assert (lsdb);
+
+  /*  RFC 2328 13.2.  Installing LSAs in the database
+
+        Installing a new LSA in the database, either as the result of
+        flooding or a newly self-originated LSA, may cause the OSPF
+        routing table structure to be recalculated.  The contents of the
+        new LSA should be compared to the old instance, if present.  If
+        there is no difference, there is no need to recalculate the
+        routing table. When comparing an LSA to its previous instance,
+        the following are all considered to be differences in contents:
+
+            o   The LSA's Options field has changed.
+
+            o   One of the LSA instances has LS age set to MaxAge, and
+                the other does not.
+
+            o   The length field in the LSA header has changed.
+
+            o   The body of the LSA (i.e., anything outside the 20-byte
+                LSA header) has changed. Note that this excludes changes
+                in LS Sequence Number and LS Checksum.
+
+  */
+  /* Look up old LSA and determine if any SPF calculation or incremental
+     update is needed */
+  old = ospf_lsdb_lookup (lsdb, lsa);
+
+  /* Do comparision and record if recalc needed. */
+  rt_recalc = 0;
+  if (  old == NULL || ospf_lsa_different(old, lsa))
+    rt_recalc = 1;
+
+  /* discard old LSA from LSDB */
+  if (old != NULL)
+    ospf_discard_from_db (lsdb, lsa);
+
+  /* Insert LSA to LSDB. */
+  ospf_lsdb_add (lsdb, lsa);
+  lsa->lsdb = lsdb;
+
+  /* Calculate Checksum if self-originated?. */
+  if (IS_LSA_SELF (lsa))
+    ospf_lsa_checksum (lsa->data);
+
+  /* Do LSA specific installation process. */
+  switch (lsa->data->type)
+    {
+    case OSPF_ROUTER_LSA:
+      new = ospf_router_lsa_install (lsa, rt_recalc);
+      break;
+    case OSPF_NETWORK_LSA:
+      assert (oi);
+      new = ospf_network_lsa_install (oi, lsa, rt_recalc);
+      break;
+    case OSPF_SUMMARY_LSA:
+      new = ospf_summary_lsa_install (lsa, rt_recalc);
+      break;
+    case OSPF_ASBR_SUMMARY_LSA:
+      new = ospf_summary_asbr_lsa_install (lsa, rt_recalc);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+      new = ospf_external_lsa_install (lsa, rt_recalc);
+      break;
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      new = ospf_opaque_lsa_install (lsa, rt_recalc);
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default: /* NSSA, or type-6,8,9....nothing special */
+#ifdef HAVE_NSSA
+      new = ospf_external_lsa_install (lsa, rt_recalc);
+#endif /* HAVE_NSSA */
+      break;
+    }
+
+  if (new == NULL)
+    return new;  /* Installation failed, cannot proceed further -- endo. */
+
+  /* Debug logs. */
+  if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+    {
+      char area_str[INET_ADDRSTRLEN];
+
+      switch (lsa->data->type)
+        {
+        case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+        case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+          zlog_info ("LSA[%s]: Install %s",
+                 dump_lsa_key (new),
+                 LOOKUP (ospf_lsa_type_msg, new->data->type));
+          break;
+        default:
+         strcpy (area_str, inet_ntoa (new->area->area_id));
+          zlog_info ("LSA[%s]: Install %s to Area %s",
+                 dump_lsa_key (new),
+                 LOOKUP (ospf_lsa_type_msg, new->data->type), area_str);
+          break;
+        }
+    }
+
+  /* If received LSA' ls_age is MaxAge, set LSA on MaxAge LSA list. */
+  if (IS_LSA_MAXAGE (new) && !IS_LSA_SELF (new))
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+       zlog_info ("LSA[Type%d:%s]: Install LSA, MaxAge",
+                  new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_maxage (lsa);
+    }
+
+  return new;
+}
+
+\f
+int
+ospf_check_nbr_status ()
+{
+  listnode node;
+
+  for (node = listhead (ospf_top->oiflist); node; node = nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+
+      if (ospf_if_is_enable (oi))
+       for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+          if ((nbr = rn->info) != NULL)
+           if (nbr->state == NSM_Exchange || nbr->state == NSM_Loading)
+             {
+               route_unlock_node (rn);
+               return 0;
+             }
+    }
+
+  return 1;
+}
+
+\f
+#ifdef ORIGINAL_CODING
+/* This function flood the maxaged LSA to DR. */
+void
+ospf_maxage_flood (struct ospf_lsa *lsa)
+{
+  switch (lsa->data->type)
+    {
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA:
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_NSSA
+    case OSPF_AS_NSSA_LSA:
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      ospf_flood_through_area (lsa->area, NULL, lsa);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      ospf_flood_through_as (NULL, lsa);
+      break;
+    default:
+      break;
+    }
+}
+#endif /* ORIGINAL_CODING */
+
+int
+ospf_maxage_lsa_remover (struct thread *thread)
+{
+  listnode node;
+  listnode next;
+  int reschedule = 0;
+
+  ospf_top->t_maxage = NULL;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("LSA[MaxAge]: remover Start");
+
+  reschedule = !ospf_check_nbr_status ();
+
+  if (!reschedule)
+    for (node = listhead (ospf_top->maxage_lsa); node; node = next)
+      {
+        struct ospf_lsa *lsa = getdata (node);
+        next = node->next;
+
+        if (lsa->retransmit_counter > 0)
+          {
+            reschedule = 1;
+            continue;
+          }
+
+        /* Remove LSA from the LSDB */
+        if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF))
+          if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+            zlog_info ("LSA[Type%d:%s]: This LSA is self-originated: ",
+                       lsa->data->type, inet_ntoa (lsa->data->id));
+
+        if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+          zlog_info ("LSA[Type%d:%s]: MaxAge LSA removed from list",
+                     lsa->data->type, inet_ntoa (lsa->data->id));
+
+       /* Flood max age LSA. */
+#ifdef ORIGINAL_CODING
+       ospf_maxage_flood (lsa);
+#else /* ORIGINAL_CODING */
+        ospf_flood_through (NULL, lsa);
+#endif /* ORIGINAL_CODING */
+
+       /* Remove from lsdb. */
+        ospf_discard_from_db (lsa->lsdb, lsa);
+        ospf_lsdb_delete (lsa->lsdb, lsa);
+      }
+
+  /*    A MaxAge LSA must be removed immediately from the router's link
+        state database as soon as both a) it is no longer contained on any
+        neighbor Link state retransmission lists and b) none of the router's
+        neighbors are in states Exchange or Loading. */
+  if (reschedule)
+    OSPF_SCHEDULE_MAXAGE (ospf_top->t_maxage, ospf_maxage_lsa_remover);
+
+  return 0;
+}
+
+int
+ospf_lsa_maxage_exist (struct ospf_lsa *new)
+{
+  listnode node;
+
+  for (node = listhead (ospf_top->maxage_lsa); node; nextnode (node))
+    if (((struct ospf_lsa *) node->data) == new)
+      return 1;
+
+  return 0;
+}
+
+void
+ospf_lsa_maxage_delete (struct ospf_lsa *lsa)
+{
+  listnode n;
+
+  if ((n = listnode_lookup (ospf_top->maxage_lsa, lsa)))
+    {
+      list_delete_node (ospf_top->maxage_lsa, n);
+      ospf_lsa_unlock (lsa);
+    }
+}
+
+void
+ospf_lsa_maxage (struct ospf_lsa *lsa)
+{
+  /* When we saw a MaxAge LSA flooded to us, we put it on the list
+     and schedule the MaxAge LSA remover. */
+  if (ospf_lsa_maxage_exist (lsa))
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+       zlog_info ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list",
+                  lsa->data->type, inet_ntoa (lsa->data->id), lsa);
+      return;
+    }
+
+  listnode_add (ospf_top->maxage_lsa, ospf_lsa_lock (lsa));
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa));
+
+  OSPF_SCHEDULE_MAXAGE (ospf_top->t_maxage, ospf_maxage_lsa_remover);
+}
+
+int
+ospf_lsa_maxage_walker_remover (struct ospf_lsa *lsa, void *p_arg, int int_arg)
+{
+#ifdef HAVE_NSSA
+  /* Stay away from any Local Translated Type-7 LSAs */
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+    return 0;
+#endif /* HAVE_NSSA */
+
+  if (IS_LSA_MAXAGE (lsa))
+    /* Self-originated LSAs should NOT time-out instead,
+       they're flushed and submitted to the max_age list explicitly. */
+    if (!ospf_lsa_is_self_originated (lsa))
+      {
+       if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+         zlog_info("LSA[%s]: is MaxAge", dump_lsa_key (lsa));
+
+        switch (lsa->data->type)
+          {
+          case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+          case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+           ospf_ase_incremental_update (lsa, ospf_top);
+            break;
+          default:
+           ospf_spf_calculate_schedule ();
+            break;
+          }
+
+       ospf_lsa_maxage (lsa);
+      }
+
+  return 0;
+}
+
+/* Periodical check of MaxAge LSA. */
+int
+ospf_lsa_maxage_walker (struct thread *t)
+{
+  listnode node;
+
+  ospf_top->t_maxage_walker = NULL;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = node->data;
+
+      foreach_lsa (ROUTER_LSDB (area), NULL, 0,
+                  ospf_lsa_maxage_walker_remover);
+      foreach_lsa (NETWORK_LSDB (area), NULL, 0,
+                  ospf_lsa_maxage_walker_remover);
+      foreach_lsa (SUMMARY_LSDB (area), NULL, 0,
+                  ospf_lsa_maxage_walker_remover);
+      foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0,
+                  ospf_lsa_maxage_walker_remover);
+#ifdef HAVE_OPAQUE_LSA
+      foreach_lsa (OPAQUE_LINK_LSDB (area), NULL, 0,
+                  ospf_lsa_maxage_walker_remover);
+      foreach_lsa (OPAQUE_AREA_LSDB (area), NULL, 0,
+                  ospf_lsa_maxage_walker_remover);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  /* for AS-eternal-LSAs. */
+  if (ospf_top->lsdb)
+    foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0,
+                ospf_lsa_maxage_walker_remover);
+
+#ifdef HAVE_OPAQUE_LSA
+  if (ospf_top->lsdb)
+    foreach_lsa (OPAQUE_AS_LSDB (ospf_top), NULL, 0,
+                ospf_lsa_maxage_walker_remover);
+#endif /* HAVE_OPAQUE_LSA */
+
+  ospf_top->t_maxage_walker = 
+    thread_add_timer (master, ospf_lsa_maxage_walker, NULL,
+                      OSPF_LSA_MAXAGE_CHECK_INTERVAL);
+  return 0;
+}
+
+int
+find_summary (struct ospf_lsa *lsa, void * v, int i)
+{
+  struct prefix_ipv4 *p, pr;
+
+  if ((p = (struct prefix_ipv4 *) v) != NULL)
+    if (lsa != NULL)
+      /* We're looking for self-originated one */
+      if (ospf_lsa_is_self_originated (lsa))
+       {
+         struct summary_lsa *sl = (struct summary_lsa *) lsa->data;
+
+         pr.family = AF_INET;
+         pr.prefix = sl->header.id;
+         pr.prefixlen = ip_masklen (sl->mask);
+         apply_mask_ipv4 (&pr);
+
+         if (prefix_same ((struct prefix*) &pr, (struct prefix*) p))
+           return 1;
+       }
+
+  return 0;
+}
+
+int
+find_asbr_summary (struct ospf_lsa *lsa, void * v, int i)
+{
+  struct prefix_ipv4 *p;
+
+  if ((p = (struct prefix_ipv4 *) v) != NULL)
+    if (lsa != NULL)
+      /* We're looking for self-originated one */
+      if (ospf_lsa_is_self_originated (lsa))
+       {
+         struct summary_lsa *sl = (struct summary_lsa *) lsa->data;
+
+         if (IPV4_ADDR_SAME (&p->prefix, &sl->header.id))
+           return 1;
+       }
+
+  return 0;
+}
+
+struct ospf_lsa *
+ospf_lsa_lookup (struct ospf_area *area, u_int32_t type,
+                 struct in_addr id, struct in_addr adv_router)
+{
+  switch (type)
+    {
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA:
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_NSSA
+    case OSPF_AS_NSSA_LSA:
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      return ospf_lsdb_lookup_by_id (ospf_top->lsdb, type, id, adv_router);
+      break;
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, 
+                       struct in_addr id)
+{
+  struct ospf_lsa *lsa;
+  struct route_node *rn;
+
+  switch (type)
+    {
+    case OSPF_ROUTER_LSA:
+      return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id);
+      break;
+    case OSPF_NETWORK_LSA:
+      for (rn = route_top (NETWORK_LSDB (area)); rn; rn = route_next (rn))
+       if ((lsa = rn->info))
+         if (IPV4_ADDR_SAME (&lsa->data->id, &id))
+           {
+             route_unlock_node (rn);
+             return lsa;
+           }
+      break;
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+      /* Currently not used. */
+      assert (1);
+      return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      /* Currently not used. */
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah)
+{
+  struct ospf_lsa *match;
+
+#ifdef HAVE_OPAQUE_LSA
+  /*
+   * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11)
+   * is redefined to have two subfields; opaque-type and opaque-id.
+   * However, it is harmless to treat the two sub fields together, as if
+   * they two were forming a unique LSA-ID.
+   */
+#endif /* HAVE_OPAQUE_LSA */
+
+  match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router);
+
+  if (match == NULL)
+    if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+      zlog_info ("LSA[Type%d:%s]: Lookup by header, NO MATCH",
+                lsah->type, inet_ntoa (lsah->id));
+
+  return match;
+}
+
+/* return +n, l1 is more recent.
+   return -n, l2 is more recent.
+   return 0, l1 and l2 is identical. */
+int
+ospf_lsa_more_recent (struct ospf_lsa *l1, struct ospf_lsa *l2)
+{
+  int r;
+  int x, y;
+
+  if (l1 == NULL && l2 == NULL)
+    return 0;
+  if (l1 == NULL)
+    return -1;
+  if (l2 == NULL)
+    return 1;
+
+  /* compare LS sequence number. */
+  x = (int) ntohl (l1->data->ls_seqnum);
+  y = (int) ntohl (l2->data->ls_seqnum);
+  if (x > y)
+    return 1;
+  if (x < y)
+    return -1;
+
+  /* compare LS checksum. */
+  r = ntohs (l1->data->checksum) - ntohs (l2->data->checksum);
+  if (r)
+    return r;
+
+  /* compare LS age. */
+  if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2))
+    return 1;
+  else if (!IS_LSA_MAXAGE (l1) && IS_LSA_MAXAGE (l2))
+    return -1;
+
+  /* compare LS age with MaxAgeDiff. */
+  if (LS_AGE (l1) - LS_AGE (l2) > OSPF_LSA_MAXAGE_DIFF)
+    return -1;
+  else if (LS_AGE (l2) - LS_AGE (l1) > OSPF_LSA_MAXAGE_DIFF)
+    return 1;
+
+  /* LSAs are identical. */
+  return 0;
+}
+
+/* If two LSAs are different, return 1, otherwise return 0. */
+int
+ospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2)
+{
+  char *p1, *p2;
+  assert (l1);
+  assert (l2);
+  assert (l1->data);
+  assert (l2->data);
+
+  if (l1->data->options != l2->data->options)
+    return 1;
+
+  if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2))
+    return 1;
+
+  if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1))
+    return 1;
+
+  if (l1->data->length != l2->data->length)
+    return 1;
+
+  if (l1->data->length ==  0)
+    return 1;
+
+  assert (l1->data->length > OSPF_LSA_HEADER_SIZE);
+
+  p1 = (char *) l1->data;
+  p2 = (char *) l2->data;
+
+  if (memcmp (p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE,
+              ntohs( l1->data->length ) - OSPF_LSA_HEADER_SIZE) != 0)
+    return 1;
+
+  return 0;
+}
+
+#ifdef ORIGINAL_CODING
+void
+ospf_lsa_flush_self_originated (struct ospf_neighbor *nbr,
+                                struct ospf_lsa *self,
+                                struct ospf_lsa *new)
+{
+  u_int32_t seqnum;
+
+  /* Adjust LS Sequence Number. */
+  seqnum = ntohl (new->data->ls_seqnum) + 1;
+  self->data->ls_seqnum = htonl (seqnum);
+
+  /* Recalculate LSA checksum. */
+  ospf_lsa_checksum (self->data);
+
+  /* Reflooding LSA. */
+  /*  RFC2328  Section 13.3
+           On non-broadcast networks, separate Link State Update
+           packets must be sent, as unicasts, to each adjacent neighbor
+           (i.e., those in state Exchange or greater).  The destination
+           IP addresses for these packets are the neighbors' IP
+           addresses.   */
+  if (nbr->oi->type == OSPF_IFTYPE_NBMA)
+    {
+      struct route_node *rn;
+      struct ospf_neighbor *onbr;
+
+      for (rn = route_top (nbr->oi->nbrs); rn; rn = route_next (rn))
+       if ((onbr = rn->info) != NULL)
+         if (onbr != nbr->oi->nbr_self && onbr->status >= NSM_Exchange)
+           ospf_ls_upd_send_lsa (onbr, self, OSPF_SEND_PACKET_DIRECT);
+    }
+  else
+  ospf_ls_upd_send_lsa (nbr, self, OSPF_SEND_PACKET_INDIRECT);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type%d:%s]: Flush self-originated LSA",
+              self->data->type, inet_ntoa (self->data->id));
+}
+#else /* ORIGINAL_CODING */
+static int
+ospf_lsa_flush_schedule (struct ospf_lsa *lsa, void *v, int i)
+{
+  if (lsa == NULL || !IS_LSA_SELF (lsa))
+    return 0;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
+
+  /* Force given lsa's age to MaxAge. */
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+
+  switch (lsa->data->type)
+    {
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_opaque_lsa_refresh (lsa);
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default:
+      ospf_lsa_maxage (lsa);
+      break;
+    }
+
+  return 0;
+}
+
+void
+ospf_flush_self_originated_lsas_now (struct ospf *top)
+{
+  listnode n1, n2;
+  struct ospf_area *area;
+  struct ospf_interface *oi;
+  struct ospf_lsa *lsa;
+  int need_to_flush_ase = 0;
+
+  for (n1 = listhead (top->areas); n1; nextnode (n1))
+    {
+      if ((area = getdata (n1)) == NULL)
+        continue;
+
+      if ((lsa = area->router_lsa_self) != NULL)
+        {
+          if (IS_DEBUG_OSPF_EVENT)
+            zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
+
+          ospf_lsa_flush_area (lsa, area);
+          ospf_lsa_unlock (area->router_lsa_self);
+          area->router_lsa_self = NULL;
+          OSPF_TIMER_OFF (area->t_router_lsa_self);
+        }
+
+      for (n2 = listhead (area->oiflist); n2; nextnode (n2))
+        {
+          if ((oi = getdata (n2)) == NULL)
+            continue;
+
+          if ((lsa = oi->network_lsa_self) != NULL
+          &&   oi->state == ISM_DR
+          &&   oi->full_nbrs > 0)
+            {
+              if (IS_DEBUG_OSPF_EVENT)
+                zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
+
+              ospf_lsa_flush_area (oi->network_lsa_self, area);
+              ospf_lsa_unlock (oi->network_lsa_self);
+              oi->network_lsa_self = NULL;
+              OSPF_TIMER_OFF (oi->t_network_lsa_self);
+            }
+
+          if (oi->type != OSPF_IFTYPE_VIRTUALLINK
+          &&  area->external_routing == OSPF_AREA_DEFAULT)
+            need_to_flush_ase = 1;
+        }
+
+      foreach_lsa (SUMMARY_LSDB (area), NULL, 0, ospf_lsa_flush_schedule);
+      foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0, ospf_lsa_flush_schedule);
+#ifdef HAVE_OPAQUE_LSA
+      foreach_lsa (OPAQUE_LINK_LSDB (area),
+                   NULL, 0, ospf_lsa_flush_schedule);
+      foreach_lsa (OPAQUE_AREA_LSDB (area),
+                   NULL, 0, ospf_lsa_flush_schedule);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  if (need_to_flush_ase)
+    {
+        foreach_lsa (EXTERNAL_LSDB (top), NULL, 0, ospf_lsa_flush_schedule);
+#ifdef HAVE_OPAQUE_LSA
+        foreach_lsa (OPAQUE_AS_LSDB (top),
+                     NULL, 0, ospf_lsa_flush_schedule);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  /*
+   * Make sure that the MaxAge LSA remover is executed immediately,
+   * without conflicting to other threads.
+   */
+  if (top->t_maxage != NULL)
+    {
+      OSPF_TIMER_OFF (top->t_maxage);
+      thread_execute (master, ospf_maxage_lsa_remover, top, 0);
+    }
+
+  return;
+}
+#endif /* ORIGINAL_CODING */
+
+/* If there is self-originated LSA, then return 1, otherwise return 0. */
+/* An interface-independent version of ospf_lsa_is_self_originated */
+int 
+ospf_lsa_is_self_originated (struct ospf_lsa *lsa)
+{
+  listnode node;
+
+  /* This LSA is already checked. */
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED))
+    return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
+
+  /* Make sure LSA is self-checked. */
+  SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED);
+
+  /* AdvRouter and Router ID is the same. */
+  if (IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf_top->router_id))
+    SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+
+  /* LSA is router-LSA. */
+  else if (lsa->data->type == OSPF_ROUTER_LSA &&
+      IPV4_ADDR_SAME (&lsa->data->id, &ospf_top->router_id))
+    SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+
+  /* LSA is network-LSA.  Compare Link ID with all interfaces. */
+  else if (lsa->data->type == OSPF_NETWORK_LSA)
+    for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+      {
+       struct ospf_interface *oi = getdata (node);
+
+       /* Ignore virtual link. */
+        if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+         if (oi->address->family == AF_INET)
+           if (IPV4_ADDR_SAME (&lsa->data->id, &oi->address->u.prefix4))
+             {
+               /* to make it easier later */
+               SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+               return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
+             }
+      }
+
+  return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
+}
+
+/* Get unique Link State ID. */
+struct in_addr
+ospf_lsa_unique_id (struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p)
+{
+  struct ospf_lsa *lsa;
+  struct in_addr mask, id;
+
+  id = p->prefix;
+
+  /* Check existence of LSA instance. */
+  lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, ospf_top->router_id);
+  if (lsa)
+    {
+      struct as_external_lsa *al = (struct as_external_lsa *) lsa->data;
+      if (ip_masklen (al->mask) == p->prefixlen)
+       {
+         if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+           zlog_warn ("ospf_lsa_unique_id(): "
+                      "Can't get Link State ID for %s/%d",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         /*      id.s_addr = 0; */
+         id.s_addr = 0xffffffff;
+         return id;
+       }
+      /* Masklen differs, then apply wildcard mask to Link State ID. */
+      else
+       {
+         masklen2ip (p->prefixlen, &mask);
+
+         id.s_addr = p->prefix.s_addr | (~mask.s_addr);
+         lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, type,
+                                      id, ospf_top->router_id);
+         if (lsa)
+           {
+             if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+               zlog_warn ("ospf_lsa_unique_id(): "
+                          "Can't get Link State ID for %s/%d",
+                          inet_ntoa (p->prefix), p->prefixlen);
+             /*              id.s_addr = 0; */
+             id.s_addr = 0xffffffff;
+             return id;
+           }
+       }
+    }
+
+  return id;
+}
+
+\f
+#define LSA_ACTION_ORIGN_RTR  1
+#define LSA_ACTION_ORIGN_NET  2
+#define LSA_ACTION_FLOOD_AREA 3
+#define LSA_ACTION_FLOOD_AS   4
+#define LSA_ACTION_FLUSH_AREA 5
+#define LSA_ACTION_FLUSH_AS   6
+
+struct lsa_action
+{
+  u_char action;
+  struct ospf_area *area;
+  struct ospf_interface *oi; 
+  struct ospf_lsa *lsa;
+};
+
+int
+ospf_lsa_action (struct thread *t)
+{
+  struct lsa_action *data;
+
+  data = THREAD_ARG (t);
+
+  if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+    zlog_info ("LSA[Action]: Performing scheduled LSA action: %d",
+              data->action);
+
+  switch (data->action)
+    {
+    case LSA_ACTION_ORIGN_RTR:
+      ospf_router_lsa_refresh (data->area->router_lsa_self);
+      break;
+    case LSA_ACTION_ORIGN_NET:
+      ospf_network_lsa_originate (data->oi);
+      break;
+    case LSA_ACTION_FLOOD_AREA:
+      ospf_flood_through_area (data->area, NULL, data->lsa);
+      break;
+    case LSA_ACTION_FLOOD_AS:
+      ospf_flood_through_as (NULL, data->lsa);
+      break;
+    case LSA_ACTION_FLUSH_AREA:
+      ospf_lsa_flush_area (data->lsa, data->area);
+      break;
+    case LSA_ACTION_FLUSH_AS:
+      ospf_lsa_flush_as (data->lsa);
+      break;
+    }
+
+  ospf_lsa_unlock (data->lsa);
+  XFREE (MTYPE_OSPF_MESSAGE, data);
+  return 0;
+}
+
+void
+ospf_schedule_lsa_flood_area (struct ospf_area *area, struct ospf_lsa *lsa)
+{
+  struct lsa_action *data;
+
+  data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action));
+  memset (data, 0, sizeof (struct lsa_action));
+
+  data->action = LSA_ACTION_FLOOD_AREA;
+  data->area = area;
+  data->lsa  = ospf_lsa_lock (lsa);
+
+  thread_add_event (master, ospf_lsa_action, data, 0);
+}
+
+void
+ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa)
+{
+  struct lsa_action *data;
+
+  data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action));
+  memset (data, 0, sizeof (struct lsa_action));
+
+  data->action = LSA_ACTION_FLUSH_AREA;
+  data->area = area;
+  data->lsa  = ospf_lsa_lock (lsa);
+
+  thread_add_event (master, ospf_lsa_action, data, 0);
+}
+
+\f
+/* LSA Refreshment functions. */
+void
+ospf_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct external_info *ei;
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
+
+  switch (lsa->data->type)
+    {
+      /* Router and Network LSAs are processed differently. */
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA: 
+      break;
+    case OSPF_SUMMARY_LSA:
+      ospf_summary_lsa_refresh (lsa);
+      break;
+    case OSPF_ASBR_SUMMARY_LSA:
+      ospf_summary_asbr_lsa_refresh (lsa);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+      ei = ospf_external_info_check (lsa);
+      if (ei)
+       ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_FORCE);
+      else
+       ospf_lsa_flush_as (lsa);
+      break;
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_opaque_lsa_refresh (lsa);
+      break;
+    default:
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    }
+}
+
+void
+ospf_refresher_register_lsa (struct ospf *top, struct ospf_lsa *lsa)
+{
+  u_int16_t index, current_index;
+  
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
+
+  if (lsa->refresh_list < 0)
+    {
+      int delay;
+
+      if (LS_AGE (lsa) == 0 &&
+         ntohl (lsa->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER)
+       /* Randomize first update by  OSPF_LS_REFRESH_SHIFT factor */ 
+       delay = OSPF_LS_REFRESH_SHIFT + (random () % OSPF_LS_REFRESH_TIME);
+      else
+       /* Randomize another updates by +-OSPF_LS_REFRESH_JITTER factor */
+       delay = OSPF_LS_REFRESH_TIME - LS_AGE (lsa) - OSPF_LS_REFRESH_JITTER
+         + (random () % (2*OSPF_LS_REFRESH_JITTER)); 
+
+      if (delay < 0)
+       delay = 0;
+
+      current_index = top->lsa_refresh_queue.index +
+       (time (NULL) - top->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
+      
+      index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY)
+       % (OSPF_LSA_REFRESHER_SLOTS);
+
+      if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+       zlog_info ("LSA[Refresh]: lsa with age %d added to index %d",
+                  LS_AGE (lsa), index);
+      if (!top->lsa_refresh_queue.qs[index])
+       top->lsa_refresh_queue.qs[index] = list_new ();
+      listnode_add (top->lsa_refresh_queue.qs[index], ospf_lsa_lock (lsa));
+      lsa->refresh_list = index;
+    }
+}
+
+void
+ospf_refresher_unregister_lsa (struct ospf *top, struct ospf_lsa *lsa)
+{
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
+  if (lsa->refresh_list >= 0)
+    {
+      list refresh_list = top->lsa_refresh_queue.qs[lsa->refresh_list];
+      listnode_delete (refresh_list, lsa);
+      if (!listcount (refresh_list))
+       {
+         list_free (refresh_list);
+         top->lsa_refresh_queue.qs[lsa->refresh_list] = NULL;
+       }
+      ospf_lsa_unlock (lsa);
+      lsa->refresh_list = -1;
+    }
+}
+
+int
+ospf_lsa_refresh_walker (struct thread *t)
+{
+  list refresh_list;
+  listnode node;
+  struct ospf *top = THREAD_ARG (t);
+  int i;
+  list lsa_to_refresh = list_new ();
+
+  if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+    zlog_info ("LSA[Refresh]:ospf_lsa_refresh_walker(): start");
+
+  
+  i = top->lsa_refresh_queue.index;
+  
+  top->lsa_refresh_queue.index =
+    (top->lsa_refresh_queue.index +
+     (time (NULL) - top->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)
+    % OSPF_LSA_REFRESHER_SLOTS;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+    zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d",
+              top->lsa_refresh_queue.index);
+
+  for (;i != top->lsa_refresh_queue.index;
+       i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+       zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh index %d", i);
+
+      refresh_list = top->lsa_refresh_queue.qs [i];
+      
+      top->lsa_refresh_queue.qs [i] = NULL;
+      
+      if (refresh_list)
+       {
+         for (node = listhead (refresh_list); node;)
+           {
+             listnode next;
+             struct ospf_lsa *lsa = getdata (node);
+             next = node->next;
+             
+             if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+               zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh lsa %p", lsa);
+             
+             list_delete_node (refresh_list, node);
+             ospf_lsa_unlock (lsa);
+             lsa->refresh_list = -1;
+             listnode_add (lsa_to_refresh, lsa);
+             node = next;
+           }
+         list_free (refresh_list);
+       }
+    }
+
+  top->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
+                                          top, top->lsa_refresh_interval);
+  top->lsa_refresher_started = time (NULL);
+
+  for (node = listhead (lsa_to_refresh); node; nextnode (node))
+    ospf_lsa_refresh (getdata (node));
+  
+  list_delete (lsa_to_refresh);
+  
+  if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+    zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): end");
+  
+  return 0;
+}
+
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
new file mode 100644 (file)
index 0000000..02fbe70
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * OSPF Link State Advertisement
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_LSA_H
+#define _ZEBRA_OSPF_LSA_H
+
+/* OSPF LSA Range definition. */
+#define OSPF_MIN_LSA           1  /* begin range here */
+#if defined (HAVE_OPAQUE_LSA)
+#define OSPF_MAX_LSA           12
+#elif defined (HAVE_NSSA)
+#define OSPF_MAX_LSA           8
+#else
+#define OSPF_MAX_LSA           6
+#endif
+
+/* OSPF LSA Type definition. */
+#define OSPF_UNKNOWN_LSA             0
+#define OSPF_ROUTER_LSA               1
+#define OSPF_NETWORK_LSA              2
+#define OSPF_SUMMARY_LSA              3
+#define OSPF_ASBR_SUMMARY_LSA         4
+#define OSPF_AS_EXTERNAL_LSA          5
+#define OSPF_GROUP_MEMBER_LSA        6  /* Not supported. */
+#define OSPF_AS_NSSA_LSA                     7
+#define OSPF_EXTERNAL_ATTRIBUTES_LSA  8  /* Not supported. */
+#define OSPF_OPAQUE_LINK_LSA         9
+#define OSPF_OPAQUE_AREA_LSA        10
+#define OSPF_OPAQUE_AS_LSA          11
+
+#define OSPF_LSA_HEADER_SIZE   20
+#define OSPF_MAX_LSA_SIZE      1500
+
+/* AS-external-LSA refresh method. */
+#define LSA_REFRESH_IF_CHANGED 0
+#define LSA_REFRESH_FORCE      1
+
+/* OSPF LSA header. */
+struct lsa_header
+{
+  u_int16_t ls_age;
+  u_char options;
+  u_char type;
+  struct in_addr id;
+  struct in_addr adv_router;
+  int ls_seqnum;
+  u_int16_t checksum;
+  u_int16_t length;
+};
+
+/* OSPF LSA. */
+struct ospf_lsa
+{
+  /* LSA origination flag. */
+  u_char flags;
+#define OSPF_LSA_SELF            0x01
+#define OSPF_LSA_SELF_CHECKED    0x02
+#define OSPF_LSA_RECEIVED        0x04
+#define OSPF_LSA_APPROVED        0x08
+#define OSPF_LSA_DISCARD         0x10
+#ifdef HAVE_NSSA
+#define OSPF_LSA_LOCAL_XLT       0x20
+#endif /* HAVE_NSSA */
+
+  /* LSA data. */
+  struct lsa_header *data;
+
+  /* Received time stamp. */
+  struct timeval tv_recv;
+
+  /* Last time it was originated */
+  struct timeval tv_orig;
+
+  /* All of reference count, also lock to remove. */
+  int lock;
+
+  /* References to this LSA in neighbor retransmission lists*/
+  int retransmit_counter;
+
+  /* Area the LSA belongs to, may be NULL if AS-external-LSA. */
+  struct ospf_area *area;
+
+  /* Parent LSDB. */
+  struct ospf_lsdb *lsdb;
+
+  /* Related Route. */
+  void *route;
+
+  /* Refreshement List or Queue */
+  int refresh_list;
+
+#ifdef HAVE_OPAQUE_LSA
+  /* For Type-9 Opaque-LSAs, reference to ospf-interface is required. */
+  struct ospf_interface *oi;
+#endif /* HAVE_OPAQUE_LSA */
+};
+
+/* OSPF LSA Link Type. */
+#define LSA_LINK_TYPE_POINTOPOINT      1
+#define LSA_LINK_TYPE_TRANSIT          2
+#define LSA_LINK_TYPE_STUB             3
+#define LSA_LINK_TYPE_VIRTUALLINK      4
+
+/* OSPF Router LSA Flag. */
+#define ROUTER_LSA_BORDER             0x01 /* The router is an ABR */
+#define ROUTER_LSA_EXTERNAL           0x02 /* The router is an ASBR */
+#define ROUTER_LSA_VIRTUAL            0x04 /* The router has a VL in this area */
+#define ROUTER_LSA_NT                 0x10 /* NSSA-specific flag */
+#define ROUTER_LSA_SHORTCUT           0x20 /* Shortcut-ABR specific flag */
+
+#define IS_ROUTER_LSA_VIRTUAL(x)       ((x)->flags & ROUTER_LSA_VIRTUAL)
+#define IS_ROUTER_LSA_EXTERNAL(x)      ((x)->flags & ROUTER_LSA_EXTERNAL)
+#define IS_ROUTER_LSA_BORDER(x)               ((x)->flags & ROUTER_LSA_BORDER)
+#define IS_ROUTER_LSA_SHORTCUT(x)      ((x)->flags & ROUTER_LSA_SHORTCUT)
+
+/* OSPF Router-LSA Link information. */
+struct router_lsa_link
+{
+  struct in_addr link_id;
+  struct in_addr link_data;
+  struct
+  {
+    u_char type;
+    u_char tos_count;
+    u_int16_t metric;
+  } m[1];
+};
+
+/* OSPF Router-LSAs structure. */
+struct router_lsa
+{
+  struct lsa_header header;
+  u_char flags;
+  u_char zero;
+  u_int16_t links;
+  struct
+  {
+    struct in_addr link_id;
+    struct in_addr link_data;
+    u_char type;
+    u_char tos;
+    u_int16_t metric;
+  } link[1];
+};
+
+/* OSPF Network-LSAs structure. */
+struct network_lsa
+{
+  struct lsa_header header;
+  struct in_addr mask;
+  struct in_addr routers[1];
+};
+
+/* OSPF Summary-LSAs structure. */
+struct summary_lsa
+{
+  struct lsa_header header;
+  struct in_addr mask;
+  u_char tos;
+  u_char metric[3];
+};
+
+/* OSPF AS-external-LSAs structure. */
+struct as_external_lsa
+{
+  struct lsa_header header;
+  struct in_addr mask;
+  struct
+  {
+    u_char tos;
+    u_char metric[3];
+    struct in_addr fwd_addr;
+    u_int32_t route_tag;
+  } e[1];
+};
+
+#ifdef HAVE_OPAQUE_LSA
+#include "ospfd/ospf_opaque.h"
+#endif /* HAVE_OPAQUE_LSA */
+
+/* Macros. */
+#define GET_METRIC(x) get_metric(x)
+#define IS_EXTERNAL_METRIC(x)   ((x) & 0x80)
+
+#define GET_AGE(x)     (ntohs ((x)->data->ls_age) + time (NULL) - (x)->tv_recv)
+#define LS_AGE(x)      (OSPF_LSA_MAXAGE < get_age(x) ? \
+                                           OSPF_LSA_MAXAGE : get_age(x))
+#define IS_LSA_SELF(L)          (CHECK_FLAG ((L)->flags, OSPF_LSA_SELF))
+#define IS_LSA_MAXAGE(L)        (LS_AGE ((L)) == OSPF_LSA_MAXAGE)
+
+#define OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX(A,P) \
+        foreach_lsa (SUMMARY_LSDB ((A)), \
+                     (struct prefix_ipv4 *) (P), 0, find_summary)
+
+#define OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX(A,P) \
+        foreach_lsa (ASBR_SUMMARY_LSDB ((A)), \
+                     (struct prefix_ipv4 *) (P), 0, find_asbr_summary)
+
+#define OSPF_LSA_UPDATE_DELAY          2
+
+#define OSPF_LSA_UPDATE_TIMER_ON(T,F) \
+      if (!(T)) \
+        (T) = thread_add_timer (master, (F), 0, 2)
+
+struct ospf_route;
+struct ospf_lsdb;
+
+/* Prototypes. */
+struct timeval tv_adjust (struct timeval);
+int tv_ceil (struct timeval);
+int tv_floor (struct timeval);
+struct timeval int2tv (int);
+struct timeval tv_add (struct timeval, struct timeval);
+struct timeval tv_sub (struct timeval, struct timeval);
+int tv_cmp (struct timeval, struct timeval);
+
+int get_age (struct ospf_lsa *);
+u_int16_t ospf_lsa_checksum (struct lsa_header *);
+
+struct stream;
+const char *dump_lsa_key (struct ospf_lsa *lsa);
+u_int32_t lsa_seqnum_increment (struct ospf_lsa *lsa);
+void lsa_header_set (struct stream *s, u_char options, u_char type, struct in_addr id);
+struct ospf_neighbor *ospf_nbr_lookup_ptop (struct route_table *nbrs, struct in_addr router_id);
+
+/* Prototype for LSA primitive. */
+struct ospf_lsa *ospf_lsa_new ();
+struct ospf_lsa *ospf_lsa_dup ();
+void ospf_lsa_free (struct ospf_lsa *lsa);
+struct ospf_lsa *ospf_lsa_lock (struct ospf_lsa *);
+void ospf_lsa_unlock (struct ospf_lsa *);
+void ospf_lsa_discard (struct ospf_lsa *);
+
+struct lsa_header *ospf_lsa_data_new (size_t);
+struct lsa_header *ospf_lsa_data_dup (struct lsa_header *);
+void ospf_lsa_data_free (struct lsa_header *);
+
+/* Prototype for various LSAs */
+struct ospf_lsa *ospf_router_lsa_originate (struct ospf_area *);
+int ospf_router_lsa_update_timer (struct thread *);
+void ospf_router_lsa_timer_add (struct ospf_area *);
+
+int ospf_network_lsa_refresh (struct ospf_lsa *, struct ospf_interface *);
+void ospf_network_lsa_timer_add (struct ospf_interface *);
+
+struct ospf_lsa *ospf_summary_lsa_originate (struct prefix_ipv4 *, u_int32_t,
+                                            struct ospf_area *);
+struct ospf_lsa *ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *,
+                                                 u_int32_t,
+                                                 struct ospf_area *);
+struct ospf_lsa *ospf_summary_lsa_refresh (struct ospf_lsa *);
+struct ospf_lsa *ospf_summary_asbr_lsa_refresh (struct ospf_lsa *);
+
+struct ospf_lsa *ospf_lsa_install (struct ospf_interface *, struct ospf_lsa *);
+
+void ospf_external_lsa_flush (u_char, struct prefix_ipv4 *,
+                             unsigned int, struct in_addr);
+
+struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *oi);
+
+struct ospf_lsa *ospf_external_lsa_originate (struct external_info *);
+int ospf_external_lsa_originate_timer (struct thread *);
+struct ospf_lsa *ospf_lsa_lookup (struct ospf_area *, u_int32_t,
+                                 struct in_addr, struct in_addr);
+struct ospf_lsa *ospf_lsa_lookup_by_id (struct ospf_area *,u_int32_t, struct in_addr);
+struct ospf_lsa *ospf_lsa_lookup_by_header (struct ospf_area *,
+                                           struct lsa_header *);
+int ospf_lsa_more_recent (struct ospf_lsa *, struct ospf_lsa *);
+int ospf_lsa_different (struct ospf_lsa *, struct ospf_lsa *);
+void ospf_flush_self_originated_lsas_now (struct ospf *top);
+
+int ospf_lsa_is_self_originated (struct ospf_lsa *);
+
+int find_summary (struct ospf_lsa *, void *, int);
+int find_asbr_summary (struct ospf_lsa *, void *, int);
+
+void ospf_lsa_maxage (struct ospf_lsa *);
+u_int32_t get_metric (u_char *);
+
+int ospf_lsa_maxage_walker (struct thread *);
+
+void ospf_external_lsa_refresh_default (void);
+
+void ospf_external_lsa_refresh_type (u_char, int);
+void ospf_external_lsa_refresh (struct ospf_lsa *, struct external_info *ei,
+                               int force);
+struct in_addr ospf_lsa_unique_id (struct ospf_lsdb *, u_char,
+                                  struct prefix_ipv4 *);
+void ospf_schedule_lsa_flood_area (struct ospf_area *, struct ospf_lsa *);
+void ospf_schedule_lsa_flush_area (struct ospf_area *, struct ospf_lsa *);
+
+void ospf_refresher_register_lsa (struct ospf *, struct ospf_lsa *);
+void ospf_refresher_unregister_lsa (struct ospf *, struct ospf_lsa *);
+int ospf_lsa_refresh_walker (struct thread *);
+
+void ospf_lsa_init ();
+
+void ospf_lsa_maxage_delete (struct ospf_lsa *);
+
+void ospf_discard_from_db (struct ospf_lsdb *, struct ospf_lsa*);
+int ospf_lsa_discard_callback (struct ospf_lsa *, void *, int);
+int is_prefix_default (struct prefix_ipv4 *);
+
+int metric_type (u_char);
+int metric_value (u_char);
+
+#endif /* _ZEBRA_OSPF_LSA_H */
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
new file mode 100644 (file)
index 0000000..46d8d70
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * OSPF LSDB support.
+ * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+\f
+struct ospf_lsdb *
+ospf_lsdb_new ()
+{
+  struct ospf_lsdb *new;
+
+  new = XCALLOC (MTYPE_OSPF_LSDB, sizeof (struct ospf_lsdb));
+  ospf_lsdb_init (new);
+
+  return new;
+}
+
+void
+ospf_lsdb_init (struct ospf_lsdb *lsdb)
+{
+  int i;
+  
+  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+    lsdb->type[i].db = route_table_init ();
+}
+
+void
+ospf_lsdb_free (struct ospf_lsdb *lsdb)
+{
+  ospf_lsdb_cleanup (lsdb);
+  XFREE (MTYPE_OSPF_LSDB, lsdb);
+}
+
+void
+ospf_lsdb_cleanup (struct ospf_lsdb *lsdb)
+{
+  int i;
+  assert (lsdb);
+  assert (lsdb->total == 0);
+
+  ospf_lsdb_delete_all (lsdb);
+  
+  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+    route_table_finish (lsdb->type[i].db);
+}
+
+void
+lsdb_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa)
+{
+  memset (lp, 0, sizeof (struct prefix_ls));
+  lp->family = 0;
+  lp->prefixlen = 64;
+  lp->id = lsa->data->id;
+  lp->adv_router = lsa->data->adv_router;
+}
+
+/* Add new LSA to lsdb. */
+void
+ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
+{
+  struct route_table *table;
+  struct prefix_ls lp;
+  struct route_node *rn;
+
+  table = lsdb->type[lsa->data->type].db;
+  lsdb_prefix_set (&lp, lsa);
+  rn = route_node_get (table, (struct prefix *)&lp);
+  if (!rn->info)
+    {
+      if (IS_LSA_SELF (lsa))
+       lsdb->type[lsa->data->type].count_self++;
+      lsdb->type[lsa->data->type].count++;
+      lsdb->total++;
+    }
+  else
+    {
+      if (rn->info == lsa)
+       return;
+      
+      ospf_lsa_unlock (rn->info);
+      route_unlock_node (rn);
+    }
+
+#ifdef MONITOR_LSDB_CHANGE
+  if (lsdb->new_lsa_hook != NULL)
+    (* lsdb->new_lsa_hook)(lsa);
+#endif /* MONITOR_LSDB_CHANGE */
+  rn->info = ospf_lsa_lock (lsa);
+}
+
+void
+ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
+{
+  struct route_table *table;
+  struct prefix_ls lp;
+  struct route_node *rn;
+
+  table = lsdb->type[lsa->data->type].db;
+  lsdb_prefix_set (&lp, lsa);
+  rn = route_node_lookup (table, (struct prefix *) &lp);
+  if (rn)
+    if (rn->info == lsa)
+      {
+       if (IS_LSA_SELF (lsa))
+         lsdb->type[lsa->data->type].count_self--;
+       lsdb->type[lsa->data->type].count--;
+       lsdb->total--;
+       rn->info = NULL;
+       route_unlock_node (rn);
+       route_unlock_node (rn);
+#ifdef MONITOR_LSDB_CHANGE
+        if (lsdb->del_lsa_hook != NULL)
+          (* lsdb->del_lsa_hook)(lsa);
+#endif /* MONITOR_LSDB_CHANGE */
+       ospf_lsa_unlock (lsa);
+       return;
+      }
+}
+
+void
+ospf_lsdb_delete_all (struct ospf_lsdb *lsdb)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct ospf_lsa *lsa;
+  int i;
+
+  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+    {
+      table = lsdb->type[i].db;
+      for (rn = route_top (table); rn; rn = route_next (rn))
+       if ((lsa = (rn->info)) != NULL)
+         {
+           if (IS_LSA_SELF (lsa))
+             lsdb->type[i].count_self--;
+           lsdb->type[i].count--;
+           lsdb->total--;
+           rn->info = NULL;
+           route_unlock_node (rn);
+#ifdef MONITOR_LSDB_CHANGE
+            if (lsdb->del_lsa_hook != NULL)
+              (* lsdb->del_lsa_hook)(lsa);
+#endif /* MONITOR_LSDB_CHANGE */
+           ospf_lsa_unlock (lsa);
+         }
+    }
+}
+
+struct ospf_lsa *
+ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
+{
+  struct route_table *table;
+  struct prefix_ls lp;
+  struct route_node *rn;
+  struct ospf_lsa *find;
+
+  table = lsdb->type[lsa->data->type].db;
+  lsdb_prefix_set (&lp, lsa);
+  rn = route_node_lookup (table, (struct prefix *) &lp);
+  if (rn)
+    {
+      find = rn->info;
+      route_unlock_node (rn);
+      return find;
+    }
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_lsdb_lookup_by_id (struct ospf_lsdb *lsdb, u_char type,
+                      struct in_addr id, struct in_addr adv_router)
+{
+  struct route_table *table;
+  struct prefix_ls lp;
+  struct route_node *rn;
+  struct ospf_lsa *find;
+
+  table = lsdb->type[type].db;
+
+  memset (&lp, 0, sizeof (struct prefix_ls));
+  lp.family = 0;
+  lp.prefixlen = 64;
+  lp.id = id;
+  lp.adv_router = adv_router;
+
+  rn = route_node_lookup (table, (struct prefix *) &lp);
+  if (rn)
+    {
+      find = rn->info;
+      route_unlock_node (rn);
+      return find;
+    }
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *lsdb, u_char type,
+                           struct in_addr id, struct in_addr adv_router,
+                           int first)
+{
+  struct route_table *table;
+  struct prefix_ls lp;
+  struct route_node *rn;
+  struct ospf_lsa *find;
+
+  table = lsdb->type[type].db;
+
+  memset (&lp, 0, sizeof (struct prefix_ls));
+  lp.family = 0;
+  lp.prefixlen = 64;
+  lp.id = id;
+  lp.adv_router = adv_router;
+
+  if (first)
+      rn = route_top (table);
+  else
+    {
+      rn = route_node_get (table, (struct prefix *) &lp);
+      rn = route_next (rn);
+    }
+
+  for (; rn; rn = route_next (rn))
+    if (rn->info)
+      break;
+
+  if (rn && rn->info)
+    {
+      find = rn->info;
+      route_unlock_node (rn);
+      return find;
+    }
+  return NULL;
+}
+
+unsigned long
+ospf_lsdb_count_all (struct ospf_lsdb *lsdb)
+{
+  return lsdb->total;
+}
+
+unsigned long
+ospf_lsdb_count (struct ospf_lsdb *lsdb, int type)
+{
+  return lsdb->type[type].count;
+}
+
+unsigned long
+ospf_lsdb_count_self (struct ospf_lsdb *lsdb, int type)
+{
+  return lsdb->type[type].count_self;
+}
+
+unsigned long
+ospf_lsdb_isempty (struct ospf_lsdb *lsdb)
+{
+  return (lsdb->total == 0);
+}
+
+struct ospf_lsa *
+foreach_lsa (struct route_table *table, void *p_arg, int int_arg, 
+            int (*callback) (struct ospf_lsa *, void *, int))
+{
+  struct route_node *rn;
+  struct ospf_lsa *lsa;
+
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    if ((lsa = rn->info) != NULL)
+      if (callback (lsa, p_arg, int_arg))
+       return lsa;
+
+  return NULL;
+}
diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h
new file mode 100644 (file)
index 0000000..34344b3
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * OSPF LSDB support.
+ * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_LSDB_H
+#define _ZEBRA_OSPF_LSDB_H
+
+/* OSPF LSDB structure. */
+struct ospf_lsdb
+{
+  struct
+  {
+    unsigned long count;
+    unsigned long count_self;
+    struct route_table *db;
+  } type[OSPF_MAX_LSA];
+  unsigned long total;
+#define MONITOR_LSDB_CHANGE 1 /* XXX */
+#ifdef MONITOR_LSDB_CHANGE
+  /* Hooks for callback functions to catch every add/del event. */
+  int (* new_lsa_hook)(struct ospf_lsa *);
+  int (* del_lsa_hook)(struct ospf_lsa *);
+#endif /* MONITOR_LSDB_CHANGE */
+};
+
+/* Macros. */
+#define LSDB_LOOP(T,N,L) \
+  for ((N) = route_top ((T)); ((N)); ((N)) = route_next ((N))) \
+    if (((L) = (N)->info))
+
+#define ROUTER_LSDB(A)       ((A)->lsdb->type[OSPF_ROUTER_LSA].db)
+#define NETWORK_LSDB(A)             ((A)->lsdb->type[OSPF_NETWORK_LSA].db)
+#define SUMMARY_LSDB(A)      ((A)->lsdb->type[OSPF_SUMMARY_LSA].db)
+#define ASBR_SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_ASBR_SUMMARY_LSA].db)
+#define EXTERNAL_LSDB(O)     ((O)->lsdb->type[OSPF_AS_EXTERNAL_LSA].db)
+#define NSSA_LSDB(A)         ((A)->lsdb->type[OSPF_AS_NSSA_LSA].db)
+#define OPAQUE_LINK_LSDB(A)  ((A)->lsdb->type[OSPF_OPAQUE_LINK_LSA].db)
+#define OPAQUE_AREA_LSDB(A)  ((A)->lsdb->type[OSPF_OPAQUE_AREA_LSA].db)
+#define OPAQUE_AS_LSDB(O)    ((O)->lsdb->type[OSPF_OPAQUE_AS_LSA].db)
+
+#define AREA_LSDB(A,T)       ((A)->lsdb->type[(T)].db)
+#define AS_LSDB(O,T)         ((O)->lsdb->type[(T)].db)
+
+/* OSPF LSDB related functions. */
+struct ospf_lsdb *ospf_lsdb_new ();
+void ospf_lsdb_init (struct ospf_lsdb *);
+void ospf_lsdb_free (struct ospf_lsdb *);
+void ospf_lsdb_cleanup (struct ospf_lsdb *);
+void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *);
+void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *);
+void ospf_lsdb_delete_all (struct ospf_lsdb *);
+struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *);
+struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char,
+                                       struct in_addr, struct in_addr);
+struct ospf_lsa *ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *, u_char,
+                                            struct in_addr, struct in_addr,
+                                            int);
+unsigned long ospf_lsdb_count_all (struct ospf_lsdb *);
+unsigned long ospf_lsdb_count (struct ospf_lsdb *, int);
+unsigned long ospf_lsdb_count_self (struct ospf_lsdb *, int);
+unsigned long ospf_lsdb_isempty (struct ospf_lsdb *);
+struct ospf_lsa *foreach_lsa (struct route_table *, void *, int,
+                     int (*callback) (struct ospf_lsa *, void *, int));
+
+#endif /* _ZEBRA_OSPF_LSDB_H */
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
new file mode 100644 (file)
index 0000000..82960b2
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * OSPFd main routine.
+ *   Copyright (C) 1998, 99 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "thread.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "filter.h"
+#include "plist.h"
+#include "stream.h"
+#include "log.h"
+#include "memory.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_vty.h"
+
+/* Configuration filename and directory. */
+char config_current[] = OSPF_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG;
+
+/* OSPFd options. */
+struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "log_mode",    no_argument,       NULL, 'l'},
+  { "help",        no_argument,       NULL, 'h'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "version",     no_argument,       NULL, 'v'},
+  { 0 }
+};
+
+/* OSPFd program name */
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_OSPFD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\
+Daemon which manages OSPF.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+  exit (status);
+}
+\f
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog (NULL, LOG_INFO, "SIGHUP received");
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog (NULL, LOG_INFO, "Terminating on signal");
+
+  ospf_terminate ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Signal wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+#ifdef SIGTSTP
+  signal_set (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+  signal_set (SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+  signal_set (SIGTTOU, SIG_IGN);
+#endif
+  signal_set (SIGUSR1, sigusr1);
+}
+\f
+/* OSPFd main routine. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  char *vty_addr = NULL;
+  int vty_port = 0;
+  int daemon_mode = 0;
+  char *config_file = NULL;
+  char *progname;
+  struct thread thread;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* get program name */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  /* Invoked by a priviledged user? -- endo. */
+  if (getuid () != 0)
+    {
+      errno = EPERM;
+      perror (progname);
+      exit (1);
+    }
+
+  zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_OSPF,
+                          LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  while (1) 
+    {
+      int opt;
+
+      opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0);
+    
+      if (opt == EOF)
+       break;
+
+      switch (opt) 
+       {
+       case 0:
+         break;
+       case 'd':
+         daemon_mode = 1;
+         break;
+       case 'f':
+         config_file = optarg;
+         break;
+       case 'A':
+         vty_addr = optarg;
+         break;
+        case 'i':
+          pid_file = optarg;
+          break;
+       case 'P':
+         vty_port = atoi (optarg);
+         break;
+       case 'v':
+         print_version (progname);
+         exit (0);
+         break;
+       case 'h':
+         usage (progname, 0);
+         break;
+       default:
+         usage (progname, 1);
+         break;
+       }
+    }
+
+  /* Initializations. */
+  master = thread_master_create ();
+
+  /* Library inits. */
+  signal_init ();
+  cmd_init (1);
+  debug_init ();
+  vty_init ();
+  memory_init ();
+
+  access_list_init ();
+  prefix_list_init ();
+
+  /* OSPFd inits. */
+  ospf_init ();
+  ospf_if_init ();
+  ospf_zebra_init ();
+
+  /* OSPF vty inits. */
+  ospf_vty_init ();
+  ospf_vty_show_init ();
+
+  ospf_route_map_init ();
+#ifdef HAVE_SNMP
+  ospf_snmp_init ();
+#endif /* HAVE_SNMP */
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_init ();
+#endif /* HAVE_OPAQUE_LSA */
+  
+  sort_node ();
+
+  /* Get configuration file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Change to the daemon program. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Process id file create. */
+  pid_output (pid_file);
+
+  /* Create VTY socket */
+  vty_serv_sock (vty_addr,
+                vty_port ? vty_port : OSPF_VTY_PORT, OSPF_VTYSH_PATH);
+
+  /* Print banner. */
+  zlog (NULL, LOG_INFO, "OSPFd (%s) starts", ZEBRA_VERSION);
+
+  /* Fetch next active thread. */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached. */
+  exit (0);
+}
+
diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h
new file mode 100644 (file)
index 0000000..f7b1874
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * OSPF Neighbor functions.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_NEIGHBOR_H
+#define _ZEBRA_OSPF_NEIGHBOR_H
+
+/* Neighbor Data Structure */
+struct ospf_neighbor
+{
+  /* This neighbor's parent ospf interface. */
+  struct ospf_interface *oi;
+
+  /* OSPF neighbor Information */
+  u_char state;                                /* NSM status. */
+  u_char dd_flags;                     /* DD bit flags. */
+  u_int32_t dd_seqnum;                 /* DD Sequence Number. */
+
+  /* Neighbor Information from Hello. */
+  struct prefix address;               /* Neighbor Interface Address. */
+
+  struct in_addr src;                  /* Src address. */
+  struct in_addr router_id;            /* Router ID. */
+  u_char options;                      /* Options. */
+  int priority;                                /* Router Priority. */
+  struct in_addr d_router;             /* Designated Router. */
+  struct in_addr bd_router;            /* Backup Designated Router. */
+
+  /* Last sent Database Description packet. */
+  struct ospf_packet *last_send;
+  /* Timestemp when last Database Description packet was sent */
+  struct timeval last_send_ts;
+
+  /* Last received Databse Description packet. */
+  struct
+  {
+    u_char options;
+    u_char flags;
+    u_int32_t dd_seqnum;
+  } last_recv;
+
+  /* LSA data. */
+  struct ospf_lsdb ls_rxmt;
+  struct ospf_lsdb db_sum;
+  struct ospf_lsdb ls_req;
+  struct ospf_lsa *ls_req_last;
+
+  u_int32_t crypt_seqnum;           /* Cryptographic Sequence Number. */
+
+  /* Timer values. */
+  u_int32_t v_inactivity;
+  u_int32_t v_db_desc;
+  u_int32_t v_ls_req;
+  u_int32_t v_ls_upd;
+
+  /* Threads. */
+  struct thread *t_inactivity;
+  struct thread *t_db_desc;
+  struct thread *t_ls_req;
+  struct thread *t_ls_upd;
+  struct thread *t_hello_reply;
+
+  /* Statistics Field */
+  u_int32_t state_change;
+  struct ospf_nbr_nbma *nbr_nbma;
+};
+
+/* Macros. */
+#define NBR_IS_DR(n)   IPV4_ADDR_SAME (&n->address.u.prefix4, &n->d_router)
+#define NBR_IS_BDR(n)   IPV4_ADDR_SAME (&n->address.u.prefix4, &n->bd_router)
+
+/* Prototypes. */
+struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *);
+void ospf_nbr_free (struct ospf_neighbor *);
+void ospf_nbr_delete (struct ospf_neighbor *);
+int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int);
+void ospf_nbr_add_self (struct ospf_interface *);
+int ospf_nbr_count (struct route_table *, int);
+#ifdef HAVE_OPAQUE_LSA
+int ospf_opaque_capable_nbr_count (struct route_table *nbrs, int status);
+#endif /* HAVE_OPAQUE_LSA */
+struct ospf_neighbor *ospf_nbr_lookup_by_addr (struct route_table *,
+                                              struct in_addr *);
+struct ospf_neighbor *ospf_nbr_lookup_by_routerid (struct route_table *,
+                                                  struct in_addr *);
+void ospf_renegotiate_optional_capabilities (struct ospf *top);
+
+#endif /* _ZEBRA_OSPF_NEIGHBOR_H */
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
new file mode 100644 (file)
index 0000000..56ec864
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * OSPF network related functions
+ *   Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "sockunion.h"
+#include "log.h"
+#include "sockopt.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_packet.h"
+
+/* Join to the OSPF ALL SPF ROUTERS multicast group. */
+int
+ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p,
+                          unsigned int ifindex)
+{
+  int ret;
+  
+  ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP,
+                                   p->u.prefix4, htonl (OSPF_ALLSPFROUTERS),
+                                   ifindex);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllSPFRouters): %s",
+               strerror (errno));
+  else
+    zlog_info ("interface %s join AllSPFRouters Multicast group.",
+              inet_ntoa (p->u.prefix4));
+
+  return ret;
+}
+
+int
+ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p,
+                           unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP,
+                                   p->u.prefix4, htonl (OSPF_ALLSPFROUTERS),
+                                   ifindex);
+  if (ret < 0)
+    zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (AllSPFRouters): %s",
+             strerror (errno));
+  else
+    zlog_info ("interface %s leave AllSPFRouters Multicast group.",
+              inet_ntoa (p->u.prefix4));
+
+  return ret;
+}
+
+/* Join to the OSPF ALL Designated ROUTERS multicast group. */
+int
+ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int
+                        ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP,
+                                   p->u.prefix4, htonl (OSPF_ALLDROUTERS),
+                                   ifindex);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllDRouters): %s",
+               strerror (errno));
+  else
+    zlog_info ("interface %s join AllDRouters Multicast group.",
+              inet_ntoa (p->u.prefix4));
+
+  return ret;
+}
+
+int
+ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int
+                         ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP,
+                                   p->u.prefix4, htonl (OSPF_ALLDROUTERS),
+                                   ifindex);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (AllDRouters): %s",
+              strerror (errno));
+  else
+    zlog_info ("interface %s leave AllDRouters Multicast group.",
+              inet_ntoa (p->u.prefix4));
+
+  return ret;
+}
+
+int
+ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex)
+{
+  u_char val;
+  int ret, len;
+  
+  val = 0;
+  len = sizeof (val);
+  
+  /* Prevent receiving self-origined multicast packets. */
+  ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0): %s", strerror (errno));
+  
+  /* Explicitly set multicast ttl to 1 -- endo. */
+  val = 1;
+  ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1): %s", strerror (errno));
+
+  ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF,
+                                   p->u.prefix4, 0, ifindex);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IP_MULTICAST_IF: %s", strerror (errno));
+
+  return ret;
+}
+
+int
+ospf_sock_init (void)
+{
+  int ospf_sock;
+  int ret, tos, hincl = 1;
+
+  ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP);
+  if (ospf_sock < 0)
+    {
+      zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Set precedence field. */
+#ifdef IPTOS_PREC_INTERNETCONTROL
+  tos = IPTOS_PREC_INTERNETCONTROL;
+  ret = setsockopt (ospf_sock, IPPROTO_IP, IP_TOS,
+                   (char *) &tos, sizeof (int));
+  if (ret < 0)
+    {
+      zlog_warn ("can't set sockopt IP_TOS %d to socket %d", tos, ospf_sock);
+      close (ospf_sock);       /* Prevent sd leak. */
+      return ret;
+    }
+#endif /* IPTOS_PREC_INTERNETCONTROL */
+
+  /* we will include IP header with packet */
+  ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl));
+  if (ret < 0)
+    zlog_warn ("Can't set IP_HDRINCL option");
+
+#if defined (IP_PKTINFO)
+  ret = setsockopt (ospf_sock, IPPROTO_IP, IP_PKTINFO, &hincl, sizeof (hincl));
+   if (ret < 0)
+    zlog_warn ("Can't set IP_PKTINFO option");
+#elif defined (IP_RECVIF)
+  ret = setsockopt (ospf_sock, IPPROTO_IP, IP_RECVIF, &hincl, sizeof (hincl));
+   if (ret < 0)
+    zlog_warn ("Can't set IP_RECVIF option");
+#else
+#warning "cannot be able to receive link information on this OS"
+#endif
+  return ospf_sock;
+}
diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h
new file mode 100644 (file)
index 0000000..52a25fd
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * OSPF network related functions.
+ *   Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_NETWORK_H
+#define _ZEBRA_OSPF_NETWORK_H
+
+/* Prototypes. */
+int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, unsigned int);
+int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int);
+int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int);
+int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int);
+int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int);
+int ospf_sock_init (void);
+
+#endif /* _ZEBRA_OSPF_NETWORK_H */
diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h
new file mode 100644 (file)
index 0000000..3d25730
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * OSPF version 2  Neighbor State Machine
+ *   From RFC2328 [OSPF Version 2]
+ *   Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_NSM_H
+#define _ZEBRA_OSPF_NSM_H
+
+/* OSPF Neighbor State Machine State. */
+#define NSM_DependUpon          0
+#define NSM_Down               1
+#define NSM_Attempt            2
+#define NSM_Init               3
+#define NSM_TwoWay             4
+#define NSM_ExStart            5
+#define NSM_Exchange           6
+#define NSM_Loading            7
+#define NSM_Full               8
+#define OSPF_NSM_STATE_MAX      9
+
+/* OSPF Neighbor State Machine Event. */
+#define NSM_NoEvent            0
+#define NSM_HelloReceived      1
+#define NSM_Start              2
+#define NSM_TwoWayReceived     3
+#define NSM_NegotiationDone    4
+#define NSM_ExchangeDone       5
+#define NSM_BadLSReq           6
+#define NSM_LoadingDone                7
+#define NSM_AdjOK              8
+#define NSM_SeqNumberMismatch  9
+#define NSM_OneWayReceived     10
+#define NSM_KillNbr           11
+#define NSM_InactivityTimer    12
+#define NSM_LLDown            13
+#define OSPF_NSM_EVENT_MAX     14
+
+/* Macro for OSPF NSM timer turn on. */
+#define OSPF_NSM_TIMER_ON(T,F,V) \
+      do { \
+        if (!(T)) \
+          (T) = thread_add_timer (master, (F), nbr, (V)); \
+      } while (0)
+
+/* Macro for OSPF NSM timer turn off. */
+#define OSPF_NSM_TIMER_OFF(X) \
+      do { \
+        if (X) \
+          { \
+            thread_cancel (X); \
+            (X) = NULL; \
+          } \
+      } while (0)
+
+/* Macro for OSPF NSM schedule event. */
+#define OSPF_NSM_EVENT_SCHEDULE(N,E) \
+      thread_add_event (master, ospf_nsm_event, (N), (E))
+
+/* Macro for OSPF NSM execute event. */
+#define OSPF_NSM_EVENT_EXECUTE(N,E) \
+      thread_execute (master, ospf_nsm_event, (N), (E))
+
+/* Prototypes. */
+int ospf_nsm_event (struct thread *);
+void nsm_change_state (struct ospf_neighbor *, int);
+void ospf_check_nbr_loading (struct ospf_neighbor *);
+int ospf_db_summary_isempty (struct ospf_neighbor *);
+int ospf_db_summary_count (struct ospf_neighbor *);
+void ospf_db_summary_clear (struct ospf_neighbor *);
+/* void ospf_db_summary_delete_all (struct ospf_neighbor *); */
+
+#endif /* _ZEBRA_OSPF_NSM_H */
+
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
new file mode 100644 (file)
index 0000000..67c6608
--- /dev/null
@@ -0,0 +1,2392 @@
+/*
+ * This is an implementation of rfc2370.
+ * Copyright (C) 2001 KDD R&D Laboratories, Inc.
+ * http://www.kddlabs.co.jp/
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/***** MTYPE definitions are not reflected to "memory.h" yet. *****/
+#define MTYPE_OSPF_OPAQUE_FUNCTAB      0
+#define MTYPE_OPAQUE_INFO_PER_TYPE     0
+#define MTYPE_OPAQUE_INFO_PER_ID       0
+
+#include <zebra.h>
+#ifdef HAVE_OPAQUE_LSA
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h"         /* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+
+/*------------------------------------------------------------------------*
+ * Followings are initialize/terminate functions for Opaque-LSAs handling.
+ *------------------------------------------------------------------------*/
+
+#ifdef HAVE_OSPF_TE
+#include "ospfd/ospf_te.h"
+#endif /* HAVE_OSPF_TE */
+
+static void ospf_opaque_register_vty (void);
+static void ospf_opaque_funclist_init (void);
+static void ospf_opaque_funclist_term (void);
+static void free_opaque_info_per_type (void *val);
+static void free_opaque_info_per_id (void *val);
+static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa);
+static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa);
+
+void
+ospf_opaque_init (void)
+{
+  ospf_opaque_register_vty ();
+  ospf_opaque_funclist_init ();
+
+#ifdef HAVE_OSPF_TE
+  if (ospf_mpls_te_init () != 0)
+    exit (1);
+#endif /* HAVE_OSPF_TE */
+
+  return;
+}
+
+void
+ospf_opaque_term (void)
+{
+#ifdef HAVE_OSPF_TE
+  ospf_mpls_te_term ();
+#endif /* HAVE_OSPF_TE */
+
+  ospf_opaque_funclist_term ();
+  return;
+}
+
+int
+ospf_opaque_type9_lsa_init (struct ospf_interface *oi)
+{
+  if (oi->opaque_lsa_self != NULL)
+    list_delete (oi->opaque_lsa_self);
+
+  oi->opaque_lsa_self = list_new ();
+  oi->opaque_lsa_self->del = free_opaque_info_per_type;
+  oi->t_opaque_lsa_self = NULL;
+  return 0;
+}
+
+void
+ospf_opaque_type9_lsa_term (struct ospf_interface *oi)
+{
+  OSPF_TIMER_OFF (oi->t_opaque_lsa_self);
+  if (oi->opaque_lsa_self != NULL)
+    list_delete (oi->opaque_lsa_self);
+  oi->opaque_lsa_self = NULL;
+  return;
+}
+
+int
+ospf_opaque_type10_lsa_init (struct ospf_area *area)
+{
+  if (area->opaque_lsa_self != NULL)
+    list_delete (area->opaque_lsa_self);
+
+  area->opaque_lsa_self = list_new ();
+  area->opaque_lsa_self->del = free_opaque_info_per_type;
+  area->t_opaque_lsa_self = NULL;
+
+#ifdef MONITOR_LSDB_CHANGE
+  area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
+  area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
+#endif /* MONITOR_LSDB_CHANGE */
+  return 0;
+}
+
+void
+ospf_opaque_type10_lsa_term (struct ospf_area *area)
+{
+#ifdef MONITOR_LSDB_CHANGE
+  area->lsdb->new_lsa_hook = 
+  area->lsdb->del_lsa_hook = NULL;
+#endif /* MONITOR_LSDB_CHANGE */
+
+  OSPF_TIMER_OFF (area->t_opaque_lsa_self);
+  if (area->opaque_lsa_self != NULL)
+    list_delete (area->opaque_lsa_self);
+  area->opaque_lsa_self = NULL;
+  return;
+}
+
+int
+ospf_opaque_type11_lsa_init (struct ospf *top)
+{
+  if (top->opaque_lsa_self != NULL)
+    list_delete (top->opaque_lsa_self);
+
+  top->opaque_lsa_self = list_new ();
+  top->opaque_lsa_self->del = free_opaque_info_per_type;
+  top->t_opaque_lsa_self = NULL;
+
+#ifdef MONITOR_LSDB_CHANGE
+  top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
+  top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
+#endif /* MONITOR_LSDB_CHANGE */
+  return 0;
+}
+
+void
+ospf_opaque_type11_lsa_term (struct ospf *top)
+{
+#ifdef MONITOR_LSDB_CHANGE
+  top->lsdb->new_lsa_hook = 
+  top->lsdb->del_lsa_hook = NULL;
+#endif /* MONITOR_LSDB_CHANGE */
+
+  OSPF_TIMER_OFF (top->t_opaque_lsa_self);
+  if (top->opaque_lsa_self != NULL)
+    list_delete (top->opaque_lsa_self);
+  top->opaque_lsa_self = NULL;
+  return;
+}
+
+static const char *
+ospf_opaque_type_name (u_char opaque_type)
+{
+  const char *name = "Unknown";
+
+  switch (opaque_type)
+    {
+    case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */
+      name = "Wildcard";
+      break;
+    case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA:
+      name = "Traffic Engineering LSA";
+      break;
+    case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC:
+      name = "Sycamore optical topology description";
+      break;
+    case OPAQUE_TYPE_GRACE_LSA:
+      name = "Grace-LSA";
+      break;
+    default:
+      if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type))
+        name = "Unassigned";
+      else if (OPAQUE_TYPE_RANGE_RESERVED (opaque_type))
+        name = "Private/Experimental";
+      break;
+    }
+  return name;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are management functions to store user specified callbacks.
+ *------------------------------------------------------------------------*/
+
+struct opaque_info_per_type; /* Forward declaration. */
+
+struct ospf_opaque_functab
+{
+  u_char opaque_type;
+  struct opaque_info_per_type *oipt;
+
+  int (* new_if_hook)(struct interface *ifp);
+  int (* del_if_hook)(struct interface *ifp);
+  void (* ism_change_hook)(struct ospf_interface *oi, int old_status);
+  void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status);
+  void (* config_write_router)(struct vty *vty);
+  void (* config_write_if    )(struct vty *vty, struct interface *ifp);
+  void (* config_write_debug )(struct vty *vty);
+  void (* show_opaque_info   )(struct vty *vty, struct ospf_lsa *lsa);
+  int  (* lsa_originator)(void *arg);
+  void (* lsa_refresher )(struct ospf_lsa *lsa);
+  int (* new_lsa_hook)(struct ospf_lsa *lsa);
+  int (* del_lsa_hook)(struct ospf_lsa *lsa);
+};
+
+static list ospf_opaque_type9_funclist;
+static list ospf_opaque_type10_funclist;
+static list ospf_opaque_type11_funclist;
+
+static void
+ospf_opaque_del_functab (void *val)
+{
+  XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, val);
+  return;
+}
+
+static void
+ospf_opaque_funclist_init (void)
+{
+  list funclist;
+
+  funclist = ospf_opaque_type9_funclist  = list_new ();
+  funclist->del = ospf_opaque_del_functab;
+
+  funclist = ospf_opaque_type10_funclist = list_new ();
+  funclist->del = ospf_opaque_del_functab;
+
+  funclist = ospf_opaque_type11_funclist = list_new ();
+  funclist->del = ospf_opaque_del_functab;
+  return;
+}
+
+static void
+ospf_opaque_funclist_term (void)
+{
+  list funclist;
+
+  funclist = ospf_opaque_type9_funclist;
+  list_delete (funclist);
+
+  funclist = ospf_opaque_type10_funclist;
+  list_delete (funclist);
+
+  funclist = ospf_opaque_type11_funclist;
+  list_delete (funclist);
+  return;
+}
+
+static list
+ospf_get_opaque_funclist (u_char lsa_type)
+{
+  list funclist = NULL;
+
+  switch (lsa_type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+      funclist = ospf_opaque_type9_funclist;
+      break;
+    case OSPF_OPAQUE_AREA_LSA:
+      funclist = ospf_opaque_type10_funclist;
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      funclist = ospf_opaque_type11_funclist;
+      break;
+    default:
+      zlog_warn ("ospf_get_opaque_funclist: Unexpected LSA-type(%u)", lsa_type);
+      break;
+    }
+  return funclist;
+}
+
+int
+ospf_register_opaque_functab (
+  u_char lsa_type,
+  u_char opaque_type,
+  int (* new_if_hook)(struct interface *ifp),
+  int (* del_if_hook)(struct interface *ifp),
+  void (* ism_change_hook)(struct ospf_interface *oi, int old_status),
+  void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status),
+  void (* config_write_router)(struct vty *vty),
+  void (* config_write_if    )(struct vty *vty, struct interface *ifp),
+  void (* config_write_debug )(struct vty *vty),
+  void (* show_opaque_info   )(struct vty *vty, struct ospf_lsa *lsa),
+  int  (* lsa_originator)(void *arg),
+  void (* lsa_refresher )(struct ospf_lsa *lsa),
+  int (* new_lsa_hook)(struct ospf_lsa *lsa),
+  int (* del_lsa_hook)(struct ospf_lsa *lsa))
+{
+  list funclist;
+  struct ospf_opaque_functab *new;
+  int rc = -1;
+
+  if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL)
+    {
+      zlog_warn ("ospf_register_opaque_functab: Cannot get funclist for Type-%u LSAs?", lsa_type);
+      goto out;
+    }
+  else
+    {
+      listnode node;
+      struct ospf_opaque_functab *functab;
+
+      for (node = listhead (funclist); node; nextnode (node))
+        if ((functab = getdata (node)) != NULL)
+          if (functab->opaque_type == opaque_type)
+            {
+              zlog_warn ("ospf_register_opaque_functab: Duplicated entry?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type);
+              goto out;
+            }
+    }
+
+  if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB,
+                     sizeof (struct ospf_opaque_functab))) == NULL)
+    {
+      zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s", strerror (errno));
+      goto out;
+    }
+
+  new->opaque_type    = opaque_type;
+  new->oipt           = NULL;
+  new->new_if_hook    = new_if_hook;
+  new->del_if_hook    = del_if_hook;
+  new->ism_change_hook     = ism_change_hook;
+  new->nsm_change_hook     = nsm_change_hook;
+  new->config_write_router = config_write_router;
+  new->config_write_if     = config_write_if;
+  new->config_write_debug  = config_write_debug;
+  new->show_opaque_info    = show_opaque_info;
+  new->lsa_originator = lsa_originator;
+  new->lsa_refresher  = lsa_refresher;
+  new->new_lsa_hook   = new_lsa_hook;
+  new->del_lsa_hook   = del_lsa_hook;
+
+  listnode_add (funclist, new);
+  rc = 0;
+
+out:
+  return rc;
+}
+
+void
+ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type)
+{
+  list funclist;
+  listnode node;
+  struct ospf_opaque_functab *functab;
+
+  if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL)
+    for (node = listhead (funclist); node; nextnode (node))
+      {
+        if ((functab = getdata (node)) != NULL
+        &&   functab->opaque_type == opaque_type)
+          {
+            /* Cleanup internal control information, if it still remains. */
+            if (functab->oipt != NULL)
+              free_opaque_info_per_type (functab->oipt);
+
+            /* Dequeue listnode entry from the list. */
+            listnode_delete (funclist, functab);
+
+            /* Avoid misjudgement in the next lookup. */
+            if (listcount (funclist) == 0)
+              funclist->head = funclist->tail = NULL;
+
+            XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, functab);
+            goto out;
+         }
+      }
+out:
+  return;
+}
+
+static struct ospf_opaque_functab *
+ospf_opaque_functab_lookup (struct ospf_lsa *lsa)
+{
+  list funclist;
+  listnode node;
+  struct ospf_opaque_functab *functab;
+  u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr));
+
+  if ((funclist = ospf_get_opaque_funclist (lsa->data->type)) != NULL)
+    for (node = listhead (funclist); node; nextnode (node))
+      if ((functab = getdata (node)) != NULL)
+        if (functab->opaque_type == key)
+          return functab;
+
+  return NULL;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are management functions for self-originated LSA entries.
+ *------------------------------------------------------------------------*/
+
+/*
+ * Opaque-LSA control information per opaque-type.
+ * Single Opaque-Type may have multiple instances; each of them will be
+ * identified by their opaque-id.
+ */
+struct opaque_info_per_type
+{
+  u_char opaque_type;
+
+  enum { PROC_NORMAL, PROC_SUSPEND } status;
+
+  /*
+   * Thread for (re-)origination scheduling for this opaque-type.
+   *
+   * Initial origination of Opaque-LSAs is controlled by generic
+   * Opaque-LSA handling module so that same opaque-type entries are
+   * called all at once when certain conditions are met.
+   * However, there might be cases that some Opaque-LSA clients need
+   * to (re-)originate their own Opaque-LSAs out-of-sync with others.
+   * This thread is prepared for that specific purpose.
+   */
+  struct thread *t_opaque_lsa_self;
+
+  /*
+   * Backpointer to an "owner" which is opaque-type dependent.
+   *   type-9:  struct ospf_interface
+   *   type-10: struct ospf_area
+   *   type-11: struct ospf
+   */
+  void *owner;
+
+  /* Collection of callback functions for this opaque-type. */
+  struct ospf_opaque_functab *functab;
+
+  /* List of Opaque-LSA control informations per opaque-id. */
+  list id_list;
+};
+
+/* Opaque-LSA control information per opaque-id. */
+struct opaque_info_per_id
+{
+  u_int32_t opaque_id;
+
+  /* Thread for refresh/flush scheduling for this opaque-type/id. */
+  struct thread *t_opaque_lsa_self;
+
+  /* Backpointer to Opaque-LSA control information per opaque-type. */
+  struct opaque_info_per_type *opqctl_type;
+
+  /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */
+  struct ospf_lsa *lsa;
+};
+
+static struct opaque_info_per_type *register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new);
+static struct opaque_info_per_type *lookup_opaque_info_by_type (struct ospf_lsa *lsa);
+static struct opaque_info_per_id *register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new);
+static struct opaque_info_per_id *lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa);
+static struct opaque_info_per_id *register_opaque_lsa (struct ospf_lsa *new);
+
+
+static struct opaque_info_per_type *
+register_opaque_info_per_type (struct ospf_opaque_functab *functab,
+                               struct ospf_lsa *new)
+{
+  struct ospf *top;
+  struct opaque_info_per_type *oipt;
+
+  if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE,
+                      sizeof (struct opaque_info_per_type))) == NULL)
+    {
+      zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", strerror (errno));
+      goto out;
+    }
+
+  switch (new->data->type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+      oipt->owner = new->oi;
+      listnode_add (new->oi->opaque_lsa_self, oipt);
+      break;
+    case OSPF_OPAQUE_AREA_LSA:
+      oipt->owner = new->area;
+      listnode_add (new->area->opaque_lsa_self, oipt);
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      top = ospf_top;
+      if (new->area != NULL && (top = new->area->top) == NULL)
+        {
+          free_opaque_info_per_type ((void *) oipt);
+          oipt = NULL;
+          goto out; /* This case may not exist. */
+        }
+      oipt->owner = top;
+      listnode_add (top->opaque_lsa_self, oipt);
+      break;
+    default:
+      free_opaque_info_per_type ((void *) oipt);
+      oipt = NULL;
+      goto out; /* This case may not exist. */
+    }
+
+  oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr));
+  oipt->status = PROC_NORMAL;
+  oipt->t_opaque_lsa_self = NULL;
+  oipt->functab = functab;
+  functab->oipt = oipt;
+  oipt->id_list = list_new ();
+  oipt->id_list->del = free_opaque_info_per_id;
+
+out:
+  return oipt;
+}
+
+static void
+free_opaque_info_per_type (void *val)
+{
+  struct opaque_info_per_type *oipt = (struct opaque_info_per_type *) val;
+  struct opaque_info_per_id *oipi;
+  struct ospf_lsa *lsa;
+  listnode node;
+
+  /* Control information per opaque-id may still exist. */
+  for (node = listhead (oipt->id_list); node; nextnode (node))
+    {
+      if ((oipi = getdata (node)) == NULL)
+        continue;
+      if ((lsa = oipi->lsa) == NULL)
+        continue;
+      if (IS_LSA_MAXAGE (lsa))
+        continue;
+      ospf_opaque_lsa_flush_schedule (lsa);
+    }
+
+  OSPF_TIMER_OFF (oipt->t_opaque_lsa_self);
+  list_delete (oipt->id_list);
+  XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
+  return;
+}
+
+static struct opaque_info_per_type *
+lookup_opaque_info_by_type (struct ospf_lsa *lsa)
+{
+  struct ospf *top;
+  struct ospf_area *area;
+  struct ospf_interface *oi;
+  list listtop = NULL;
+  listnode node;
+  struct opaque_info_per_type *oipt = NULL;
+  u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr));
+
+  switch (lsa->data->type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+      if ((oi = lsa->oi) != NULL)
+        listtop = oi->opaque_lsa_self;
+      else
+        zlog_warn ("Type-9 Opaque-LSA: Reference to OI is missing?");
+      break;
+    case OSPF_OPAQUE_AREA_LSA:
+      if ((area = lsa->area) != NULL)
+        listtop = area->opaque_lsa_self;
+      else
+        zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?");
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      top = ospf_top;
+      if ((area = lsa->area) != NULL && (top = area->top) == NULL)
+        {
+          zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?");
+          break; /* Unlikely to happen. */
+        }
+      listtop = top->opaque_lsa_self;
+      break;
+    default:
+      zlog_warn ("lookup_opaque_info_by_type: Unexpected LSA-type(%u)", lsa->data->type);
+      break;
+    }
+
+  if (listtop != NULL)
+    for (node = listhead (listtop); node; nextnode (node))
+      if ((oipt = getdata (node)) != NULL)
+        if (oipt->opaque_type == key)
+          return oipt;
+
+  return NULL;
+}
+
+static struct opaque_info_per_id *
+register_opaque_info_per_id (struct opaque_info_per_type *oipt,
+                             struct ospf_lsa *new)
+{
+  struct opaque_info_per_id *oipi;
+
+  if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID,
+                      sizeof (struct opaque_info_per_id))) == NULL)
+    {
+      zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", strerror (errno));
+      goto out;
+    }
+  oipi->opaque_id = GET_OPAQUE_ID (ntohl (new->data->id.s_addr));
+  oipi->t_opaque_lsa_self = NULL;
+  oipi->opqctl_type = oipt;
+  oipi->lsa = ospf_lsa_lock (new);
+
+  listnode_add (oipt->id_list, oipi);
+
+out:
+  return oipi;
+}
+
+static void
+free_opaque_info_per_id (void *val)
+{
+  struct opaque_info_per_id *oipi = (struct opaque_info_per_id *) val;
+
+  OSPF_TIMER_OFF (oipi->t_opaque_lsa_self);
+  if (oipi->lsa != NULL)
+    ospf_lsa_unlock (oipi->lsa);
+  XFREE (MTYPE_OPAQUE_INFO_PER_ID, oipi);
+  return;
+}
+
+static struct opaque_info_per_id *
+lookup_opaque_info_by_id (struct opaque_info_per_type *oipt,
+                          struct ospf_lsa *lsa)
+{
+  listnode node;
+  struct opaque_info_per_id   *oipi;
+  u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr));
+
+  for (node = listhead (oipt->id_list); node; nextnode (node))
+    if ((oipi = getdata (node)) != NULL)
+      if (oipi->opaque_id == key)
+        return oipi;
+
+  return NULL;
+}
+
+static struct opaque_info_per_id *
+register_opaque_lsa (struct ospf_lsa *new)
+{
+  struct ospf_opaque_functab *functab;
+  struct opaque_info_per_type *oipt;
+  struct opaque_info_per_id *oipi = NULL;
+
+  if ((functab = ospf_opaque_functab_lookup (new)) == NULL)
+    goto out;
+
+  if ((oipt = lookup_opaque_info_by_type (new)) == NULL
+  &&  (oipt = register_opaque_info_per_type (functab, new)) == NULL)
+    goto out;
+
+  if ((oipi = register_opaque_info_per_id (oipt, new)) == NULL)
+    goto out;
+
+out:
+  return oipi;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are (vty) configuration functions for Opaque-LSAs handling.
+ *------------------------------------------------------------------------*/
+
+DEFUN (capability_opaque,
+       capability_opaque_cmd,
+       "capability opaque",
+       "Enable specific OSPF feature\n"
+       "Opaque LSA\n")
+{
+  struct ospf *ospf = (struct ospf *) vty->index;
+
+  /* Turn on the "master switch" of opaque-lsa capability. */
+  if (!CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Opaque capability: OFF -> ON");
+
+      SET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE);
+      ospf_renegotiate_optional_capabilities (ospf);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (capability_opaque,
+       ospf_opaque_capable_cmd,
+       "ospf opaque-lsa",
+       "OSPF specific commands\n"
+       "Enable the Opaque-LSA capability (rfc2370)\n")
+
+DEFUN (no_capability_opaque,
+       no_capability_opaque_cmd,
+       "no capability opaque",
+       NO_STR
+       "Enable specific OSPF feature\n"
+       "Opaque LSA\n")
+{
+  struct ospf *ospf = (struct ospf *) vty->index;
+
+  /* Turn off the "master switch" of opaque-lsa capability. */
+  if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Opaque capability: ON -> OFF");
+
+      UNSET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE);
+      ospf_renegotiate_optional_capabilities (ospf);
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_capability_opaque,
+       no_ospf_opaque_capable_cmd,
+       "no ospf opaque-lsa",
+       NO_STR
+       "OSPF specific commands\n"
+       "Disable the Opaque-LSA capability (rfc2370)\n")
+
+static void
+ospf_opaque_register_vty (void)
+{
+  install_element (OSPF_NODE, &capability_opaque_cmd);
+  install_element (OSPF_NODE, &no_capability_opaque_cmd);
+  install_element (OSPF_NODE, &ospf_opaque_capable_cmd);
+  install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd);
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are collection of user-registered function callers.
+ *------------------------------------------------------------------------*/
+
+static int
+opaque_lsa_new_if_callback (list funclist, struct interface *ifp)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+  int rc = -1;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->new_if_hook != NULL)
+        if ((* functab->new_if_hook)(ifp) != 0)
+          goto out;
+  rc = 0;
+out:
+  return rc;
+}
+
+static int
+opaque_lsa_del_if_callback (list funclist, struct interface *ifp)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+  int rc = -1;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->del_if_hook != NULL)
+        if ((* functab->del_if_hook)(ifp) != 0)
+          goto out;
+  rc = 0;
+out:
+  return rc;
+}
+
+static void
+opaque_lsa_ism_change_callback (list funclist,
+                                struct ospf_interface *oi, int old_status)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->ism_change_hook != NULL)
+        (* functab->ism_change_hook)(oi, old_status);
+  return;
+}
+
+static void
+opaque_lsa_nsm_change_callback (list funclist,
+                                struct ospf_neighbor *nbr, int old_status)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->nsm_change_hook != NULL)
+        (* functab->nsm_change_hook)(nbr, old_status);
+  return;
+}
+
+static void
+opaque_lsa_config_write_router_callback (list funclist, struct vty *vty)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->config_write_router != NULL)
+        (* functab->config_write_router)(vty);
+  return;
+}
+
+static void
+opaque_lsa_config_write_if_callback (list funclist,
+                                     struct vty *vty, struct interface *ifp)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->config_write_if != NULL)
+        (* functab->config_write_if)(vty, ifp);
+  return;
+}
+
+static void
+opaque_lsa_config_write_debug_callback (list funclist, struct vty *vty)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->config_write_debug != NULL)
+        (* functab->config_write_debug)(vty);
+  return;
+}
+
+static int
+opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+  int rc = -1;
+
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->lsa_originator != NULL)
+        if ((* functab->lsa_originator)(lsa_type_dependent) != 0)
+           goto out;
+  rc = 0;
+out:
+  return rc;
+}
+
+static int
+new_lsa_callback (list funclist, struct ospf_lsa *lsa)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+  int rc = -1;
+
+  /* This function handles ALL types of LSAs, not only opaque ones. */
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->new_lsa_hook != NULL)
+        if ((* functab->new_lsa_hook)(lsa) != 0)
+          goto out;
+  rc = 0;
+out:
+  return rc;
+}
+
+static int
+del_lsa_callback (list funclist, struct ospf_lsa *lsa)
+{
+  listnode node;
+  struct ospf_opaque_functab *functab;
+  int rc = -1;
+
+  /* This function handles ALL types of LSAs, not only opaque ones. */
+  for (node = listhead (funclist); node; nextnode (node))
+    if ((functab = getdata (node)) != NULL)
+      if (functab->del_lsa_hook != NULL)
+        if ((* functab->del_lsa_hook)(lsa) != 0)
+          goto out;
+  rc = 0;
+out:
+  return rc;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are glue functions to call Opaque-LSA specific processing.
+ *------------------------------------------------------------------------*/
+
+int
+ospf_opaque_new_if (struct interface *ifp)
+{
+  list funclist;
+  int rc = -1;
+
+  funclist = ospf_opaque_type9_funclist;
+  if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type10_funclist;
+  if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type11_funclist;
+  if (opaque_lsa_new_if_callback (funclist, ifp) != 0)
+    goto out;
+
+  rc = 0;
+out:
+  return rc;
+}
+
+int
+ospf_opaque_del_if (struct interface *ifp)
+{
+  list funclist;
+  int rc = -1;
+
+  funclist = ospf_opaque_type9_funclist;
+  if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type10_funclist;
+  if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type11_funclist;
+  if (opaque_lsa_del_if_callback (funclist, ifp) != 0)
+    goto out;
+
+  rc = 0;
+out:
+  return rc;
+}
+
+void
+ospf_opaque_ism_change (struct ospf_interface *oi, int old_status)
+{
+  list funclist;
+
+  funclist = ospf_opaque_type9_funclist;
+  opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
+  funclist = ospf_opaque_type10_funclist;
+  opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
+  funclist = ospf_opaque_type11_funclist;
+  opaque_lsa_ism_change_callback (funclist, oi, old_status);
+
+  return;
+}
+
+void
+ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_state)
+{
+  struct ospf *top;
+  list funclist;
+
+  if ((top = oi_to_top (nbr->oi)) == NULL)
+    goto out;
+
+  if (old_state != NSM_Full && nbr->state == NSM_Full)
+    {
+      if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
+        {
+          if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT))
+            {
+              if (IS_DEBUG_OSPF_EVENT)
+                zlog_info ("Opaque-LSA: Now get operational!");
+
+              SET_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT);
+            }
+
+          ospf_opaque_lsa_originate_schedule (nbr->oi, NULL);
+        }
+    }
+  else
+  if (old_state == NSM_Full && nbr->state != NSM_Full)
+    {
+#ifdef NOTYET
+      /*
+       * If no more opaque-capable full-state neighbor remains in the
+       * flooding scope which corresponds to Opaque-LSA type, periodic
+       * LS flooding should be stopped.
+       */
+#endif /* NOTYET */
+      ;
+    }
+
+  funclist = ospf_opaque_type9_funclist;
+  opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
+  funclist = ospf_opaque_type10_funclist;
+  opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
+  funclist = ospf_opaque_type11_funclist;
+  opaque_lsa_nsm_change_callback (funclist, nbr, old_state);
+
+out:
+  return;
+}
+
+void
+ospf_opaque_config_write_router (struct vty *vty, struct ospf *ospf)
+{
+  list funclist;
+
+  if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE))
+    vty_out (vty, " capability opaque%s", VTY_NEWLINE);
+
+  funclist = ospf_opaque_type9_funclist;
+  opaque_lsa_config_write_router_callback (funclist, vty);
+
+  funclist = ospf_opaque_type10_funclist;
+  opaque_lsa_config_write_router_callback (funclist, vty);
+
+  funclist = ospf_opaque_type11_funclist;
+  opaque_lsa_config_write_router_callback (funclist, vty);
+
+  return;
+}
+
+void
+ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp)
+{
+  list funclist;
+
+  funclist = ospf_opaque_type9_funclist;
+  opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
+  funclist = ospf_opaque_type10_funclist;
+  opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
+  funclist = ospf_opaque_type11_funclist;
+  opaque_lsa_config_write_if_callback (funclist, vty, ifp);
+
+  return;
+}
+
+void
+ospf_opaque_config_write_debug (struct vty *vty)
+{
+  list funclist;
+
+  funclist = ospf_opaque_type9_funclist;
+  opaque_lsa_config_write_debug_callback (funclist, vty);
+
+  funclist = ospf_opaque_type10_funclist;
+  opaque_lsa_config_write_debug_callback (funclist, vty);
+
+  funclist = ospf_opaque_type11_funclist;
+  opaque_lsa_config_write_debug_callback (funclist, vty);
+
+  return;
+}
+
+void
+show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  struct lsa_header *lsah = (struct lsa_header *) lsa->data;
+  u_int32_t lsid = ntohl (lsah->id.s_addr);
+  u_char    opaque_type = GET_OPAQUE_TYPE (lsid);
+  u_int32_t opaque_id = GET_OPAQUE_ID (lsid);
+  struct ospf_opaque_functab *functab;
+
+  /* Switch output functionality by vty address. */
+  if (vty != NULL)
+    {
+      vty_out (vty, "  Opaque-Type %u (%s)%s", opaque_type, ospf_opaque_type_name (opaque_type), VTY_NEWLINE);
+      vty_out (vty, "  Opaque-ID   0x%x%s", opaque_id, VTY_NEWLINE);
+
+      vty_out (vty, "  Opaque-Info: %u octets of data%s%s",
+               ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE,
+               VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)",
+               VTY_NEWLINE);
+    }
+  else
+    {
+      zlog_info ("    Opaque-Type %u (%s)", opaque_type, ospf_opaque_type_name (opaque_type));
+      zlog_info ("    Opaque-ID   0x%x", opaque_id);
+
+      zlog_info ("    Opaque-Info: %u octets of data%s",
+               ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE,
+               VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)");
+    }
+
+  /* Call individual output functions. */
+  if ((functab = ospf_opaque_functab_lookup (lsa)) != NULL)
+    if (functab->show_opaque_info != NULL)
+      (* functab->show_opaque_info)(vty, lsa);
+
+  return;
+}
+
+void
+ospf_opaque_lsa_dump (struct stream *s, u_int16_t length)
+{
+  struct ospf_lsa lsa;
+
+  lsa.data = (struct lsa_header *) STREAM_PNT (s);
+  show_opaque_info_detail (NULL, &lsa);
+  return;
+}
+
+static int
+ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa)
+{
+  list funclist;
+  int rc = -1;
+
+  /*
+   * Some Opaque-LSA user may want to monitor every LSA installation
+   * into the LSDB, regardless with target LSA type.
+   */
+  funclist = ospf_opaque_type9_funclist;
+  if (new_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type10_funclist;
+  if (new_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type11_funclist;
+  if (new_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
+  rc = 0;
+out:
+  return rc;
+}
+
+static int
+ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa)
+{
+  list funclist;
+  int rc = -1;
+
+  /*
+   * Some Opaque-LSA user may want to monitor every LSA deletion
+   * from the LSDB, regardless with target LSA type.
+   */
+  funclist = ospf_opaque_type9_funclist;
+  if (del_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type10_funclist;
+  if (del_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
+  funclist = ospf_opaque_type11_funclist;
+  if (del_lsa_callback (funclist, lsa) != 0)
+    goto out;
+
+  rc = 0;
+out:
+  return rc;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are Opaque-LSA origination/refresh management functions.
+ *------------------------------------------------------------------------*/
+
+static int ospf_opaque_type9_lsa_originate (struct thread *t);
+static int ospf_opaque_type10_lsa_originate (struct thread *t);
+static int ospf_opaque_type11_lsa_originate (struct thread *t);
+static void ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg);
+
+void
+ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0)
+{
+  struct ospf *top;
+  struct ospf_area *area;
+  listnode node;
+  struct opaque_info_per_type *oipt;
+  int delay = 0;
+
+  if ((top = oi_to_top (oi)) == NULL || (area = oi->area) == NULL)
+    {
+      zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?");
+      goto out;
+    }
+
+  /* It may not a right time to schedule origination now. */
+  if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("ospf_opaque_lsa_originate_schedule: Not operational.");
+      goto out; /* This is not an error. */
+    }
+  if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("ospf_opaque_lsa_originate_schedule: Under blockade.");
+      goto out; /* This is not an error, too. */
+    }
+
+  if (delay0 != NULL)
+    delay = *delay0;
+
+  /*
+   * There might be some entries that have been waiting for triggering
+   * of per opaque-type re-origination get resumed.
+   */
+  ospf_opaque_lsa_reoriginate_resume (  oi->opaque_lsa_self, (void *)   oi);
+  ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area);
+  ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *)  top);
+
+  /*
+   * Now, schedule origination of all Opaque-LSAs per opaque-type.
+   */
+  if (! list_isempty (ospf_opaque_type9_funclist)
+  &&    list_isempty (oi->opaque_lsa_self)
+  &&    oi->t_opaque_lsa_self == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay);
+      oi->t_opaque_lsa_self =
+       thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay);
+      delay += OSPF_MIN_LS_INTERVAL;
+    }
+
+  if (! list_isempty (ospf_opaque_type10_funclist)
+  &&    list_isempty (area->opaque_lsa_self)
+  &&    area->t_opaque_lsa_self == NULL)
+    {
+      /*
+       * One AREA may contain multiple OIs, but above 2nd and 3rd
+       * conditions prevent from scheduling the originate function
+       * again and again.
+       */
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay);
+      area->t_opaque_lsa_self =
+        thread_add_timer (master, ospf_opaque_type10_lsa_originate,
+                          area, delay);
+      delay += OSPF_MIN_LS_INTERVAL;
+    }
+
+  if (! list_isempty (ospf_opaque_type11_funclist)
+  &&    list_isempty (top->opaque_lsa_self)
+  &&    top->t_opaque_lsa_self == NULL)
+    {
+      /*
+       * One OSPF may contain multiple AREAs, but above 2nd and 3rd
+       * conditions prevent from scheduling the originate function
+       * again and again.
+       */
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay);
+      top->t_opaque_lsa_self =
+        thread_add_timer (master, ospf_opaque_type11_lsa_originate,
+                          top, delay);
+      delay += OSPF_MIN_LS_INTERVAL;
+    }
+
+  /*
+   * Following section treats a special situation that this node's
+   * opaque capability has changed as "ON -> OFF -> ON".
+   */
+  if (! list_isempty (ospf_opaque_type9_funclist)
+  &&  ! list_isempty (oi->opaque_lsa_self))
+    {
+      for (node = listhead (oi->opaque_lsa_self); node; nextnode (node))
+        {
+          if ((oipt = getdata (node))  == NULL /* Something wrong? */
+          ||   oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */
+          ||   oipt->status == PROC_SUSPEND    /* Cannot originate now. */
+          ||  ! list_isempty (oipt->id_list))  /* Handler is already active. */
+              continue;
+
+          ospf_opaque_lsa_reoriginate_schedule ((void *) oi,
+            OSPF_OPAQUE_LINK_LSA, oipt->opaque_type);
+        }
+    }
+
+  if (! list_isempty (ospf_opaque_type10_funclist)
+  &&  ! list_isempty (area->opaque_lsa_self))
+    {
+      for (node = listhead (area->opaque_lsa_self); node; nextnode (node))
+        {
+          if ((oipt = getdata (node))  == NULL /* Something wrong? */
+          ||   oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */
+          ||   oipt->status == PROC_SUSPEND    /* Cannot originate now. */
+          ||  ! list_isempty (oipt->id_list))  /* Handler is already active. */
+            continue;
+
+          ospf_opaque_lsa_reoriginate_schedule ((void *) area,
+            OSPF_OPAQUE_AREA_LSA, oipt->opaque_type);
+        }
+    }
+
+  if (! list_isempty (ospf_opaque_type11_funclist)
+  &&  ! list_isempty (top->opaque_lsa_self))
+    {
+      for (node = listhead (top->opaque_lsa_self); node; nextnode (node))
+        {
+          if ((oipt = getdata (node))  == NULL /* Something wrong? */
+          ||   oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */
+          ||   oipt->status == PROC_SUSPEND    /* Cannot originate now. */
+          ||  ! list_isempty (oipt->id_list))  /* Handler is already active. */
+            continue;
+
+          ospf_opaque_lsa_reoriginate_schedule ((void *) top,
+            OSPF_OPAQUE_AS_LSA, oipt->opaque_type);
+        }
+    }
+
+  if (delay0 != NULL)
+    *delay0 = delay;
+
+out:
+  return;
+}
+
+static int
+ospf_opaque_type9_lsa_originate (struct thread *t)
+{
+  struct ospf_interface *oi;
+  int rc;
+
+  oi = THREAD_ARG (t);
+  oi->t_opaque_lsa_self = NULL;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s",
+                IF_NAME (oi));
+
+  rc = opaque_lsa_originate_callback (ospf_opaque_type9_funclist, oi);
+
+  return rc;
+}
+
+static int
+ospf_opaque_type10_lsa_originate (struct thread *t)
+{
+  struct ospf_area *area;
+  int rc;
+
+  area = THREAD_ARG (t);
+  area->t_opaque_lsa_self = NULL;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s",
+                inet_ntoa (area->area_id));
+
+  rc = opaque_lsa_originate_callback (ospf_opaque_type10_funclist, area);
+
+  return rc;
+}
+
+static int
+ospf_opaque_type11_lsa_originate (struct thread *t)
+{
+  struct ospf *top;
+  int rc;
+
+  top = THREAD_ARG (t);
+  top->t_opaque_lsa_self = NULL;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Type11-LSA]: Originate AS-External Opaque-LSAs");
+
+  rc = opaque_lsa_originate_callback (ospf_opaque_type11_funclist, top);
+
+  return rc;
+}
+
+static void
+ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg)
+{
+  listnode node;
+  struct opaque_info_per_type *oipt;
+  struct ospf_opaque_functab *functab;
+
+  if (listtop == NULL)
+    goto out;
+
+  /*
+   * Pickup oipt entries those which in SUSPEND status, and give
+   * them a chance to start re-origination now.
+   */
+  for (node = listhead (listtop); node; nextnode (node))
+    {
+      if ((oipt = getdata (node)) == NULL
+      ||   oipt->status != PROC_SUSPEND)
+          continue;
+
+      oipt->status = PROC_NORMAL;
+
+      if ((functab = oipt->functab) == NULL
+      ||   functab->lsa_originator  == NULL)
+        continue;
+
+      if ((* functab->lsa_originator)(arg) != 0)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)", oipt->opaque_type);
+          continue;
+        }
+    }
+
+out:
+  return;
+}
+
+struct ospf_lsa *
+ospf_opaque_lsa_install (struct ospf_lsa *lsa, int rt_recalc)
+{
+  struct ospf_lsa *new = NULL;
+  struct opaque_info_per_type *oipt;
+  struct opaque_info_per_id *oipi;
+  struct ospf *top;
+
+  /* Don't take "rt_recalc" into consideration for now. *//* XXX */
+
+  if (! IS_LSA_SELF (lsa))
+    {
+      new = lsa; /* Don't touch this LSA. */
+      goto out;
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+    zlog_info ("Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+
+  /* Replace the existing lsa with the new one. */
+  if ((oipt = lookup_opaque_info_by_type (lsa)) != NULL
+  &&  (oipi = lookup_opaque_info_by_id (oipt, lsa)) != NULL)
+    {
+      ospf_lsa_unlock (oipi->lsa);
+      oipi->lsa = ospf_lsa_lock (lsa);
+    }
+  /* Register the new lsa entry and get its control info. */
+  else
+  if ((oipi = register_opaque_lsa (lsa)) == NULL)
+    {
+      zlog_warn ("ospf_opaque_lsa_install: register_opaque_lsa() ?");
+      goto out;
+    }
+
+  /*
+   * Make use of a common mechanism (ospf_lsa_refresh_walker)
+   * for periodic refresh of self-originated Opaque-LSAs.
+   */
+  switch (lsa->data->type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+      if (lsa->area == NULL || (top = lsa->area->top) == NULL)
+        {
+          /* Above conditions must have passed. */
+          zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
+          goto out;
+        }
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      top = ospf_top;
+      if (lsa->area != NULL && (top = lsa->area->top) == NULL)
+        {
+          /* Above conditions must have passed. */
+          zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
+          goto out;
+        }
+      break;
+    default:
+      zlog_warn ("ospf_opaque_lsa_install: Unexpected LSA-type(%u)", lsa->data->type);
+      goto out;
+    }
+
+  ospf_refresher_register_lsa (top, lsa);
+  new = lsa;
+
+out:
+  return new;
+}
+
+void
+ospf_opaque_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_opaque_functab *functab;
+
+  if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL
+  ||   functab->lsa_refresher == NULL)
+    {
+      /*
+       * Though this LSA seems to have originated on this node, the
+       * handling module for this "lsa-type and opaque-type" was
+       * already deleted sometime ago.
+       * Anyway, this node still has a responsibility to flush this
+       * LSA from the routing domain.
+       */
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id));
+
+      lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+      ospf_lsa_maxage (lsa);
+    }
+  else
+    (* functab->lsa_refresher)(lsa);
+
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are re-origination/refresh/flush operations of Opaque-LSAs,
+ * triggered by external interventions (vty session, signaling, etc).
+ *------------------------------------------------------------------------*/
+
+#define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \
+      if (!(T)) \
+        (T) = thread_add_timer (master, (F), (L), (V))
+
+static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type);
+static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t);
+static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t);
+static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t);
+static int ospf_opaque_lsa_refresh_timer (struct thread *t);
+
+void
+ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent,
+                                      u_char lsa_type, u_char opaque_type)
+{
+  struct ospf *top;
+  struct ospf_area dummy, *area = NULL;
+  struct ospf_interface *oi = NULL;
+
+  struct ospf_lsa *lsa;
+  struct opaque_info_per_type *oipt;
+  int (* func)(struct thread *t) = NULL;
+  int delay;
+
+  switch (lsa_type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+      if ((oi = (struct ospf_interface *) lsa_type_dependent) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-9 Opaque-LSA: Invalid parameter?");
+         goto out;
+        }
+      if ((top = oi_to_top (oi)) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?", IF_NAME (oi));
+          goto out;
+        }
+      if (! list_isempty (ospf_opaque_type9_funclist)
+      &&    list_isempty (oi->opaque_lsa_self)
+      &&    oi->t_opaque_lsa_self != NULL)
+        {
+          zlog_warn ("Type-9 Opaque-LSA (opaque_type=%u): Common origination for OI(%s) has already started", opaque_type, IF_NAME (oi));
+          goto out;
+        }
+      func = ospf_opaque_type9_lsa_reoriginate_timer;
+      break;
+    case OSPF_OPAQUE_AREA_LSA:
+      if ((area = (struct ospf_area *) lsa_type_dependent) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-10 Opaque-LSA: Invalid parameter?");
+          goto out;
+        }
+      if ((top = area->top) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: AREA(%s) -> TOP?", inet_ntoa (area->area_id));
+          goto out;
+        }
+      if (! list_isempty (ospf_opaque_type10_funclist)
+      &&    list_isempty (area->opaque_lsa_self)
+      &&    area->t_opaque_lsa_self != NULL)
+        {
+          zlog_warn ("Type-10 Opaque-LSA (opaque_type=%u): Common origination for AREA(%s) has already started", opaque_type, inet_ntoa (area->area_id));
+          goto out;
+        }
+      func = ospf_opaque_type10_lsa_reoriginate_timer;
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      if ((top = (struct ospf *) lsa_type_dependent) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-11 Opaque-LSA: Invalid parameter?");
+         goto out;
+        }
+      if (! list_isempty (ospf_opaque_type11_funclist)
+      &&    list_isempty (top->opaque_lsa_self)
+      &&    top->t_opaque_lsa_self != NULL)
+        {
+          zlog_warn ("Type-11 Opaque-LSA (opaque_type=%u): Common origination has already started", opaque_type);
+          goto out;
+        }
+
+      /* Fake "area" to pass "ospf" to a lookup function later. */
+      dummy.top = top;
+      area = &dummy;
+
+      func = ospf_opaque_type11_lsa_reoriginate_timer;
+      break;
+    default:
+      zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Unexpected LSA-type(%u)", lsa_type);
+      goto out;
+    }
+
+  /* It may not a right time to schedule reorigination now. */
+  if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Not operational.");
+      goto out; /* This is not an error. */
+    }
+  if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Under blockade.");
+      goto out; /* This is not an error, too. */
+    }
+
+  /* Generate a dummy lsa to be passed for a lookup function. */
+  lsa = pseudo_lsa (oi, area, lsa_type, opaque_type);
+
+  if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL)
+    {
+      struct ospf_opaque_functab *functab;
+      if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: No associated function?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type);
+          goto out;
+        }
+      if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL)
+        {
+          zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Cannot get a control info?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type);
+          goto out;
+        }
+    }
+
+  if (oipt->t_opaque_lsa_self != NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Type-%u Opaque-LSA has already scheduled to RE-ORIGINATE: [opaque-type=%u]", lsa_type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)));
+      goto out;
+    }
+
+  /*
+   * Different from initial origination time, in which various conditions
+   * (opaque capability, neighbor status etc) are assured by caller of
+   * the originating function "ospf_opaque_lsa_originate_schedule ()",
+   * it is highly possible that these conditions might not be satisfied
+   * at the time of re-origination function is to be called.
+   */
+  delay = OSPF_MIN_LS_INTERVAL; /* XXX */
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)));
+
+  OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay);
+
+out:
+  return;
+}
+
+static struct ospf_lsa *
+pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area,
+            u_char lsa_type, u_char opaque_type)
+{
+  static struct ospf_lsa lsa = { 0 };
+  static struct lsa_header lsah = { 0 };
+  u_int32_t tmp;
+
+  lsa.oi   = oi;
+  lsa.area = area;
+  lsa.data = &lsah;
+
+  lsah.type = lsa_type;
+  tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */
+  lsah.id.s_addr = htonl (tmp);
+
+  return &lsa;
+}
+
+static int
+ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t)
+{
+  struct opaque_info_per_type *oipt;
+  struct ospf_opaque_functab *functab;
+  struct ospf *top;
+  struct ospf_interface *oi;
+  int rc = -1;
+
+  oipt = THREAD_ARG (t);
+  oipt->t_opaque_lsa_self = NULL;
+
+  if ((functab = oipt->functab) == NULL
+  ||   functab->lsa_originator == NULL)
+    {
+      zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?");
+      goto out;
+    }
+
+  oi = (struct ospf_interface *) oipt->owner;
+  if ((top = oi_to_top (oi)) == NULL)
+    {
+      zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?");
+      goto out;
+    }
+
+  if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)
+  ||  ! ospf_if_is_enable (oi)
+  ||    ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full) == 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type);
+    
+      oipt->status = PROC_SUSPEND;
+      rc = 0;
+      goto out;
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME (oi));
+
+  rc = (* functab->lsa_originator)(oi);
+out:
+  return rc;
+}
+
+static int
+ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t)
+{
+  struct opaque_info_per_type *oipt;
+  struct ospf_opaque_functab *functab;
+  listnode node;
+  struct ospf *top;
+  struct ospf_area *area;
+  struct ospf_interface *oi;
+  int n, rc = -1;
+
+  oipt = THREAD_ARG (t);
+  oipt->t_opaque_lsa_self = NULL;
+
+  if ((functab = oipt->functab) == NULL
+  ||   functab->lsa_originator == NULL)
+    {
+      zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?");
+      goto out;
+    }
+
+  area = (struct ospf_area *) oipt->owner;
+  if (area == NULL || (top = area->top) == NULL)
+    {
+      zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?");
+      goto out;
+    }
+
+  /* There must be at least one "opaque-capable, full-state" neighbor. */
+  n = 0;
+  for (node = listhead (area->oiflist); node; nextnode (node))
+    {
+      if ((oi = getdata (node)) == NULL)
+        continue;
+      if ((n = ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full)) > 0)
+        break;
+    }
+
+  if (n == 0 || ! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Suspend re-origination of Type-10 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type);
+
+      oipt->status = PROC_SUSPEND;
+      rc = 0;
+      goto out;
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Type10-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for Area %s", oipt->opaque_type, inet_ntoa (area->area_id));
+
+  rc = (* functab->lsa_originator)(area);
+out:
+  return rc;
+}
+
+static int
+ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t)
+{
+  struct opaque_info_per_type *oipt;
+  struct ospf_opaque_functab *functab;
+  struct ospf *top;
+  int rc = -1;
+
+  oipt = THREAD_ARG (t);
+  oipt->t_opaque_lsa_self = NULL;
+
+  if ((functab = oipt->functab) == NULL
+  ||   functab->lsa_originator == NULL)
+    {
+      zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: No associated function?");
+      goto out;
+    }
+
+  if ((top = (struct ospf *) oipt->owner) == NULL)
+    {
+      zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?");
+      goto out;
+    }
+
+  if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type);
+    
+      oipt->status = PROC_SUSPEND;
+      rc = 0;
+      goto out;
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type);
+
+  rc = (* functab->lsa_originator)(top);
+out:
+  return rc;
+}
+
+extern int ospf_lsa_refresh_delay (struct ospf_lsa *); /* ospf_lsa.c */
+
+void
+ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0)
+{
+  struct opaque_info_per_type *oipt;
+  struct opaque_info_per_id *oipi;
+  struct ospf_lsa *lsa;
+  int delay;
+
+  if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL
+  ||  (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL)
+    {
+      zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?");
+      goto out;
+    }
+
+  /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
+  if ((lsa = oipi->lsa) == NULL)
+    {
+      zlog_warn ("ospf_opaque_lsa_refresh_schedule: Something wrong?");
+      goto out;
+    }
+
+  if (oipi->t_opaque_lsa_self != NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+      goto out;
+    }
+
+  /* Delete this lsa from neighbor retransmit-list. */
+  switch (lsa->data->type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+      ospf_ls_retransmit_delete_nbr_all (lsa->area, lsa);
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+      break;
+    default:
+      zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type);
+      goto out;
+    }
+
+  delay = ospf_lsa_refresh_delay (lsa);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+
+  OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self,
+                        ospf_opaque_lsa_refresh_timer, oipi, delay);
+out:
+  return;
+}
+
+static int
+ospf_opaque_lsa_refresh_timer (struct thread *t)
+{
+  struct opaque_info_per_id *oipi;
+  struct ospf_opaque_functab *functab;
+  struct ospf_lsa *lsa;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)");
+
+  oipi = THREAD_ARG (t);
+  oipi->t_opaque_lsa_self = NULL;
+
+  if ((lsa = oipi->lsa) != NULL)
+    if ((functab = oipi->opqctl_type->functab) != NULL)
+      if (functab->lsa_refresher != NULL)
+        (* functab->lsa_refresher)(lsa);
+
+  return 0;
+}
+
+void
+ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0)
+{
+  struct opaque_info_per_type *oipt;
+  struct opaque_info_per_id *oipi;
+  struct ospf_lsa *lsa;
+
+  if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL
+  ||  (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL)
+    {
+      zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?");
+      goto out;
+    }
+
+  /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
+  if ((lsa = oipi->lsa) == NULL)
+    {
+      zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?");
+      goto out;
+    }
+
+  /* Delete this lsa from neighbor retransmit-list. */
+  switch (lsa->data->type)
+    {
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+      ospf_ls_retransmit_delete_nbr_all (lsa->area, lsa);
+      break;
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+      break;
+    default:
+      zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type);
+      goto out;
+    }
+
+  /* Dequeue listnode entry from the list. */
+  listnode_delete (oipt->id_list, oipi);
+
+  /* Avoid misjudgement in the next lookup. */
+  if (listcount (oipt->id_list) == 0)
+    oipt->id_list->head = oipt->id_list->tail = NULL;
+
+  /* Disassociate internal control information with the given lsa. */
+  oipi->lsa = NULL;
+  free_opaque_info_per_id ((void *) oipi);
+
+  /* Force given lsa's age to MaxAge. */
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
+
+  /* This lsa will be flushed and removed eventually. */
+  ospf_lsa_maxage (lsa);
+
+out:
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are control functions to block origination after restart.
+ *------------------------------------------------------------------------*/
+
+static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa);
+static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi);
+static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area);
+static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top);
+static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type);
+
+void
+ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas)
+{
+  struct ospf *top;
+  struct ospf_area *area;
+  struct ospf_interface *oi;
+  listnode node1, node2;
+  struct ospf_lsa *lsa;
+
+  if ((top = oi_to_top (nbr->oi)) == NULL)
+    goto out;
+
+  /*
+   * If an instance of self-originated Opaque-LSA is found in the given
+   * LSA list, and it is not installed to LSDB yet, exclude it from the
+   * list "nbr->ls_req". In this way, it is assured that an LSReq message,
+   * which might be sent in the process of flooding, will not request for
+   * the LSA to be flushed immediately; otherwise, depending on timing,
+   * an LSUpd message will carry instances of target LSAs with MaxAge,
+   * while other LSUpd message might carry old LSA instances (non-MaxAge).
+   * Obviously, the latter would trigger miserable situations that repeat
+   * installation and removal of unwanted LSAs indefinitely.
+   */
+  for (node1 = listhead (lsas); node1; nextnode (node1))
+    {
+      if ((lsa = getdata (node1)) == NULL)
+        continue;
+
+      /* Filter out unwanted LSAs. */
+      if (! IS_OPAQUE_LSA (lsa->data->type))
+        continue;
+      if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id))
+        continue;
+
+      /*
+       * Don't touch an LSA which has MaxAge; two possible cases.
+       *
+       *   1) This LSA has originally flushed by myself (received LSUpd
+       *      message's router-id is equal to my router-id), and flooded
+       *      back by an opaque-capable router.
+       *
+       *   2) This LSA has expired in an opaque-capable router and thus
+       *      flushed by the router.
+       */
+      if (IS_LSA_MAXAGE (lsa))
+        continue;
+
+      /* If the LSA has installed in the LSDB, nothing to do here. */
+      if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL)
+        continue;
+
+      /* Ok, here we go. */
+      switch (lsa->data->type)
+        {
+        case OSPF_OPAQUE_LINK_LSA:
+          oi = nbr->oi;
+          ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
+          break;
+        case OSPF_OPAQUE_AREA_LSA:
+          area = nbr->oi->area;
+          for (node2 = listhead (area->oiflist); node2; nextnode (node2))
+            {
+              if ((oi = getdata (node2)) == NULL)
+                continue;
+              ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
+            }
+          break;
+        case OSPF_OPAQUE_AS_LSA:
+          for (node2 = listhead (top->oiflist); node2; nextnode (node2))
+            {
+              if ((oi = getdata (node2)) == NULL)
+                continue;
+              ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
+            }
+          break;
+        default:
+          break;
+        }
+    }
+
+out:
+  return;
+}
+
+static void
+ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs,
+                                    struct ospf_neighbor *inbr,
+                                    struct ospf_lsa *lsa)
+{
+  struct route_node *rn;
+  struct ospf_neighbor *onbr;
+  struct ospf_lsa *ls_req;
+
+  for (rn = route_top (nbrs); rn; rn = route_next (rn))
+    {
+      if ((onbr = rn->info) == NULL)
+        continue;
+      if (onbr == inbr)
+        continue;
+      if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL)
+        continue;
+
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa));
+
+      ospf_ls_request_delete (onbr, ls_req);
+/*    ospf_check_nbr_loading (onbr);*//* XXX */
+    }
+
+  return;
+}
+
+void
+ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas)
+{
+  struct ospf *top;
+  listnode node, next;
+  struct ospf_lsa *lsa;
+  u_char before;
+
+  if ((top = oi_to_top (nbr->oi)) == NULL)
+    goto out;
+
+  before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque);
+
+  for (node = listhead (lsas); node; node = next)
+    {
+      next = node->next;
+
+      if ((lsa = getdata (node)) == NULL)
+        continue;
+
+      listnode_delete (lsas, lsa);
+
+      /*
+       * Since these LSA entries are not yet installed into corresponding
+       * LSDB, just flush them without calling ospf_ls_maxage() afterward.
+       */
+      lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+      switch (lsa->data->type)
+        {
+        case OSPF_OPAQUE_LINK_LSA:
+          SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT);
+          ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa);
+          break;
+        case OSPF_OPAQUE_AREA_LSA:
+          SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT);
+          ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa);
+          break;
+        case OSPF_OPAQUE_AS_LSA:
+          SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT);
+          ospf_flood_through_as (NULL/*inbr*/, lsa);
+          break;
+        default:
+          zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type);
+          goto out;
+        }
+
+      ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */
+    }
+
+  if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Block Opaque-LSA origination: OFF -> ON");
+    }
+
+out:
+  return;
+}
+
+void
+ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks)
+{
+  struct ospf *top;
+  listnode node;
+  struct ospf_lsa *lsa;
+  char type9_lsa_rcv = 0, type10_lsa_rcv = 0, type11_lsa_rcv = 0;
+
+  if ((top = oi_to_top (nbr->oi)) == NULL)
+    goto out;
+
+  for (node = listhead (acks); node; nextnode (node))
+    {
+      if ((lsa = getdata (node)) == NULL)
+        continue;
+
+      switch (lsa->data->type)
+        {
+        case OSPF_OPAQUE_LINK_LSA:
+          type9_lsa_rcv = 1;
+          /* Callback function... */
+          break;
+        case OSPF_OPAQUE_AREA_LSA:
+          type10_lsa_rcv = 1;
+          /* Callback function... */
+          break;
+        case OSPF_OPAQUE_AS_LSA:
+          type11_lsa_rcv = 1;
+          /* Callback function... */
+          break;
+        default:
+          zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type);
+          goto out;
+        }
+    }
+
+  if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+    {
+      int delay;
+      struct ospf_interface *oi;
+
+      if (type9_lsa_rcv
+      &&  CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT))
+        ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi);
+
+      if (type10_lsa_rcv
+      &&  CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT))
+        ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area);
+
+      if (type11_lsa_rcv
+      &&  CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT))
+        ospf_opaque_type11_lsa_rxmt_nbr_check (top);
+
+      if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
+        goto out; /* Blocking still in progress. */
+
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Block Opaque-LSA origination: ON -> OFF");
+
+      if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
+        goto out; /* Opaque capability condition must have changed. */
+
+      /* Ok, let's start origination of Opaque-LSAs. */
+      delay = OSPF_MIN_LS_INTERVAL;
+      for (node = listhead (top->oiflist); node; nextnode (node))
+        {
+          if ((oi = getdata (node)) == NULL)
+            continue;
+
+          if (! ospf_if_is_enable (oi)
+          ||    ospf_opaque_capable_nbr_count (oi->nbrs, NSM_Full) == 0)
+            continue;
+
+          ospf_opaque_lsa_originate_schedule (oi, &delay);
+        }
+    }
+
+out:
+  return;
+}
+
+static void
+ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi)
+{
+  unsigned long n;
+
+  n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA);
+  if (n == 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi));
+
+      UNSET_FLAG (oi->area->top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT);
+    }
+  return;
+}
+
+static void
+ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area)
+{
+  listnode node;
+  struct ospf_interface *oi;
+  unsigned long n = 0;
+
+  for (node = listhead (area->oiflist); node; nextnode (node))
+    {
+      if ((oi = getdata (node)) == NULL)
+        continue;
+
+      if (area->area_id.s_addr != OSPF_AREA_BACKBONE
+      &&  oi->type == OSPF_IFTYPE_VIRTUALLINK) 
+        continue;
+
+      n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA);
+      if (n > 0)
+        break;
+    }
+
+  if (n == 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id));
+
+      UNSET_FLAG (area->top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT);
+    }
+
+  return;
+}
+
+static void
+ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top)
+{
+  listnode node;
+  struct ospf_interface *oi;
+  unsigned long n = 0;
+
+  for (node = listhead (top->oiflist); node; nextnode (node))
+    {
+      if ((oi = getdata (node)) == NULL)
+        continue;
+
+      switch (oi->type)
+        {
+        case OSPF_IFTYPE_VIRTUALLINK:
+          continue;
+        default:
+          break;
+        }
+
+      n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA);
+      if (n > 0)
+        goto out;
+    }
+
+  if (n == 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_info ("Self-originated type-11 Opaque-LSAs: Flush completed");
+
+      UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT);
+    }
+
+out:
+  return;
+}
+
+static unsigned long
+ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type)
+{
+  struct route_node *rn;
+  struct ospf_neighbor *nbr;
+  struct ospf *top;
+  unsigned long n = 0;
+
+  for (rn = route_top (nbrs); rn; rn = route_next (rn))
+    {
+      if ((nbr = rn->info) == NULL)
+        continue;
+      if ((top = oi_to_top (nbr->oi)) == NULL)
+        continue;
+      if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id))
+        continue;
+      n += ospf_ls_retransmit_count_self (nbr, lsa_type);
+    }
+
+  return n;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are util functions; probably be used by Opaque-LSAs only...
+ *------------------------------------------------------------------------*/
+
+void
+htonf (float *src, float *dst)
+{
+  u_int32_t lu1, lu2;
+
+  memcpy (&lu1, src, sizeof (u_int32_t));
+  lu2 = htonl (lu1);
+  memcpy (dst, &lu2, sizeof (u_int32_t));
+  return;
+}
+
+void
+ntohf (float *src, float *dst)
+{
+  u_int32_t lu1, lu2;
+
+  memcpy (&lu1, src, sizeof (u_int32_t));
+  lu2 = ntohl (lu1);
+  memcpy (dst, &lu2, sizeof (u_int32_t));
+  return;
+}
+
+struct ospf *
+oi_to_top (struct ospf_interface *oi)
+{
+  struct ospf *top = NULL;
+  struct ospf_area *area;
+
+  if (oi == NULL || (area = oi->area) == NULL || (top = area->top) == NULL)
+    zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?");
+
+  return top;
+}
+
+#endif /* HAVE_OPAQUE_LSA */
diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h
new file mode 100644 (file)
index 0000000..9aa08e5
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This is an implementation of rfc2370.
+ * Copyright (C) 2001 KDD R&D Laboratories, Inc.
+ * http://www.kddlabs.co.jp/
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_OPAQUE_H
+#define _ZEBRA_OSPF_OPAQUE_H
+
+#define        IS_OPAQUE_LSA(type) \
+       ((type) == OSPF_OPAQUE_LINK_LSA  || \
+        (type) == OSPF_OPAQUE_AREA_LSA  || \
+        (type) == OSPF_OPAQUE_AS_LSA)
+
+/*
+ * Usage of Opaque-LSA administrative flags in "struct ospf".
+ *
+ *    7   6   5   4   3   2   1   0
+ * +---+---+---+---+---+---+---+---+
+ * |///|///|///|///|B11|B10|B09| O |
+ * +---+---+---+---+---+---+---+---+
+ *                 |<--------->| A
+ *                       |       +--- Operation status (operational = 1)
+ *                       +----------- Blocking status for each LSA type
+ */
+
+#define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \
+        CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \
+                         OPAQUE_BLOCK_TYPE_10_LSA_BIT | \
+                         OPAQUE_BLOCK_TYPE_11_LSA_BIT))
+
+/*
+ * Opaque LSA's link state ID is redefined as follows.
+ *
+ *        24       16        8        0
+ * +--------+--------+--------+--------+
+ * |tttttttt|........|........|........|
+ * +--------+--------+--------+--------+
+ * |<-Type->|<------- Opaque ID ------>|
+ */
+#define LSID_OPAQUE_TYPE_MASK  0xff000000      /*  8 bits */
+#define LSID_OPAQUE_ID_MASK    0x00ffffff      /* 24 bits */
+
+#define        GET_OPAQUE_TYPE(lsid) \
+       (((u_int32_t)(lsid) & LSID_OPAQUE_TYPE_MASK) >> 24)
+
+#define        GET_OPAQUE_ID(lsid) \
+        ((u_int32_t)(lsid) & LSID_OPAQUE_ID_MASK)
+
+#define        SET_OPAQUE_LSID(type, id) \
+       ((((type) << 24) & LSID_OPAQUE_TYPE_MASK) \
+       | ((id)          & LSID_OPAQUE_ID_MASK))
+
+/*
+ * Opaque LSA types will be assigned by IANA.
+ * <http://www.iana.org/assignments/ospf-opaque-types>
+ */
+#define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA            1
+#define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC     2
+#define OPAQUE_TYPE_GRACE_LSA                          3
+
+/* Followings types are proposed in internet-draft documents. */
+#define OPAQUE_TYPE_8021_QOSPF                         129
+#define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY       224
+#define OPAQUE_TYPE_FLOODGATE                           225
+
+/* Ugly hack to make use of an unallocated value for wildcard matching! */
+#define OPAQUE_TYPE_WILDCARD                           0
+
+#define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \
+       (  4 <= (type) && (type) <= 127)
+
+#define OPAQUE_TYPE_RANGE_RESERVED(type) \
+       (127 <  (type) && (type) <= 255)
+
+#define VALID_OPAQUE_INFO_LEN(lsahdr) \
+       ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \
+       ((ntohs((lsahdr)->length) %  sizeof (u_int32_t)) == 0))
+
+/* Prototypes. */
+struct vty;
+struct stream;
+
+extern void ospf_opaque_init (void);
+extern void ospf_opaque_term (void);
+extern int ospf_opaque_type9_lsa_init (struct ospf_interface *oi);
+extern void ospf_opaque_type9_lsa_term (struct ospf_interface *oi);
+extern int ospf_opaque_type10_lsa_init (struct ospf_area *area);
+extern void ospf_opaque_type10_lsa_term (struct ospf_area *area);
+extern int ospf_opaque_type11_lsa_init (struct ospf *ospf);
+extern void ospf_opaque_type11_lsa_term (struct ospf *ospf);
+
+extern int
+ospf_register_opaque_functab (
+  u_char lsa_type,
+  u_char opaque_type,
+  int (* new_if_hook)(struct interface *ifp),
+  int (* del_if_hook)(struct interface *ifp),
+  void (* ism_change_hook)(struct ospf_interface *oi, int old_status),
+  void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status),
+  void (* config_write_router)(struct vty *vty),
+  void (* config_write_if    )(struct vty *vty, struct interface *ifp),
+  void (* config_write_debug )(struct vty *vty),
+  void (* show_opaque_info   )(struct vty *vty, struct ospf_lsa *lsa),
+  int  (* lsa_originator)(void *arg),
+  void (* lsa_refresher )(struct ospf_lsa *lsa),
+  int (* new_lsa_hook)(struct ospf_lsa *lsa),
+  int (* del_lsa_hook)(struct ospf_lsa *lsa)
+);
+extern void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type);
+
+extern int ospf_opaque_new_if (struct interface *ifp);
+extern int ospf_opaque_del_if (struct interface *ifp);
+extern void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status);
+extern void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_status);
+extern void ospf_opaque_config_write_router (struct vty *vty, struct ospf *);
+extern void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp);
+extern void ospf_opaque_config_write_debug (struct vty *vty);
+extern void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa);
+extern void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length);
+
+extern void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *init_delay);
+extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *new, int rt_recalc);
+extern void ospf_opaque_lsa_refresh (struct ospf_lsa *lsa);
+
+extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type);
+extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa);
+extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa);
+
+extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas);
+extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas);
+extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks);
+
+extern void htonf (float *src, float *dst);
+extern void ntohf (float *src, float *dst);
+extern struct ospf *oi_to_top (struct ospf_interface *oi);
+
+#endif /* _ZEBRA_OSPF_OPAQUE_H */
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
new file mode 100644 (file)
index 0000000..2156ce3
--- /dev/null
@@ -0,0 +1,3243 @@
+/*
+ * OSPF Sending and Receiving OSPF Packets.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "md5-gnu.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_dump.h"
+
+static void ospf_ls_ack_send_list (struct ospf_interface *, list,
+                                  struct in_addr);
+
+/* Packet Type String. */
+char *ospf_packet_type_str[] =
+{
+  "unknown",
+  "Hello",
+  "Database Description",
+  "Link State Request",
+  "Link State Update",
+  "Link State Acknowledgment",
+};
+
+extern int in_cksum (void *ptr, int nbytes);
+
+/* OSPF authentication checking function */
+int
+ospf_auth_type (struct ospf_interface *oi)
+{
+  int auth_type;
+
+  if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET)
+    auth_type = oi->area->auth_type;
+  else
+    auth_type = OSPF_IF_PARAM (oi, auth_type);
+
+  /* Handle case where MD5 key list is not configured aka Cisco */
+  if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC &&
+      list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
+    return OSPF_AUTH_NULL;
+  
+  return auth_type;
+
+}
+
+/* forward output pointer. */
+void
+ospf_output_forward (struct stream *s, int size)
+{
+  s->putp += size;
+}
+
+struct ospf_packet *
+ospf_packet_new (size_t size)
+{
+  struct ospf_packet *new;
+
+  new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet));
+  new->s = stream_new (size);
+
+  return new;
+}
+
+void
+ospf_packet_free (struct ospf_packet *op)
+{
+  if (op->s)
+    stream_free (op->s);
+
+  XFREE (MTYPE_OSPF_PACKET, op);
+
+  op = NULL;
+}
+
+struct ospf_fifo *
+ospf_fifo_new ()
+{
+  struct ospf_fifo *new;
+
+  new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo));
+  return new;
+}
+
+/* Add new packet to fifo. */
+void
+ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op)
+{
+  if (fifo->tail)
+    fifo->tail->next = op;
+  else
+    fifo->head = op;
+
+  fifo->tail = op;
+
+  fifo->count++;
+}
+
+/* Delete first packet from fifo. */
+struct ospf_packet *
+ospf_fifo_pop (struct ospf_fifo *fifo)
+{
+  struct ospf_packet *op;
+
+  op = fifo->head;
+
+  if (op)
+    {
+      fifo->head = op->next;
+
+      if (fifo->head == NULL)
+       fifo->tail = NULL;
+
+      fifo->count--;
+    }
+
+  return op;
+}
+
+/* Return first fifo entry. */
+struct ospf_packet *
+ospf_fifo_head (struct ospf_fifo *fifo)
+{
+  return fifo->head;
+}
+
+/* Flush ospf packet fifo. */
+void
+ospf_fifo_flush (struct ospf_fifo *fifo)
+{
+  struct ospf_packet *op;
+  struct ospf_packet *next;
+
+  for (op = fifo->head; op; op = next)
+    {
+      next = op->next;
+      ospf_packet_free (op);
+    }
+  fifo->head = fifo->tail = NULL;
+  fifo->count = 0;
+}
+
+/* Free ospf packet fifo. */
+void
+ospf_fifo_free (struct ospf_fifo *fifo)
+{
+  ospf_fifo_flush (fifo);
+
+  XFREE (MTYPE_OSPF_FIFO, fifo);
+}
+
+void
+ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
+{
+  /* Add packet to end of queue. */
+  ospf_fifo_push (oi->obuf, op);
+
+  /* Debug of packet fifo*/
+  /* ospf_fifo_debug (oi->obuf); */
+}
+
+void
+ospf_packet_delete (struct ospf_interface *oi)
+{
+  struct ospf_packet *op;
+  
+  op = ospf_fifo_pop (oi->obuf);
+
+  if (op)
+    ospf_packet_free (op);
+}
+
+struct stream *
+ospf_stream_copy (struct stream *new, struct stream *s)
+{
+  new->endp = s->endp;
+  new->putp = s->putp;
+  new->getp = s->getp;
+
+  memcpy (new->data, s->data, stream_get_endp (s));
+
+  return new;
+}
+
+struct ospf_packet *
+ospf_packet_dup (struct ospf_packet *op)
+{
+  struct ospf_packet *new;
+
+  new = ospf_packet_new (op->length);
+  ospf_stream_copy (new->s, op->s);
+
+  new->dst = op->dst;
+  new->length = op->length;
+
+  return new;
+}
+
+int
+ospf_packet_max (struct ospf_interface *oi)
+{
+  int max;
+
+  if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
+    max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88;
+  else
+    max = oi->ifp->mtu - 88;
+
+  return max;
+}
+
+\f
+int
+ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
+                       u_int16_t length)
+{
+  void *ibuf;
+  struct md5_ctx ctx;
+  unsigned char digest[OSPF_AUTH_MD5_SIZE];
+  unsigned char *pdigest;
+  struct crypt_key *ck;
+  struct ospf_header *ospfh;
+  struct ospf_neighbor *nbr;
+  
+
+  ibuf = STREAM_PNT (s);
+  ospfh = (struct ospf_header *) ibuf;
+
+  /* Get pointer to the end of the packet. */
+  pdigest = ibuf + length;
+
+  /* Get secret key. */
+  ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt),
+                             ospfh->u.crypt.key_id);
+  if (ck == NULL)
+    {
+      zlog_warn ("interface %s: ospf_check_md5 no key %d",
+                IF_NAME (oi), ospfh->u.crypt.key_id);
+      return 0;
+    }
+
+  /* check crypto seqnum. */
+  nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id);
+
+  if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum))
+    {
+      zlog_warn ("interface %s: ospf_check_md5 bad sequence %d (expect %d)",
+                IF_NAME (oi),
+                ntohl(ospfh->u.crypt.crypt_seqnum),
+                ntohl(nbr->crypt_seqnum));
+      return 0;
+    }
+      
+  /* Generate a digest for the ospf packet - their digest + our digest. */
+  md5_init_ctx (&ctx);
+  md5_process_bytes (ibuf, length, &ctx);
+  md5_process_bytes (ck->auth_key, OSPF_AUTH_MD5_SIZE, &ctx);
+  md5_finish_ctx (&ctx, digest);
+
+  /* compare the two */
+  if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE))
+    {
+      zlog_warn ("interface %s: ospf_check_md5 checksum mismatch",
+                IF_NAME (oi));
+      return 0;
+    }
+
+  /* save neighbor's crypt_seqnum */
+  if (nbr)
+    nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
+  return 1;
+}
+
+/* This function is called from ospf_write(), it will detect the
+   authentication scheme and if it is MD5, it will change the sequence
+   and update the MD5 digest. */
+int
+ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
+{
+  struct ospf_header *ospfh;
+  unsigned char digest[OSPF_AUTH_MD5_SIZE];
+  struct md5_ctx ctx;
+  void *ibuf;
+  unsigned long oldputp;
+  struct crypt_key *ck;
+  char *auth_key;
+
+  ibuf = STREAM_DATA (op->s);
+  ospfh = (struct ospf_header *) ibuf;
+
+  if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+    return 0;
+
+  /* We do this here so when we dup a packet, we don't have to
+     waste CPU rewriting other headers. */
+  ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum++);
+
+  /* Get MD5 Authentication key from auth_key list. */
+  if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
+    auth_key = "";
+  else
+    {
+      ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+      auth_key = ck->auth_key;
+    }
+
+  /* Generate a digest for the entire packet + our secret key. */
+  md5_init_ctx (&ctx);
+  md5_process_bytes (ibuf, ntohs (ospfh->length), &ctx);
+  md5_process_bytes (auth_key, OSPF_AUTH_MD5_SIZE, &ctx);
+  md5_finish_ctx (&ctx, digest);
+
+  /* Append md5 digest to the end of the stream. */
+  oldputp = stream_get_putp (op->s);
+  stream_set_putp (op->s, ntohs (ospfh->length));
+  stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE);
+  stream_set_putp (op->s, oldputp);
+
+  /* We do *NOT* increment the OSPF header length. */
+  op->length += OSPF_AUTH_MD5_SIZE;
+
+  return OSPF_AUTH_MD5_SIZE;
+}
+
+\f
+int
+ospf_ls_req_timer (struct thread *thread)
+{
+  struct ospf_neighbor *nbr;
+
+  nbr = THREAD_ARG (thread);
+  nbr->t_ls_req = NULL;
+
+  /* Send Link State Request. */
+  if (ospf_ls_request_count (nbr))
+    ospf_ls_req_send (nbr);
+
+  /* Set Link State Request retransmission timer. */
+  OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
+
+  return 0;
+}
+
+void
+ospf_ls_req_event (struct ospf_neighbor *nbr)
+{
+  if (nbr->t_ls_req)
+    {
+      thread_cancel (nbr->t_ls_req);
+      nbr->t_ls_req = NULL;
+    }
+  nbr->t_ls_req = thread_add_event (master, ospf_ls_req_timer, nbr, 0);
+}
+
+/* Cyclic timer function.  Fist registered in ospf_nbr_new () in
+   ospf_neighbor.c  */
+int
+ospf_ls_upd_timer (struct thread *thread)
+{
+  struct ospf_neighbor *nbr;
+
+  nbr = THREAD_ARG (thread);
+  nbr->t_ls_upd = NULL;
+
+  /* Send Link State Update. */
+  if (ospf_ls_retransmit_count (nbr) > 0)
+    {
+      list update;
+      struct ospf_lsdb *lsdb;
+      int i;
+      struct timeval now;
+      int retransmit_interval;
+
+      gettimeofday (&now, NULL);
+      retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval);
+
+      lsdb = &nbr->ls_rxmt;
+      update = list_new ();
+
+      for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+       {
+         struct route_table *table = lsdb->type[i].db;
+         struct route_node *rn;
+         
+         for (rn = route_top (table); rn; rn = route_next (rn))
+           {
+             struct ospf_lsa *lsa;
+             
+             if ((lsa = rn->info) != NULL)
+               /* Don't retransmit an LSA if we received it within
+                 the last RxmtInterval seconds - this is to allow the
+                 neighbour a chance to acknowledge the LSA as it may
+                 have ben just received before the retransmit timer
+                 fired.  This is a small tweak to what is in the RFC,
+                 but it will cut out out a lot of retransmit traffic
+                 - MAG */
+               if (tv_cmp (tv_sub (now, lsa->tv_recv), 
+                           int2tv (retransmit_interval)) >= 0)
+                 listnode_add (update, rn->info);
+           }
+       }
+
+      if (listcount (update) > 0)
+       ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT);
+      list_delete (update);
+    }
+
+  /* Set LS Update retransmission timer. */
+  OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
+
+  return 0;
+}
+
+int
+ospf_ls_ack_timer (struct thread *thread)
+{
+  struct ospf_interface *oi;
+
+  oi = THREAD_ARG (thread);
+  oi->t_ls_ack = NULL;
+
+  /* Send Link State Acknowledgment. */
+  if (listcount (oi->ls_ack) > 0)
+    ospf_ls_ack_send_delayed (oi);
+
+  /* Set LS Ack timer. */
+  OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
+
+  return 0;
+}
+
+int
+ospf_write (struct thread *thread)
+{
+  struct ospf_interface *oi;
+  struct ospf_packet *op;
+  struct sockaddr_in sa_dst;
+  u_char type;
+  int ret;
+  int flags = 0;
+  struct ip iph;
+  struct msghdr msg;
+  struct iovec iov[2];
+  struct ospf *top;
+  listnode node;
+  
+  top = THREAD_ARG (thread);
+  top->t_write = NULL;
+
+  node = listhead (top->oi_write_q);
+  assert (node);
+  oi = getdata (node);
+  assert (oi);
+  
+  /* Get one packet from queue. */
+  op = ospf_fifo_head (oi->obuf);
+  assert (op);
+  assert (op->length >= OSPF_HEADER_SIZE);
+
+  if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) ||
+      op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
+    ospf_if_ipmulticast (top, oi->address, oi->ifp->ifindex);
+
+  /* Rewrite the md5 signature & update the seq */
+  ospf_make_md5_digest (oi, op);
+
+  memset (&sa_dst, 0, sizeof (sa_dst));
+  sa_dst.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sa_dst.sin_len = sizeof(sa_dst);
+#endif /* HAVE_SIN_LEN */
+  sa_dst.sin_addr = op->dst;
+  sa_dst.sin_port = htons (0);
+
+  /* Set DONTROUTE flag if dst is unicast. */
+  if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+    if (!IN_MULTICAST (htonl (op->dst.s_addr)))
+      flags = MSG_DONTROUTE;
+
+  iph.ip_hl = sizeof (struct ip) >> 2;
+  iph.ip_v = IPVERSION;
+  iph.ip_tos = 0;
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+  iph.ip_len = iph.ip_hl*4 + op->length;
+#else
+  iph.ip_len = htons (iph.ip_hl*4 + op->length);
+#endif
+  iph.ip_id = 0;
+  iph.ip_off = 0;
+  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+    iph.ip_ttl = OSPF_VL_IP_TTL;
+  else
+    iph.ip_ttl = OSPF_IP_TTL;
+  iph.ip_p = IPPROTO_OSPFIGP;
+  iph.ip_sum = 0;
+  iph.ip_src.s_addr = oi->address->u.prefix4.s_addr;
+  iph.ip_dst.s_addr = op->dst.s_addr;
+
+  memset (&msg, 0, sizeof (msg));
+  msg.msg_name = &sa_dst;
+  msg.msg_namelen = sizeof (sa_dst); 
+  msg.msg_iov = iov;
+  msg.msg_iovlen = 2;
+  iov[0].iov_base = (char*)&iph;
+  iov[0].iov_len = iph.ip_hl*4;
+  iov[1].iov_base = STREAM_DATA (op->s);
+  iov[1].iov_len = op->length;
+
+  ret = sendmsg (top->fd, &msg, flags);
+  
+  if (ret < 0)
+    zlog_warn ("*** sendmsg in ospf_write failed with %s", strerror (errno));
+
+  /* Retrieve OSPF packet type. */
+  stream_set_getp (op->s, 1);
+  type = stream_getc (op->s);
+
+  /* Show debug sending packet. */
+  if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
+    {
+      if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
+       {
+         zlog_info ("-----------------------------------------------------");
+         stream_set_getp (op->s, 0);
+         ospf_packet_dump (op->s);
+       }
+
+      zlog_info ("%s sent to [%s] via [%s].",
+                ospf_packet_type_str[type], inet_ntoa (op->dst),
+                IF_NAME (oi));
+
+      if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
+       zlog_info ("-----------------------------------------------------");
+    }
+
+  /* Now delete packet from queue. */
+  ospf_packet_delete (oi);
+
+  if (ospf_fifo_head (oi->obuf) == NULL)
+    {
+      oi->on_write_q = 0;
+      list_delete_node (top->oi_write_q, node);
+    }
+  
+  /* If packets still remain in queue, call write thread. */
+  if (!list_isempty (top->oi_write_q))
+    ospf_top->t_write =                                              
+      thread_add_write (master, ospf_write, top, top->fd);
+
+  return 0;
+}
+
+/* OSPF Hello message read -- RFC2328 Section 10.5. */
+void
+ospf_hello (struct ip *iph, struct ospf_header *ospfh,
+           struct stream * s, struct ospf_interface *oi, int size)
+{
+  struct ospf_hello *hello;
+  struct ospf_neighbor *nbr;
+  struct route_node *rn;
+  struct prefix p, key;
+  int old_state;
+
+  /* increment statistics. */
+  oi->hello_in++;
+
+  hello = (struct ospf_hello *) STREAM_PNT (s);
+
+  /* If Hello is myself, silently discard. */
+  if (IPV4_ADDR_SAME (&ospfh->router_id, &ospf_top->router_id))
+    return;
+
+  /* If incoming interface is passive one, ignore Hello. */
+  if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+    return;
+
+  /* get neighbor prefix. */
+  p.family = AF_INET;
+  p.prefixlen = ip_masklen (hello->network_mask);
+  p.u.prefix4 = iph->ip_src;
+
+  /* Compare network mask. */
+  /* Checking is ignored for Point-to-Point and Virtual link. */
+  if (oi->type != OSPF_IFTYPE_POINTOPOINT 
+      && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+    if (oi->address->prefixlen != p.prefixlen)
+      {
+       zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch.",
+                  inet_ntoa (ospfh->router_id));
+       return;
+      }
+
+  /* Compare Hello Interval. */
+  if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
+    {
+      zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+
+  /* Compare Router Dead Interval. */
+  if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval))
+    {
+      zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch.",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Packet %s [Hello:RECV]: Options %s",
+              inet_ntoa (ospfh->router_id),
+              ospf_options_dump (hello->options));
+
+  /* Compare options. */
+#define REJECT_IF_TBIT_ON      1 /* XXX */
+#ifdef REJECT_IF_TBIT_ON
+  if (CHECK_FLAG (hello->options, OSPF_OPTION_T))
+    {
+      /*
+       * This router does not support non-zero TOS.
+       * Drop this Hello packet not to establish neighbor relationship.
+       */
+      zlog_warn ("Packet %s [Hello:RECV]: T-bit on, drop it.",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+#endif /* REJECT_IF_TBIT_ON */
+
+#ifdef HAVE_OPAQUE_LSA
+  if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE)
+      && CHECK_FLAG (hello->options, OSPF_OPTION_O))
+    {
+      /*
+       * This router does know the correct usage of O-bit
+       * the bit should be set in DD packet only.
+       */
+      zlog_warn ("Packet %s [Hello:RECV]: O-bit abuse?",
+                inet_ntoa (ospfh->router_id));
+#ifdef STRICT_OBIT_USAGE_CHECK
+      return;                                     /* Reject this packet. */
+#else /* STRICT_OBIT_USAGE_CHECK */
+      UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */
+#endif /* STRICT_OBIT_USAGE_CHECK */
+    }
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* new for NSSA is to ensure that NP is on and E is off */
+
+#ifdef HAVE_NSSA
+  if (oi->area->external_routing == OSPF_AREA_NSSA) 
+    {
+      if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP)
+            && CHECK_FLAG (hello->options, OSPF_OPTION_NP)
+            && ! CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E)
+            && ! CHECK_FLAG (hello->options, OSPF_OPTION_E)))
+       {
+         zlog_warn ("NSSA-Packet-%s[Hello:RECV]: my options: %x, his options %x", inet_ntoa (ospfh->router_id), OPTIONS (oi), hello->options);
+         return;
+       }
+      if (IS_DEBUG_OSPF_NSSA)
+        zlog_info ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id));
+    }
+  else    
+#endif /* HAVE_NSSA */
+    /* The setting of the E-bit found in the Hello Packet's Options
+       field must match this area's ExternalRoutingCapability A
+       mismatch causes processing to stop and the packet to be
+       dropped. The setting of the rest of the bits in the Hello
+       Packet's Options field should be ignored. */
+    if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) !=
+       CHECK_FLAG (hello->options, OSPF_OPTION_E))
+      {
+       zlog_warn ("Packet[Hello:RECV]: my options: %x, his options %x",
+                  OPTIONS (oi), hello->options);
+       return;
+      }
+
+
+  /* Get neighbor information from table. */
+  key.family = AF_INET;
+  key.prefixlen = IPV4_MAX_BITLEN;
+  key.u.prefix4 = iph->ip_src;
+
+  rn = route_node_get (oi->nbrs, &key);
+  if (rn->info)
+    {
+      route_unlock_node (rn);
+      nbr = rn->info;
+
+      if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt)
+       {
+         nbr->src = iph->ip_src;
+         nbr->address = p;
+       }
+    }
+  else
+    {
+      /* Create new OSPF Neighbor structure. */
+      nbr = ospf_nbr_new (oi);
+      nbr->state = NSM_Down;
+      nbr->src = iph->ip_src;
+      nbr->address = p;
+
+      rn->info = nbr;
+
+      nbr->nbr_nbma = NULL;
+
+      if (oi->type == OSPF_IFTYPE_NBMA)
+       {
+         struct ospf_nbr_nbma *nbr_nbma;
+         listnode node;
+
+         for (node = listhead (oi->nbr_nbma); node; nextnode (node))
+           {
+             nbr_nbma = getdata (node);
+             assert (nbr_nbma);
+      
+             if (IPV4_ADDR_SAME(&nbr_nbma->addr, &iph->ip_src))
+               {
+                 nbr_nbma->nbr = nbr;
+                 nbr->nbr_nbma = nbr_nbma;
+
+                 if (nbr_nbma->t_poll)
+                   OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll);
+                 
+                 nbr->state_change = nbr_nbma->state_change + 1;
+               }
+           }
+       }
+      
+      /* New nbr, save the crypto sequence number if necessary */
+      if (ntohs (ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
+       nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("NSM[%s:%s]: start", IF_NAME (nbr->oi),
+                  inet_ntoa (nbr->router_id));
+    }
+  
+  nbr->router_id = ospfh->router_id;
+
+  old_state = nbr->state;
+
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_EXECUTE (nbr, NSM_HelloReceived);
+
+  /*  RFC2328  Section 9.5.1
+      If the router is not eligible to become Designated Router,
+      (snip)   It      must also send an Hello Packet in reply to an
+      Hello Packet received from any eligible neighbor (other than
+      the      current Designated Router and Backup Designated Router).  */
+  if (oi->type == OSPF_IFTYPE_NBMA)
+    if (PRIORITY(oi) == 0 && hello->priority > 0
+       && IPV4_ADDR_CMP(&DR(oi),  &iph->ip_src)
+       && IPV4_ADDR_CMP(&BDR(oi), &iph->ip_src))
+      OSPF_NSM_TIMER_ON (nbr->t_hello_reply, ospf_hello_reply_timer,
+                        OSPF_HELLO_REPLY_DELAY);
+
+  /* on NBMA network type, it happens to receive bidirectional Hello packet
+     without advance 1-Way Received event.
+     To avoid incorrect DR-seletion, raise 1-Way Received event.*/
+  if (oi->type == OSPF_IFTYPE_NBMA &&
+      (old_state == NSM_Down || old_state == NSM_Attempt))
+    {
+      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived);
+      nbr->priority = hello->priority;
+      nbr->d_router = hello->d_router;
+      nbr->bd_router = hello->bd_router;
+      return;
+    }
+
+  if (ospf_nbr_bidirectional (&ospf_top->router_id, hello->neighbors,
+                             size - OSPF_HELLO_MIN_SIZE))
+    {
+      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived);
+      nbr->options |= hello->options;
+    }
+  else
+    {
+      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived);
+      /* Set neighbor information. */
+      nbr->priority = hello->priority;
+      nbr->d_router = hello->d_router;
+      nbr->bd_router = hello->bd_router;
+      return;
+    }
+
+  /* If neighbor itself declares DR and no BDR exists,
+     cause event BackupSeen */
+  if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router))
+    if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting)
+      OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen);
+
+  /* neighbor itself declares BDR. */
+  if (oi->state == ISM_Waiting &&
+      IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router))
+    OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen);
+
+  /* had not previously. */
+  if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router) &&
+       IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->d_router)) ||
+      (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->d_router) &&
+       IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router)))
+    OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
+
+  /* had not previously. */
+  if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router) &&
+       IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->bd_router)) ||
+      (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->bd_router) &&
+       IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router)))
+    OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
+
+  /* Neighbor priority check. */
+  if (nbr->priority >= 0 && nbr->priority != hello->priority)
+    OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
+
+  /* Set neighbor information. */
+  nbr->priority = hello->priority;
+  nbr->d_router = hello->d_router;
+  nbr->bd_router = hello->bd_router;
+}
+
+/* Save DD flags/options/Seqnum received. */
+void
+ospf_db_desc_save_current (struct ospf_neighbor *nbr,
+                          struct ospf_db_desc *dd)
+{
+  nbr->last_recv.flags = dd->flags;
+  nbr->last_recv.options = dd->options;
+  nbr->last_recv.dd_seqnum = ntohl (dd->dd_seqnum);
+}
+
+/* Process rest of DD packet. */
+static void
+ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
+                  struct ospf_neighbor *nbr, struct ospf_db_desc *dd,
+                  u_int16_t size)
+{
+  struct ospf_lsa *new, *find;
+  struct lsa_header *lsah;
+
+  stream_forward (s, OSPF_DB_DESC_MIN_SIZE);
+  for (size -= OSPF_DB_DESC_MIN_SIZE;
+       size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE) 
+    {
+      lsah = (struct lsa_header *) STREAM_PNT (s);
+      stream_forward (s, OSPF_LSA_HEADER_SIZE);
+
+      /* Unknown LS type. */
+      if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA)
+       {
+         zlog_warn ("Pakcet [DD:RECV]: Unknown LS type %d.", lsah->type);
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+         return;
+       }
+
+#ifdef HAVE_OPAQUE_LSA
+      if (IS_OPAQUE_LSA (lsah->type)
+      &&  ! CHECK_FLAG (nbr->options, OSPF_OPTION_O))
+        {
+          zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id));
+          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+          return;
+        }
+#endif /* HAVE_OPAQUE_LSA */
+
+      switch (lsah->type)
+        {
+        case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+       case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+#ifdef HAVE_NSSA
+          /* Check for stub area.  Reject if AS-External from stub but
+             allow if from NSSA. */
+          if (oi->area->external_routing == OSPF_AREA_STUB)
+#else /* ! HAVE_NSSA */
+          if (oi->area->external_routing != OSPF_AREA_DEFAULT)
+#endif /* HAVE_NSSA */
+            {
+              zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.",
+                         lsah->type, inet_ntoa (lsah->id),
+                         (oi->area->external_routing == OSPF_AREA_STUB) ?\
+                         "STUB" : "NSSA");
+              OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+              return;
+            }
+          break;
+       default:
+         break;
+        }
+
+      /* Create LS-request object. */
+      new = ospf_ls_request_new (lsah);
+
+      /* Lookup received LSA, then add LS request list. */
+      find = ospf_lsa_lookup_by_header (oi->area, lsah);
+      if (!find || ospf_lsa_more_recent (find, new) < 0)
+       {
+         ospf_ls_request_add (nbr, new);
+         ospf_lsa_discard (new);
+       }
+      else
+       {
+         /* Received LSA is not recent. */
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("Packet [DD:RECV]: LSA received Type %d, "
+                      "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id));
+         ospf_lsa_discard (new);
+         continue;
+       }
+    }
+
+  /* Master */
+  if (IS_SET_DD_MS (nbr->dd_flags))
+    {
+      nbr->dd_seqnum++;
+      /* Entire DD packet sent. */
+      if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags))
+       OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
+      else
+       /* Send new DD packet. */
+       ospf_db_desc_send (nbr);
+    }
+  /* Slave */
+  else
+    {
+      nbr->dd_seqnum = ntohl (dd->dd_seqnum);
+
+      /* When master's more flags is not set. */
+      if (!IS_SET_DD_M (dd->flags) && ospf_db_summary_isempty (nbr))
+       {
+         nbr->dd_flags &= ~(OSPF_DD_FLAG_M);
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
+       }
+
+      /* Send DD pakcet in reply. */
+      ospf_db_desc_send (nbr);
+    }
+
+  /* Save received neighbor values from DD. */
+  ospf_db_desc_save_current (nbr, dd);
+}
+
+int
+ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr)
+{
+  /* Is DD duplicated? */
+  if (dd->options == nbr->last_recv.options &&
+      dd->flags == nbr->last_recv.flags &&
+      dd->dd_seqnum == htonl (nbr->last_recv.dd_seqnum))
+    return 1;
+
+  return 0;
+}
+
+/* OSPF Database Description message read -- RFC2328 Section 10.6. */
+void
+ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
+             struct stream *s, struct ospf_interface *oi, u_int16_t size)
+{
+  struct ospf_db_desc *dd;
+  struct ospf_neighbor *nbr;
+
+  /* Increment statistics. */
+  oi->db_desc_in++;
+
+  dd = (struct ospf_db_desc *) STREAM_PNT (s);
+
+  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  if (nbr == NULL)
+    {
+      zlog_warn ("Packet[DD]: Unknown Neighbor %s",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+
+  /* Check MTU. */
+  if (ntohs (dd->mtu) > oi->ifp->mtu)
+    {
+      zlog_warn ("Packet[DD]: MTU is larger than [%s]'s MTU", IF_NAME (oi));
+      return;
+    }
+
+#ifdef REJECT_IF_TBIT_ON
+  if (CHECK_FLAG (dd->options, OSPF_OPTION_T))
+    {
+      /*
+       * In Hello protocol, optional capability must have checked
+       * to prevent this T-bit enabled router be my neighbor.
+       */
+      zlog_warn ("Packet[DD]: Neighbor %s: T-bit on?", inet_ntoa (nbr->router_id));
+      return;
+    }
+#endif /* REJECT_IF_TBIT_ON */
+
+#ifdef HAVE_OPAQUE_LSA
+  if (CHECK_FLAG (dd->options, OSPF_OPTION_O)
+      && !CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE))
+    {
+      /*
+       * This node is not configured to handle O-bit, for now.
+       * Clear it to ignore unsupported capability proposed by neighbor.
+       */
+      UNSET_FLAG (dd->options, OSPF_OPTION_O);
+    }
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Process DD packet by neighbor status. */
+  switch (nbr->state)
+    {
+    case NSM_Down:
+    case NSM_Attempt:
+    case NSM_TwoWay:
+      zlog_warn ("Packet[DD]: Neighbor state is %s, packet discarded.",
+                LOOKUP (ospf_nsm_state_msg, nbr->state));
+      break;
+    case NSM_Init:
+      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived);
+      /* If the new state is ExStart, the processing of the current
+        packet should then continue in this new state by falling
+        through to case ExStart below.  */
+      if (nbr->state != NSM_ExStart)
+       break;
+    case NSM_ExStart:
+      /* Initial DBD */
+      if ((IS_SET_DD_ALL (dd->flags) == OSPF_DD_FLAG_ALL) &&
+         (size == OSPF_DB_DESC_MIN_SIZE))
+       {
+         if (IPV4_ADDR_CMP (&nbr->router_id, &ospf_top->router_id) > 0)
+           {
+             /* We're Slave---obey */
+             zlog_warn ("Packet[DD]: Negotiation done (Slave).");
+             nbr->dd_seqnum = ntohl (dd->dd_seqnum);
+             nbr->dd_flags &= ~(OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I); /* Reset I/MS */
+           }
+         else
+           {
+             /* We're Master, ignore the initial DBD from Slave */
+             zlog_warn ("Packet[DD]: Initial DBD from Slave, ignoring.");
+             break;
+           }
+       }
+      /* Ack from the Slave */
+      else if (!IS_SET_DD_MS (dd->flags) && !IS_SET_DD_I (dd->flags) &&
+              ntohl (dd->dd_seqnum) == nbr->dd_seqnum &&
+              IPV4_ADDR_CMP (&nbr->router_id, &ospf_top->router_id) < 0)
+       {
+         zlog_warn ("Packet[DD]: Negotiation done (Master).");
+         nbr->dd_flags &= ~OSPF_DD_FLAG_I;
+       }
+      else
+       {
+         zlog_warn ("Packet[DD]: Negotiation fails.");
+         break;
+       }
+      
+      /* This is where the real Options are saved */
+      nbr->options = dd->options;
+
+#ifdef HAVE_OPAQUE_LSA
+      if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE))
+        {
+          if (IS_DEBUG_OSPF_EVENT)
+            zlog_info ("Neighbor[%s] is %sOpaque-capable.",
+                      inet_ntoa (nbr->router_id),
+                      CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT ");
+
+          if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O)
+          &&  IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4))
+            {
+              zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; Opaque-LSAs cannot be reliably advertised in this network.", inet_ntoa (nbr->router_id));
+              /* This situation is undesirable, but not a real error. */
+            }
+        }
+#endif /* HAVE_OPAQUE_LSA */
+
+      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone);
+
+      /* continue processing rest of packet. */
+      ospf_db_desc_proc (s, oi, nbr, dd, size);
+      break;
+    case NSM_Exchange:
+      if (ospf_db_desc_is_dup (dd, nbr))
+       {
+         if (IS_SET_DD_MS (nbr->dd_flags))
+           /* Master: discard duplicated DD packet. */
+           zlog_warn ("Packet[DD] (Master): packet duplicated.");
+         else
+           /* Slave: cause to retransmit the last Database Description. */
+           {
+             zlog_warn ("Packet[DD] [Slave]: packet duplicated.");
+             ospf_db_desc_resend (nbr);
+           }
+         break;
+       }
+
+      /* Otherwise DD packet should be checked. */
+      /* Check Master/Slave bit mismatch */
+      if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags))
+       {
+         zlog_warn ("Packet[DD]: MS-bit mismatch.");
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
+                      dd->flags, nbr->dd_flags);
+         break;
+       }
+
+      /* Check initialize bit is set. */
+      if (IS_SET_DD_I (dd->flags))
+       {
+         zlog_warn ("Packet[DD]: I-bit set.");
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+         break;
+       }
+
+      /* Check DD Options. */
+      if (dd->options != nbr->options)
+       {
+#ifdef ORIGINAL_CODING
+         /* Save the new options for debugging */
+         nbr->options = dd->options;
+#endif /* ORIGINAL_CODING */
+         zlog_warn ("Packet[DD]: options mismatch.");
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+         break;
+       }
+
+      /* Check DD sequence number. */
+      if ((IS_SET_DD_MS (nbr->dd_flags) &&
+          ntohl (dd->dd_seqnum) != nbr->dd_seqnum) ||
+         (!IS_SET_DD_MS (nbr->dd_flags) &&
+          ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1))
+       {
+         zlog_warn ("Pakcet[DD]: sequence number mismatch.");
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+         break;
+       }
+
+      /* Continue processing rest of packet. */
+      ospf_db_desc_proc (s, oi, nbr, dd, size);
+      break;
+    case NSM_Loading:
+    case NSM_Full:
+      if (ospf_db_desc_is_dup (dd, nbr))
+       {
+         if (IS_SET_DD_MS (nbr->dd_flags))
+           {
+             /* Master should discard duplicate DD packet. */
+             zlog_warn ("Pakcet[DD]: duplicated, packet discarded.");
+             break;
+           }
+         else
+           {
+             struct timeval t, now;
+             gettimeofday (&now, NULL);
+             t = tv_sub (now, nbr->last_send_ts);
+             if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0)
+               {
+                 /* In states Loading and Full the slave must resend
+                    its last Database Description packet in response to
+                    duplicate Database Description packets received
+                    from the master.  For this reason the slave must
+                    wait RouterDeadInterval seconds before freeing the
+                    last Database Description packet.  Reception of a
+                    Database Description packet from the master after
+                    this interval will generate a SeqNumberMismatch
+                    neighbor event. RFC2328 Section 10.8 */
+                 ospf_db_desc_resend (nbr);
+                 break;
+               }
+           }
+       }
+
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+      break;
+    default:
+      zlog_warn ("Packet[DD]: NSM illegal status.");
+      break;
+    }
+}
+
+#define OSPF_LSA_KEY_SIZE       12 /* type(4) + id(4) + ar(4) */
+
+/* OSPF Link State Request Read -- RFC2328 Section 10.7. */
+void
+ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
+            struct stream *s, struct ospf_interface *oi, u_int16_t size)
+{
+  struct ospf_neighbor *nbr;
+  u_int32_t ls_type;
+  struct in_addr ls_id;
+  struct in_addr adv_router;
+  struct ospf_lsa *find;
+  list ls_upd;
+  int length;
+
+  /* Increment statistics. */
+  oi->ls_req_in++;
+
+  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  if (nbr == NULL)
+    {
+      zlog_warn ("Link State Request: Unknown Neighbor %s.",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+
+  /* Neighbor State should be Exchange or later. */
+  if (nbr->state != NSM_Exchange &&
+      nbr->state != NSM_Loading &&
+      nbr->state != NSM_Full)
+    {
+      zlog_warn ("Link State Request: Neighbor state is %s, packet discarded.",
+                LOOKUP (ospf_nsm_state_msg, nbr->state));
+      return;
+    }
+
+  /* Send Link State Update for ALL requested LSAs. */
+  ls_upd = list_new ();
+  length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE;
+
+  while (size >= OSPF_LSA_KEY_SIZE)
+    {
+      /* Get one slice of Link State Request. */
+      ls_type = stream_getl (s);
+      ls_id.s_addr = stream_get_ipv4 (s);
+      adv_router.s_addr = stream_get_ipv4 (s);
+
+      /* Verify LSA type. */
+      if (ls_type < OSPF_MIN_LSA || ls_type >= OSPF_MAX_LSA)
+       {
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
+         list_delete (ls_upd);
+         return;
+       }
+
+      /* Search proper LSA in LSDB. */
+      find = ospf_lsa_lookup (oi->area, ls_type, ls_id, adv_router);
+      if (find == NULL)
+       {
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
+         list_delete (ls_upd);
+         return;
+       }
+
+      /* Packet overflows MTU size, send immediatly. */
+      if (length + ntohs (find->data->length) > OSPF_PACKET_MAX (oi))
+       {
+         if (oi->type == OSPF_IFTYPE_NBMA)
+           ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
+         else
+           ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT);
+
+         /* Only remove list contents.  Keep ls_upd. */
+         list_delete_all_node (ls_upd);
+
+         length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE;
+       }
+
+      /* Append LSA to update list. */
+      listnode_add (ls_upd, find);
+      length += ntohs (find->data->length);
+
+      size -= OSPF_LSA_KEY_SIZE;
+    }
+
+  /* Send rest of Link State Update. */
+  if (listcount (ls_upd) > 0)
+    {
+      if (oi->type == OSPF_IFTYPE_NBMA)
+       ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
+      else
+       ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT);
+
+      list_delete (ls_upd);
+    }
+  else
+    list_free (ls_upd);
+}
+
+/* Get the list of LSAs from Link State Update packet.
+   And process some validation -- RFC2328 Section 13. (1)-(2). */
+static list
+ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
+                      struct ospf_interface *oi, size_t size)
+{
+  u_int16_t count, sum;
+  u_int32_t length;
+  struct lsa_header *lsah;
+  struct ospf_lsa *lsa;
+  list lsas;
+
+  lsas = list_new ();
+
+  count = stream_getl (s);
+  size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */
+
+  for (; size >= OSPF_LSA_HEADER_SIZE && count > 0;
+       size -= length, stream_forward (s, length), count--)
+    {
+      lsah = (struct lsa_header *) STREAM_PNT (s);
+      length = ntohs (lsah->length);
+
+      if (length > size)
+       {
+         zlog_warn ("Link State Update: LSA length exceeds packet size.");
+         break;
+       }
+
+      /* Validate the LSA's LS checksum. */
+      sum = lsah->checksum;
+      if (sum != ospf_lsa_checksum (lsah))
+       {
+         zlog_warn ("Link State Update: LSA checksum error %x, %x.",
+                    sum, lsah->checksum);
+         continue;
+       }
+
+      /* Examine the LSA's LS type. */
+      if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA)
+       {
+         zlog_warn ("Link State Update: Unknown LS type %d", lsah->type);
+         continue;
+       }
+
+      /*
+       * What if the received LSA's age is greater than MaxAge?
+       * Treat it as a MaxAge case -- endo.
+       */
+      if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE)
+        lsah->ls_age = htons (OSPF_LSA_MAXAGE);
+
+#ifdef HAVE_OPAQUE_LSA
+      if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
+        {
+#ifdef STRICT_OBIT_USAGE_CHECK
+         if ((IS_OPAQUE_LSA(lsah->type) &&
+               ! CHECK_FLAG (lsah->options, OSPF_OPTION_O))
+         ||  (! IS_OPAQUE_LSA(lsah->type) &&
+               CHECK_FLAG (lsah->options, OSPF_OPTION_O)))
+            {
+              /*
+               * This neighbor must know the exact usage of O-bit;
+               * the bit will be set in Type-9,10,11 LSAs only.
+               */
+              zlog_warn ("LSA[Type%d:%s]: O-bit abuse?", lsah->type, inet_ntoa (lsah->id));
+              continue;
+            }
+#endif /* STRICT_OBIT_USAGE_CHECK */
+
+          /* Do not take in AS External Opaque-LSAs if we are a stub. */
+          if (lsah->type == OSPF_OPAQUE_AS_LSA
+             && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) 
+            {
+              if (IS_DEBUG_OSPF_EVENT)
+                zlog_info ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id));
+              continue;
+            }
+        }
+      else if (IS_OPAQUE_LSA(lsah->type))
+        {
+          zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id));
+          continue;
+        }
+#endif /* HAVE_OPAQUE_LSA */
+
+      /* Create OSPF LSA instance. */
+      lsa = ospf_lsa_new ();
+
+      /* We may wish to put some error checking if type NSSA comes in
+         and area not in NSSA mode */
+      switch (lsah->type)
+        {
+        case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+        case OSPF_OPAQUE_AS_LSA:
+          lsa->area = NULL;
+          break;
+        case OSPF_OPAQUE_LINK_LSA:
+          lsa->oi = oi; /* Remember incoming interface for flooding control. */
+          /* Fallthrough */
+#endif /* HAVE_OPAQUE_LSA */
+        default:
+          lsa->area = oi->area;
+          break;
+        }
+
+      lsa->data = ospf_lsa_data_new (length);
+      memcpy (lsa->data, lsah, length);
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info("LSA[Type%d:%s]: %p new LSA created with Link State Update",
+                 lsa->data->type, inet_ntoa (lsa->data->id), lsa);
+      listnode_add (lsas, lsa);
+    }
+
+  return lsas;
+}
+
+/* Cleanup Update list. */
+void
+ospf_upd_list_clean (list lsas)
+{
+  listnode node;
+  struct ospf_lsa *lsa;
+
+  for (node = listhead (lsas); node; nextnode (node))
+    if ((lsa = getdata (node)) != NULL)
+      ospf_lsa_discard (lsa);
+
+  list_delete (lsas);
+}
+
+/* OSPF Link State Update message read -- RFC2328 Section 13. */
+void
+ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
+            struct stream *s, struct ospf_interface *oi, u_int16_t size)
+{
+  struct ospf_neighbor *nbr;
+  list lsas;
+#ifdef HAVE_OPAQUE_LSA
+  list mylsa_acks, mylsa_upds;
+#endif /* HAVE_OPAQUE_LSA */
+  listnode node, next;
+  struct ospf_lsa *lsa = NULL;
+  /* unsigned long ls_req_found = 0; */
+
+  /* Dis-assemble the stream, update each entry, re-encapsulate for flooding */
+
+  /* Increment statistics. */
+  oi->ls_upd_in++;
+
+  /* Check neighbor. */
+  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  if (nbr == NULL)
+    {
+      zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s",
+                inet_ntoa (ospfh->router_id), IF_NAME (oi));
+      return;
+    }
+
+  /* Check neighbor state. */
+  if (nbr->state < NSM_Exchange)
+    {
+      zlog_warn ("Link State Update: Neighbor[%s] state is less than Exchange",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+
+  /* Get list of LSAs from Link State Update packet. - Also perorms Stages 
+   * 1 (validate LSA checksum) and 2 (check for LSA consistent type) 
+   * of section 13. 
+   */
+  lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size);
+
+#ifdef HAVE_OPAQUE_LSA
+  /*
+   * Prepare two kinds of lists to clean up unwanted self-originated
+   * Opaque-LSAs from the routing domain as soon as possible.
+   */
+  mylsa_acks = list_new (); /* Let the sender cease retransmission. */
+  mylsa_upds = list_new (); /* Flush target LSAs if necessary. */
+
+  /*
+   * If self-originated Opaque-LSAs that have flooded before restart
+   * are contained in the received LSUpd message, corresponding LSReq
+   * messages to be sent may have to be modified.
+   * To eliminate possible race conditions such that flushing and normal
+   * updating for the same LSA would take place alternately, this trick
+   * must be done before entering to the loop below.
+   */
+   ospf_opaque_adjust_lsreq (nbr, lsas);
+#endif /* HAVE_OPAQUE_LSA */
+
+#define DISCARD_LSA(L,N) {\
+        if (IS_DEBUG_OSPF_EVENT) \
+          zlog_info ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \
+        ospf_lsa_discard (L); \
+       continue; }
+
+  /* Process each LSA received in the one packet. */
+  for (node = listhead (lsas); node; node = next)
+    {
+      struct ospf_lsa *ls_ret, *current;
+      int ret = 1;
+
+      next = node->next;
+
+      lsa = getdata (node);
+
+#ifdef HAVE_NSSA
+      if (IS_DEBUG_OSPF_NSSA)
+       {
+         char buf1[INET_ADDRSTRLEN];
+         char buf2[INET_ADDRSTRLEN];
+         char buf3[INET_ADDRSTRLEN];
+
+         zlog_info("LSA Type-%d from %s, ID: %s, ADV: %s",
+                 lsa->data->type,
+                 inet_ntop (AF_INET, &ospfh->router_id,
+                            buf1, INET_ADDRSTRLEN),
+                 inet_ntop (AF_INET, &lsa->data->id,
+                            buf2, INET_ADDRSTRLEN),
+                 inet_ntop (AF_INET, &lsa->data->adv_router,
+                            buf3, INET_ADDRSTRLEN));
+       }
+#endif /* HAVE_NSSA */
+
+      listnode_delete (lsas, lsa); /* We don't need it in list anymore */
+
+      /* Validate Checksum - Done above by ospf_ls_upd_list_lsa() */
+
+      /* LSA Type  - Done above by ospf_ls_upd_list_lsa() */
+   
+      /* Do not take in AS External LSAs if we are a stub or NSSA. */
+
+      /* Do not take in AS NSSA if this neighbor and we are not NSSA */
+
+      /* Do take in Type-7's if we are an NSSA  */ 
+      /* If we are also an ABR, later translate them to a Type-5 packet */
+      /* Later, an NSSA Re-fresh can Re-fresh Type-7's and an ABR will
+        translate them to a separate Type-5 packet.  */
+
+      if (lsa->data->type == OSPF_AS_EXTERNAL_LSA)
+        /* Reject from STUB or NSSA */
+        if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) 
+         {
+           DISCARD_LSA (lsa, 1);
+#ifdef HAVE_NSSA
+           if (IS_DEBUG_OSPF_NSSA)
+             zlog_info("Incoming External LSA Discarded: We are NSSA/STUB Area");
+#endif /* HAVE_NSSA */
+         }
+
+#ifdef  HAVE_NSSA 
+      if (lsa->data->type == OSPF_AS_NSSA_LSA)
+       if (nbr->oi->area->external_routing != OSPF_AREA_NSSA)
+         {
+           DISCARD_LSA (lsa,2);
+           if (IS_DEBUG_OSPF_NSSA)
+             zlog_info("Incoming NSSA LSA Discarded:  Not NSSA Area");
+         }
+#endif /* HAVE_NSSA */
+
+      /* Find the LSA in the current database. */
+
+      current = ospf_lsa_lookup_by_header (oi->area, lsa->data);
+
+      /* If the LSA's LS age is equal to MaxAge, and there is currently
+        no instance of the LSA in the router's link state database,
+        and none of router's neighbors are in states Exchange or Loading,
+        then take the following actions. */
+
+      if (IS_LSA_MAXAGE (lsa) && !current &&
+         (ospf_nbr_count (oi->nbrs, NSM_Exchange) +
+          ospf_nbr_count (oi->nbrs, NSM_Loading)) == 0)
+       {
+         /* Response Link State Acknowledgment. */
+         ospf_ls_ack_send (nbr, lsa);
+
+         /* Discard LSA. */      
+         zlog_warn ("Link State Update: LS age is equal to MaxAge.");
+          DISCARD_LSA (lsa, 3);
+       }
+
+#ifdef HAVE_OPAQUE_LSA
+      if (IS_OPAQUE_LSA (lsa->data->type)
+      &&  IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf_top->router_id))
+        {
+          /*
+           * Even if initial flushing seems to be completed, there might
+           * be a case that self-originated LSA with MaxAge still remain
+           * in the routing domain.
+           * Just send an LSAck message to cease retransmission.
+           */
+          if (IS_LSA_MAXAGE (lsa))
+            {
+              zlog_warn ("LSA[%s]: Boomerang effect?", dump_lsa_key (lsa));
+              ospf_ls_ack_send (nbr, lsa);
+              ospf_lsa_discard (lsa);
+
+              if (current != NULL && ! IS_LSA_MAXAGE (current))
+                ospf_opaque_lsa_refresh_schedule (current);
+              continue;
+            }
+
+          /*
+           * If an instance of self-originated Opaque-LSA is not found
+           * in the LSDB, there are some possible cases here.
+           *
+           * 1) This node lost opaque-capability after restart.
+           * 2) Else, a part of opaque-type is no more supported.
+           * 3) Else, a part of opaque-id is no more supported.
+           *
+           * Anyway, it is still this node's responsibility to flush it.
+           * Otherwise, the LSA instance remains in the routing domain
+           * until its age reaches to MaxAge.
+           */
+          if (current == NULL)
+            {
+              if (IS_DEBUG_OSPF_EVENT)
+                zlog_info ("LSA[%s]: Previously originated Opaque-LSA, not found in the LSDB.", dump_lsa_key (lsa));
+
+              SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+              listnode_add (mylsa_upds, ospf_lsa_dup  (lsa));
+              listnode_add (mylsa_acks, ospf_lsa_lock (lsa));
+              continue;
+            }
+        }
+#endif /* HAVE_OPAQUE_LSA */
+
+      /* (5) Find the instance of this LSA that is currently contained
+        in the router's link state database.  If there is no
+        database copy, or the received LSA is more recent than
+        the database copy the following steps must be performed. */
+
+      if (current == NULL ||
+         (ret = ospf_lsa_more_recent (current, lsa)) < 0)
+       {
+         /* Actual flooding procedure. */
+         if (ospf_flood (nbr, current, lsa) < 0)  /* Trap NSSA later. */
+           DISCARD_LSA (lsa, 4);
+         continue;
+       }
+
+      /* (6) Else, If there is an instance of the LSA on the sending
+        neighbor's Link state request list, an error has occurred in
+        the Database Exchange process.  In this case, restart the
+        Database Exchange process by generating the neighbor event
+        BadLSReq for the sending neighbor and stop processing the
+        Link State Update packet. */
+
+      if (ospf_ls_request_lookup (nbr, lsa))
+       {
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
+         zlog_warn ("LSA instance exists on Link state request list");
+
+         /* Clean list of LSAs. */
+          ospf_upd_list_clean (lsas);
+         /* this lsa is not on lsas list already. */
+         ospf_lsa_discard (lsa);
+#ifdef HAVE_OPAQUE_LSA
+          list_delete (mylsa_acks);
+          list_delete (mylsa_upds);
+#endif /* HAVE_OPAQUE_LSA */
+         return;
+       }
+
+      /* If the received LSA is the same instance as the database copy
+        (i.e., neither one is more recent) the following two steps
+        should be performed: */
+
+      if (ret == 0)
+       {
+         /* If the LSA is listed in the Link state retransmission list
+            for the receiving adjacency, the router itself is expecting
+            an acknowledgment for this LSA.  The router should treat the
+            received LSA as an acknowledgment by removing the LSA from
+            the Link state retransmission list.  This is termed an
+            "implied acknowledgment". */
+
+         ls_ret = ospf_ls_retransmit_lookup (nbr, lsa);
+
+         if (ls_ret != NULL)
+           {
+             ospf_ls_retransmit_delete (nbr, ls_ret);
+
+             /* Delayed acknowledgment sent if advertisement received
+                from Designated Router, otherwise do nothing. */
+             if (oi->state == ISM_Backup)
+               if (NBR_IS_DR (nbr))
+                 listnode_add (oi->ls_ack, ospf_lsa_lock (lsa));
+
+              DISCARD_LSA (lsa, 5);
+           }
+         else
+           /* Acknowledge the receipt of the LSA by sending a
+              Link State Acknowledgment packet back out the receiving
+              interface. */
+           {
+             ospf_ls_ack_send (nbr, lsa);
+             DISCARD_LSA (lsa, 6);
+           }
+       }
+
+      /* The database copy is more recent.  If the database copy
+        has LS age equal to MaxAge and LS sequence number equal to
+        MaxSequenceNumber, simply discard the received LSA without
+        acknowledging it. (In this case, the LSA's LS sequence number is
+        wrapping, and the MaxSequenceNumber LSA must be completely
+        flushed before any new LSA instance can be introduced). */
+
+      else if (ret > 0)  /* Database copy is more recent */
+       { 
+         if (IS_LSA_MAXAGE (current) &&
+             current->data->ls_seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER))
+           {
+             DISCARD_LSA (lsa, 7);
+           }
+         /* Otherwise, as long as the database copy has not been sent in a
+            Link State Update within the last MinLSArrival seconds, send the
+            database copy back to the sending neighbor, encapsulated within
+            a Link State Update Packet. The Link State Update Packet should
+            be sent directly to the neighbor. In so doing, do not put the
+            database copy of the LSA on the neighbor's link state
+            retransmission list, and do not acknowledge the received (less
+            recent) LSA instance. */
+         else
+           {
+             struct timeval now;
+             
+             gettimeofday (&now, NULL);
+             
+             if (tv_cmp (tv_sub (now, current->tv_orig), 
+                         int2tv (OSPF_MIN_LS_ARRIVAL)) > 0)
+               /* Trap NSSA type later.*/
+               ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT);
+             DISCARD_LSA (lsa, 8);
+           }
+       }
+    }
+  
+#ifdef HAVE_OPAQUE_LSA
+  /*
+   * Now that previously originated Opaque-LSAs those which not yet
+   * installed into LSDB are captured, take several steps to clear
+   * them completely from the routing domain, before proceeding to
+   * origination for the current target Opaque-LSAs.
+   */
+  while (listcount (mylsa_acks) > 0)
+    ospf_ls_ack_send_list (oi, mylsa_acks, nbr->address.u.prefix4);
+
+  if (listcount (mylsa_upds) > 0)
+    ospf_opaque_self_originated_lsa_received (nbr, mylsa_upds);
+
+  list_delete (mylsa_upds);
+#endif /* HAVE_OPAQUE_LSA */
+
+  assert (listcount (lsas) == 0);
+  list_delete (lsas);
+}
+
+/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */
+void
+ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
+            struct stream *s, struct ospf_interface *oi, u_int16_t size)
+{
+  struct ospf_neighbor *nbr;
+#ifdef HAVE_OPAQUE_LSA
+  list opaque_acks;
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* increment statistics. */
+  oi->ls_ack_in++;
+
+  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  if (nbr == NULL)
+    {
+      zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.",
+                inet_ntoa (ospfh->router_id));
+      return;
+    }
+
+  if (nbr->state < NSM_Exchange)
+    {
+      zlog_warn ("Link State Acknowledgment: State is less than Exchange.");
+      return;
+    }
+
+#ifdef HAVE_OPAQUE_LSA
+  opaque_acks = list_new ();
+#endif /* HAVE_OPAQUE_LSA */
+
+  while (size >= OSPF_LSA_HEADER_SIZE)
+    {
+      struct ospf_lsa *lsa, *lsr;
+
+      lsa = ospf_lsa_new ();
+      lsa->data = (struct lsa_header *) STREAM_PNT (s);
+
+      /* lsah = (struct lsa_header *) STREAM_PNT (s); */
+      size -= OSPF_LSA_HEADER_SIZE;
+      stream_forward (s, OSPF_LSA_HEADER_SIZE);
+
+      if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA)
+       {
+         lsa->data = NULL;
+         ospf_lsa_discard (lsa);
+         continue;
+       }
+
+      lsr = ospf_ls_retransmit_lookup (nbr, lsa);
+
+      if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
+        {
+#ifdef HAVE_OPAQUE_LSA
+          /* Keep this LSA entry for later reference. */
+          if (IS_OPAQUE_LSA (lsr->data->type))
+            listnode_add (opaque_acks, ospf_lsa_dup (lsr));
+#endif /* HAVE_OPAQUE_LSA */
+
+          ospf_ls_retransmit_delete (nbr, lsr);
+        }
+
+      lsa->data = NULL;
+      ospf_lsa_discard (lsa);
+    }
+
+#ifdef HAVE_OPAQUE_LSA
+  if (listcount (opaque_acks) > 0)
+    ospf_opaque_ls_ack_received (nbr, opaque_acks);
+
+  list_delete (opaque_acks);
+  return;
+#endif /* HAVE_OPAQUE_LSA */
+}
+\f
+struct stream *
+ospf_recv_packet (int fd, struct interface **ifp)
+{
+  int ret;
+  struct ip iph;
+  u_int16_t ip_len;
+  struct stream *ibuf;
+  unsigned int ifindex = 0;
+  struct iovec iov;
+  struct cmsghdr *cmsg;
+#if defined (IP_PKTINFO)
+  struct in_pktinfo *pktinfo;
+#elif defined (IP_RECVIF)
+  struct sockaddr_dl *pktinfo;
+#else
+  char *pktinfo; /* dummy */
+#endif
+  char buff [sizeof (*cmsg) + sizeof (*pktinfo)];
+  struct msghdr msgh = {NULL, 0, &iov, 1, buff,
+                       sizeof (*cmsg) + sizeof (*pktinfo), 0};
+    
+  ret = recvfrom (fd, (void *)&iph, sizeof (iph), MSG_PEEK, NULL, 0);
+  
+  if (ret != sizeof (iph))
+    {
+      zlog_warn ("ospf_recv_packet packet smaller than ip header");
+      return NULL;
+    }
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+  ip_len = iph.ip_len;
+#else
+  ip_len = ntohs (iph.ip_len);
+#endif
+
+#if !defined(GNU_LINUX)
+  /*
+   * Kernel network code touches incoming IP header parameters,
+   * before protocol specific processing.
+   *
+   *   1) Convert byteorder to host representation.
+   *      --> ip_len, ip_id, ip_off
+   *
+   *   2) Adjust ip_len to strip IP header size!
+   *      --> If user process receives entire IP packet via RAW
+   *          socket, it must consider adding IP header size to
+   *          the "ip_len" field of "ip" structure.
+   *
+   * For more details, see <netinet/ip_input.c>.
+   */
+  ip_len = ip_len + (iph.ip_hl << 2);
+#endif
+  
+  ibuf = stream_new (ip_len);
+  iov.iov_base = STREAM_DATA (ibuf);
+  iov.iov_len = ip_len;
+  ret = recvmsg (fd, &msgh, 0);
+  
+  cmsg = CMSG_FIRSTHDR (&msgh);
+  
+  if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) &&
+      cmsg->cmsg_level == IPPROTO_IP &&
+#if defined (IP_PKTINFO)
+      cmsg->cmsg_type == IP_PKTINFO
+#elif defined (IP_RECVIF)
+      cmsg->cmsg_type == IP_RECVIF
+#else
+      0
+#endif
+      )
+    {
+#if defined (IP_PKTINFO)
+      pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
+      ifindex = pktinfo->ipi_ifindex;
+#elif defined (IP_RECVIF)
+      pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg);
+      ifindex = pktinfo->sdl_index;
+#else
+      ifindex = 0;
+#endif
+    }
+  
+  *ifp = if_lookup_by_index (ifindex);
+
+  if (ret != ip_len)
+    {
+      zlog_warn ("ospf_recv_packet short read. "
+                "ip_len %d bytes read %d", ip_len, ret);
+      stream_free (ibuf);
+      return NULL;
+    }
+  
+  return ibuf;
+}
+
+struct ospf_interface *
+ospf_associate_packet_vl (struct interface *ifp, struct ospf_interface *oi,
+                         struct ip *iph, struct ospf_header *ospfh)
+{
+  struct ospf_interface *rcv_oi;
+  listnode node;
+  struct ospf_vl_data *vl_data;
+  struct ospf_area *vl_area;
+
+  if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) ||
+      !OSPF_IS_AREA_BACKBONE (ospfh))
+    return oi;
+
+  if ((rcv_oi = oi) == NULL)
+    {
+     if ((rcv_oi = ospf_if_lookup_by_local_addr (ifp, iph->ip_dst)) == NULL)
+       return NULL;
+    }
+
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    {
+      if ((vl_data = getdata (node)) == NULL)
+       continue;
+      
+      vl_area = ospf_area_lookup_by_area_id (vl_data->vl_area_id);
+      if (!vl_area)
+       continue;
+      
+      if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) &&
+         IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("associating packet with %s",
+                      IF_NAME (vl_data->vl_oi));
+         if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP))
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("This VL is not up yet, sorry");
+             return NULL;
+           }
+         
+         return vl_data->vl_oi;
+       }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("couldn't find any VL to associate the packet with");
+  
+  return oi;
+}
+
+int
+ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+  /* Check match the Area ID of the receiving interface. */
+  if (OSPF_AREA_SAME (&oi->area, &ospfh))
+    return 1;
+
+  return 0;
+}
+
+/* Unbound socket will accept any Raw IP packets if proto is matched.
+   To prevent it, compare src IP address and i/f address with masking
+   i/f network mask. */
+int
+ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
+{
+  struct in_addr mask, me, him;
+
+  if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
+      oi->type == OSPF_IFTYPE_VIRTUALLINK)
+    return 1;
+
+  masklen2ip (oi->address->prefixlen, &mask);
+
+  me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+  him.s_addr = ip_src.s_addr & mask.s_addr;
+
+ if (IPV4_ADDR_SAME (&me, &him))
+   return 1;
+
+ return 0;
+}
+
+int
+ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
+                struct ospf_header *ospfh)
+{
+  int ret = 0;
+  struct crypt_key *ck;
+
+  switch (ntohs (ospfh->auth_type))
+    {
+    case OSPF_AUTH_NULL:
+      ret = 1;
+      break;
+    case OSPF_AUTH_SIMPLE:
+      if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE))
+       ret = 1;
+      else
+       ret = 0;
+      break;
+    case OSPF_AUTH_CRYPTOGRAPHIC:
+      if ((ck = getdata (OSPF_IF_PARAM (oi,auth_crypt)->tail)) == NULL)
+       {
+         ret = 0;
+         break;
+       }
+      
+      /* This is very basic, the digest processing is elsewhere */
+      if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && 
+          ospfh->u.crypt.key_id == ck->key_id &&
+          ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= stream_get_size (ibuf))
+        ret = 1;
+      else
+        ret = 0;
+      break;
+    default:
+      ret = 0;
+      break;
+    }
+
+  return ret;
+}
+
+int
+ospf_check_sum (struct ospf_header *ospfh)
+{
+  u_int32_t ret;
+  u_int16_t sum;
+  int in_cksum (void *ptr, int nbytes);
+
+  /* clear auth_data for checksum. */
+  memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+
+  /* keep checksum and clear. */
+  sum = ospfh->checksum;
+  memset (&ospfh->checksum, 0, sizeof (u_int16_t));
+
+  /* calculate checksum. */
+  ret = in_cksum (ospfh, ntohs (ospfh->length));
+
+  if (ret != sum)
+    {
+      zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X",
+                ret, sum);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* OSPF Header verification. */
+int
+ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
+                   struct ip *iph, struct ospf_header *ospfh)
+{
+  /* check version. */
+  if (ospfh->version != OSPF_VERSION)
+    {
+      zlog_warn ("interface %s: ospf_read version number mismatch.",
+                IF_NAME (oi));
+      return -1;
+    }
+
+  /* Check Area ID. */
+  if (!ospf_check_area_id (oi, ospfh))
+    {
+      zlog_warn ("interface %s: ospf_read invalid Area ID %s.",
+                IF_NAME (oi), inet_ntoa (ospfh->area_id));
+      return -1;
+    }
+
+  /* Check network mask, Silently discarded. */
+  if (! ospf_check_network_mask (oi, iph->ip_src))
+    {
+      zlog_warn ("interface %s: ospf_read network address is not same [%s]",
+                IF_NAME (oi), inet_ntoa (iph->ip_src));
+      return -1;
+    }
+
+  /* Check authentication. */
+  if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))
+    {
+      zlog_warn ("interface %s: ospf_read authentication type mismatch.",
+                IF_NAME (oi));
+      return -1;
+    }
+
+  if (! ospf_check_auth (oi, ibuf, ospfh))
+    {
+      zlog_warn ("interface %s: ospf_read authentication failed.",
+                IF_NAME (oi));
+      return -1;
+    }
+
+  /* if check sum is invalid, packet is discarded. */
+  if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+    {
+      if (! ospf_check_sum (ospfh))
+       {
+         zlog_warn ("interface %s: ospf_read packet checksum error %s",
+                    IF_NAME (oi), inet_ntoa (ospfh->router_id));
+         return -1;
+       }
+    }
+  else
+    {
+      if (ospfh->checksum != 0)
+       return -1;
+      if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0)
+       {
+         zlog_warn ("interface %s: ospf_read md5 authentication failed.",
+                    IF_NAME (oi));
+         return -1;
+       }
+    }
+
+  return 0;
+}
+
+/* Starting point of packet process function. */
+int
+ospf_read (struct thread *thread)
+{
+  int ret;
+  struct stream *ibuf;
+  struct ospf *top;
+  struct ospf_interface *oi;
+  struct ip *iph;
+  struct ospf_header *ospfh;
+  u_int16_t length;
+  struct interface *ifp;
+
+  /* first of all get interface pointer. */
+  top = THREAD_ARG (thread);
+  top->t_read = NULL;
+
+  /* read OSPF packet. */
+  ibuf = ospf_recv_packet (top->fd, &ifp);
+  if (ibuf == NULL)
+    return -1;
+  
+  iph = (struct ip *) STREAM_DATA (ibuf);
+
+  /* prepare for next packet. */
+  top->t_read = thread_add_read (master, ospf_read, top, top->fd);
+
+  /* IP Header dump. */
+  /*
+  if (ospf_debug_packet & OSPF_DEBUG_RECV)
+    ospf_ip_header_dump (ibuf);
+  */
+  /* Self-originated packet should be discarded silently. */
+  if (ospf_if_lookup_by_local_addr (NULL, iph->ip_src))
+    {
+      stream_free (ibuf);
+      return 0;
+    }
+
+  /* Adjust size to message length. */
+  stream_forward (ibuf, iph->ip_hl * 4);
+  
+  /* Get ospf packet header. */
+  ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
+
+  /* associate packet with ospf interface */
+  oi = ospf_if_lookup_recv_interface (iph->ip_src);
+  if (ifp && oi && oi->ifp != ifp)
+    {
+      zlog_warn ("Packet from [%s] received on wrong link %s",
+                inet_ntoa (iph->ip_src), ifp->name); 
+      stream_free (ibuf);
+      return 0;
+    }
+  
+  if ((oi = ospf_associate_packet_vl (ifp, oi, iph, ospfh)) == NULL)
+    {
+      stream_free (ibuf);
+      return 0;
+    }
+
+  /*
+   * If the received packet is destined for AllDRouters, the packet
+   * should be accepted only if the received ospf interface state is
+   * either DR or Backup -- endo.
+   */
+  if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS)
+  && (oi->state != ISM_DR && oi->state != ISM_Backup))
+    {
+      zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)",
+                 inet_ntoa (iph->ip_src), IF_NAME (oi),
+                 LOOKUP (ospf_ism_state_msg, oi->state));
+      stream_free (ibuf);
+      return 0;
+    }
+
+  /* Show debug receiving packet. */
+  if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+    {
+      if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
+       {
+         zlog_info ("-----------------------------------------------------");
+         ospf_packet_dump (ibuf);
+       }
+
+      zlog_info ("%s received from [%s] via [%s]",
+                ospf_packet_type_str[ospfh->type],
+                inet_ntoa (ospfh->router_id), IF_NAME (oi));
+      zlog_info (" src [%s],", inet_ntoa (iph->ip_src));
+      zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst));
+
+      if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
+       zlog_info ("-----------------------------------------------------");
+    }
+
+  /* Some header verification. */
+  ret = ospf_verify_header (ibuf, oi, iph, ospfh);
+  if (ret < 0)
+    {
+      stream_free (ibuf);
+      return ret;
+    }
+
+  stream_forward (ibuf, OSPF_HEADER_SIZE);
+
+  /* Adjust size to message length. */
+  length = ntohs (ospfh->length) - OSPF_HEADER_SIZE;
+
+  /* Read rest of the packet and call each sort of packet routine. */
+  switch (ospfh->type)
+    {
+    case OSPF_MSG_HELLO:
+      ospf_hello (iph, ospfh, ibuf, oi, length);
+      break;
+    case OSPF_MSG_DB_DESC:
+      ospf_db_desc (iph, ospfh, ibuf, oi, length);
+      break;
+    case OSPF_MSG_LS_REQ:
+      ospf_ls_req (iph, ospfh, ibuf, oi, length);
+      break;
+    case OSPF_MSG_LS_UPD:
+      ospf_ls_upd (iph, ospfh, ibuf, oi, length);
+      break;
+    case OSPF_MSG_LS_ACK:
+      ospf_ls_ack (iph, ospfh, ibuf, oi, length);
+      break;
+    default:
+      zlog (NULL, LOG_WARNING,
+           "interface %s: OSPF packet header type %d is illegal",
+           IF_NAME (oi), ospfh->type);
+      break;
+    }
+
+  stream_free (ibuf);
+  return 0;
+}
+
+/* Make OSPF header. */
+void
+ospf_make_header (int type, struct ospf_interface *oi, struct stream *s)
+{
+  struct ospf_header *ospfh;
+
+  ospfh = (struct ospf_header *) STREAM_DATA (s);
+
+  ospfh->version = (u_char) OSPF_VERSION;
+  ospfh->type = (u_char) type;
+
+  ospfh->router_id = ospf_top->router_id;
+
+  ospfh->checksum = 0;
+  ospfh->area_id = oi->area->area_id;
+  ospfh->auth_type = htons (ospf_auth_type (oi));
+
+  memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+
+  ospf_output_forward (s, OSPF_HEADER_SIZE);
+}
+
+/* Make Authentication Data. */
+int
+ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+  struct crypt_key *ck;
+
+  switch (ospf_auth_type (oi))
+    {
+    case OSPF_AUTH_NULL:
+      /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */
+      break;
+    case OSPF_AUTH_SIMPLE:
+      memcpy (ospfh->u.auth_data, OSPF_IF_PARAM (oi, auth_simple),
+             OSPF_AUTH_SIMPLE_SIZE);
+      break;
+    case OSPF_AUTH_CRYPTOGRAPHIC:
+      /* If key is not set, then set 0. */
+      if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
+       {
+         ospfh->u.crypt.zero = 0;
+         ospfh->u.crypt.key_id = 0;
+         ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+       }
+      else
+       {
+         ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+         ospfh->u.crypt.zero = 0;
+         ospfh->u.crypt.key_id = ck->key_id;
+         ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+       }
+      /* note: the seq is done in ospf_make_md5_digest() */
+      break;
+    default:
+      /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */
+      break;
+    }
+
+  return 0;
+}
+
+/* Fill rest of OSPF header. */
+void
+ospf_fill_header (struct ospf_interface *oi,
+                 struct stream *s, u_int16_t length)
+{
+  struct ospf_header *ospfh;
+
+  ospfh = (struct ospf_header *) STREAM_DATA (s);
+
+  /* Fill length. */
+  ospfh->length = htons (length);
+
+  /* Calculate checksum. */
+  if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+    ospfh->checksum = in_cksum (ospfh, length);
+  else
+    ospfh->checksum = 0;
+
+  /* Add Authentication Data. */
+  ospf_make_auth (oi, ospfh);
+}
+
+int
+ospf_make_hello (struct ospf_interface *oi, struct stream *s)
+{
+  struct ospf_neighbor *nbr;
+  struct route_node *rn;
+  u_int16_t length = OSPF_HELLO_MIN_SIZE;
+  struct in_addr mask;
+  unsigned long p;
+  int flag = 0;
+
+  /* Set netmask of interface. */
+  if (oi->type != OSPF_IFTYPE_POINTOPOINT &&
+      oi->type != OSPF_IFTYPE_VIRTUALLINK)
+    masklen2ip (oi->address->prefixlen, &mask);
+  else
+    memset ((char *) &mask, 0, sizeof (struct in_addr));
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* Set Hello Interval. */
+  stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("make_hello: options: %x, int: %s",
+              OPTIONS(oi), IF_NAME (oi));
+
+  /* Set Options. */
+  stream_putc (s, OPTIONS (oi));
+
+  /* Set Router Priority. */
+  stream_putc (s, PRIORITY (oi));
+
+  /* Set Router Dead Interval. */
+  stream_putl (s, OSPF_IF_PARAM (oi, v_wait));
+
+  /* Set Designated Router. */
+  stream_put_ipv4 (s, DR (oi).s_addr);
+
+  p = s->putp;
+
+  /* Set Backup Designated Router. */
+  stream_put_ipv4 (s, BDR (oi).s_addr);
+
+  /* Add neighbor seen. */
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info) != NULL)
+      /* ignore 0.0.0.0 node. */
+      if (nbr->router_id.s_addr != 0)
+       if (nbr->state != NSM_Attempt)
+       /* ignore Down neighbor. */
+       if (nbr->state != NSM_Down)
+         /* this is myself for DR election. */
+         if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf_top->router_id))
+           {
+             /* Check neighbor is sane? */
+             if (nbr->d_router.s_addr != 0 &&
+                 IPV4_ADDR_SAME (&nbr->d_router, &oi->address->u.prefix4) &&
+                 IPV4_ADDR_SAME (&nbr->bd_router, &oi->address->u.prefix4))
+               flag = 1;
+
+             stream_put_ipv4 (s, nbr->router_id.s_addr);
+             length += 4;
+           }
+
+  /* Let neighbor generate BackupSeen. */
+  if (flag == 1)
+    {
+      stream_set_putp (s, p);
+      stream_put_ipv4 (s, 0);
+    }
+
+  return length;
+}
+
+int
+ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
+                  struct stream *s)
+{
+  struct ospf_lsa *lsa;
+  u_int16_t length = OSPF_DB_DESC_MIN_SIZE;
+  u_char options;
+  unsigned long pp;
+  int i;
+  struct ospf_lsdb *lsdb;
+  
+  /* Set Interface MTU. */
+  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+    stream_putw (s, 0);
+  else
+    stream_putw (s, oi->ifp->mtu);
+
+  /* Set Options. */
+  options = OPTIONS (oi);
+#ifdef HAVE_OPAQUE_LSA
+  if (CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE))
+    {
+      if (IS_SET_DD_I (nbr->dd_flags)
+      ||  CHECK_FLAG (nbr->options, OSPF_OPTION_O))
+        /*
+         * Set O-bit in the outgoing DD packet for capablity negotiation,
+         * if one of following case is applicable. 
+         *
+         * 1) WaitTimer expiration event triggered the neighbor state to
+         *    change to Exstart, but no (valid) DD packet has received
+         *    from the neighbor yet.
+         *
+         * 2) At least one DD packet with O-bit on has received from the
+         *    neighbor.
+         */
+        SET_FLAG (options, OSPF_OPTION_O);
+    }
+#endif /* HAVE_OPAQUE_LSA */
+  stream_putc (s, options);
+
+  /* Keep pointer to flags. */
+  pp = stream_get_putp (s);
+  stream_putc (s, nbr->dd_flags);
+
+  /* Set DD Sequence Number. */
+  stream_putl (s, nbr->dd_seqnum);
+
+  if (ospf_db_summary_isempty (nbr))
+    {
+      if (nbr->state >= NSM_Exchange)
+       {
+         nbr->dd_flags &= ~OSPF_DD_FLAG_M;
+         /* Set DD flags again */
+         stream_set_putp (s, pp);
+         stream_putc (s, nbr->dd_flags);
+       }
+      return length;
+    }
+
+  /* Describe LSA Header from Database Summary List. */
+  lsdb = &nbr->db_sum;
+
+  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+    {
+      struct route_table *table = lsdb->type[i].db;
+      struct route_node *rn;
+
+      for (rn = route_top (table); rn; rn = route_next (rn))
+       if ((lsa = rn->info) != NULL)
+         {
+#ifdef HAVE_OPAQUE_LSA
+            if (IS_OPAQUE_LSA (lsa->data->type)
+            && (! CHECK_FLAG (options, OSPF_OPTION_O)))
+              {
+                /* Suppress advertising opaque-informations. */
+                /* Remove LSA from DB summary list. */
+                ospf_lsdb_delete (lsdb, lsa);
+                continue;
+              }
+#endif /* HAVE_OPAQUE_LSA */
+
+           if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD))
+             {
+               struct lsa_header *lsah;
+               u_int16_t ls_age;
+               
+               /* DD packet overflows interface MTU. */
+               if (length + OSPF_LSA_HEADER_SIZE > OSPF_PACKET_MAX (oi))
+                 break;
+               
+               /* Keep pointer to LS age. */
+               lsah = (struct lsa_header *) (STREAM_DATA (s) +
+                                             stream_get_putp (s));
+               
+               /* Proceed stream pointer. */
+               stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
+               length += OSPF_LSA_HEADER_SIZE;
+               
+               /* Set LS age. */
+               ls_age = LS_AGE (lsa);
+               lsah->ls_age = htons (ls_age);
+               
+             }
+           
+           /* Remove LSA from DB summary list. */
+           ospf_lsdb_delete (lsdb, lsa);
+         }
+    }
+
+  return length;
+}
+
+int
+ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
+                      unsigned long delta, struct ospf_neighbor *nbr,
+                      struct ospf_lsa *lsa)
+{
+  struct ospf_interface *oi;
+
+  oi = nbr->oi;
+
+  /* LS Request packet overflows interface MTU. */
+  if (*length + delta > OSPF_PACKET_MAX(oi))
+    return 0;
+
+  stream_putl (s, lsa->data->type);
+  stream_put_ipv4 (s, lsa->data->id.s_addr);
+  stream_put_ipv4 (s, lsa->data->adv_router.s_addr);
+  
+  ospf_lsa_unlock (nbr->ls_req_last);
+  nbr->ls_req_last = ospf_lsa_lock (lsa);
+  
+  *length += 12;
+  return 1;
+}
+
+int
+ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s)
+{
+  struct ospf_lsa *lsa;
+  u_int16_t length = OSPF_LS_REQ_MIN_SIZE;
+  unsigned long delta = stream_get_putp(s)+12;
+  struct route_table *table;
+  struct route_node *rn;
+  int i;
+  struct ospf_lsdb *lsdb;
+
+  lsdb = &nbr->ls_req;
+
+  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+    {
+      table = lsdb->type[i].db;
+      for (rn = route_top (table); rn; rn = route_next (rn))
+       if ((lsa = (rn->info)) != NULL)
+         if (ospf_make_ls_req_func (s, &length, delta, nbr, lsa) == 0)
+           {
+             route_unlock_node (rn);
+             break;
+           }
+    }
+  return length;
+}
+
+int
+ls_age_increment (struct ospf_lsa *lsa, int delay)
+{
+  int age;
+
+  age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay;
+
+  return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
+}
+
+int
+ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s)
+{
+  struct ospf_lsa *lsa;
+  listnode node;
+  u_int16_t length = OSPF_LS_UPD_MIN_SIZE;
+  unsigned long delta = stream_get_putp (s);
+  unsigned long pp;
+  int count = 0;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info("ospf_make_ls_upd: Start");
+  
+  pp = stream_get_putp (s);
+  ospf_output_forward (s, 4);
+
+  while ((node = listhead (update)) != NULL)
+    {
+      struct lsa_header *lsah;
+      u_int16_t ls_age;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info("ospf_make_ls_upd: List Iteration");
+
+      lsa = getdata (node);
+      assert (lsa);
+      assert (lsa->data);
+
+      /* Check packet size. */
+      if (length + delta + ntohs (lsa->data->length) > OSPF_PACKET_MAX (oi))
+       break;
+      
+      /* Keep pointer to LS age. */
+      lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_putp (s));
+
+      /* Put LSA to Link State Request. */
+      stream_put (s, lsa->data, ntohs (lsa->data->length));
+
+      /* Set LS age. */
+      /* each hop must increment an lsa_age by transmit_delay 
+         of OSPF interface */
+      ls_age = ls_age_increment (lsa, OSPF_IF_PARAM (oi, transmit_delay));
+      lsah->ls_age = htons (ls_age);
+
+      length += ntohs (lsa->data->length);
+      count++;
+
+      list_delete_node (update, node);
+      ospf_lsa_unlock (lsa);
+    }
+
+  /* Now set #LSAs. */
+  stream_set_putp (s, pp);
+  stream_putl (s, count);
+
+  stream_set_putp (s, s->endp);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info("ospf_make_ls_upd: Stop");
+  return length;
+}
+
+int
+ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s)
+{
+  list rm_list;
+  listnode node;
+  u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
+  unsigned long delta = stream_get_putp(s) + 24;
+  struct ospf_lsa *lsa;
+
+  rm_list = list_new ();
+  
+  for (node = listhead (ack); node; nextnode (node))
+    {
+      lsa = getdata (node);
+      assert (lsa);
+      
+      if (length + delta > OSPF_PACKET_MAX (oi))
+       break;
+      
+      stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
+      length += OSPF_LSA_HEADER_SIZE;
+      
+      listnode_add (rm_list, lsa);
+    }
+  
+  /* Remove LSA from LS-Ack list. */
+  for (node = listhead (rm_list); node; nextnode (node))
+    {
+      lsa = (struct ospf_lsa *) getdata (node);
+      
+      listnode_delete (ack, lsa);
+      ospf_lsa_unlock (lsa);
+    }
+  
+  list_delete (rm_list);
+  
+  return length;
+}
+
+void
+ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr)
+{
+  struct ospf_packet *op;
+  u_int16_t length = OSPF_HEADER_SIZE;
+
+  op = ospf_packet_new (oi->ifp->mtu);
+
+  /* Prepare OSPF common header. */
+  ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
+
+  /* Prepare OSPF Hello body. */
+  length += ospf_make_hello (oi, op->s);
+
+  /* Fill OSPF header. */
+  ospf_fill_header (oi, op->s, length);
+
+  /* Set packet length. */
+  op->length = length;
+
+  op->dst.s_addr = addr->s_addr;
+
+  /* Add packet to the interface output queue. */
+  ospf_packet_add (oi, op);
+
+  /* Hook thread to write packet. */
+  OSPF_ISM_WRITE_ON ();
+}
+
+void
+ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
+{
+  struct ospf_interface *oi;
+
+  oi = nbr_nbma->oi;
+  assert(oi);
+
+  /* If this is passive interface, do not send OSPF Hello. */
+  if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+    return;
+
+  if (oi->type != OSPF_IFTYPE_NBMA)
+    return;
+
+  if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down)
+    return;
+
+  if (PRIORITY(oi) == 0)
+    return;
+
+  if (nbr_nbma->priority == 0
+      && oi->state != ISM_DR && oi->state != ISM_Backup)
+    return;
+
+  ospf_hello_send_sub (oi, &nbr_nbma->addr);
+}
+
+int
+ospf_poll_timer (struct thread *thread)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = THREAD_ARG (thread);
+  nbr_nbma->t_poll = NULL;
+
+  if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
+    zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (Poll timer expire)",
+    IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr));
+
+  ospf_poll_send (nbr_nbma);
+
+  if (nbr_nbma->v_poll > 0)
+    OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
+                       nbr_nbma->v_poll);
+
+  return 0;
+}
+
+
+int
+ospf_hello_reply_timer (struct thread *thread)
+{
+  struct ospf_neighbor *nbr;
+
+  nbr = THREAD_ARG (thread);
+  nbr->t_hello_reply = NULL;
+
+  assert (nbr->oi);
+
+  if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
+    zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (hello-reply timer expire)",
+         IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
+
+  ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4);
+
+  return 0;
+}
+
+/* Send OSPF Hello. */
+void
+ospf_hello_send (struct ospf_interface *oi)
+{
+  struct ospf_packet *op;
+  u_int16_t length = OSPF_HEADER_SIZE;
+
+  /* If this is passive interface, do not send OSPF Hello. */
+  if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+    return;
+
+  op = ospf_packet_new (oi->ifp->mtu);
+
+  /* Prepare OSPF common header. */
+  ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
+
+  /* Prepare OSPF Hello body. */
+  length += ospf_make_hello (oi, op->s);
+
+  /* Fill OSPF header. */
+  ospf_fill_header (oi, op->s, length);
+
+  /* Set packet length. */
+  op->length = length;
+
+  if (oi->type == OSPF_IFTYPE_NBMA)
+    {
+      struct ospf_neighbor *nbr;
+      struct route_node *rn;
+
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info))
+         if (nbr != oi->nbr_self)
+           if (nbr->state != NSM_Down)
+             {
+               /*  RFC 2328  Section 9.5.1
+                   If the router is not eligible to become Designated Router,
+                   it must periodically send Hello Packets to both the
+                   Designated Router and the Backup Designated Router (if they
+                   exist).  */
+               if (PRIORITY(oi) == 0 &&
+                   IPV4_ADDR_CMP(&DR(oi),  &nbr->address.u.prefix4) &&
+                   IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4))
+                 continue;
+
+               /*  If the router is eligible to become Designated Router, it
+                   must periodically send Hello Packets to all neighbors that
+                   are also eligible. In addition, if the router is itself the
+                   Designated Router or Backup Designated Router, it must also
+                   send periodic Hello Packets to all other neighbors. */
+
+               if (nbr->priority == 0 && oi->state == ISM_DROther)
+                 continue;
+               /* if oi->state == Waiting, send hello to all neighbors */
+               {
+                 struct ospf_packet *op_dup;
+
+                 op_dup = ospf_packet_dup(op);
+                 op_dup->dst = nbr->address.u.prefix4;
+
+                 /* Add packet to the interface output queue. */
+                 ospf_packet_add (oi, op_dup);
+
+                 OSPF_ISM_WRITE_ON ();
+               }
+
+             }
+      ospf_packet_free (op);
+    }
+  else
+    {
+      /* Decide destination address. */
+      if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+       op->dst.s_addr = oi->vl_data->peer_addr.s_addr;
+      else 
+       op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+
+      /* Add packet to the interface output queue. */
+      ospf_packet_add (oi, op);
+
+      /* Hook thread to write packet. */
+      OSPF_ISM_WRITE_ON ();
+    }
+}
+
+/* Send OSPF Database Description. */
+void
+ospf_db_desc_send (struct ospf_neighbor *nbr)
+{
+  struct ospf_interface *oi;
+  struct ospf_packet *op;
+  u_int16_t length = OSPF_HEADER_SIZE;
+
+  oi = nbr->oi;
+  op = ospf_packet_new (oi->ifp->mtu);
+
+  /* Prepare OSPF common header. */
+  ospf_make_header (OSPF_MSG_DB_DESC, oi, op->s);
+
+  /* Prepare OSPF Database Description body. */
+  length += ospf_make_db_desc (oi, nbr, op->s);
+
+  /* Fill OSPF header. */
+  ospf_fill_header (oi, op->s, length);
+
+  /* Set packet length. */
+  op->length = length;
+
+  /* Decide destination address. */
+  op->dst = nbr->address.u.prefix4;
+
+  /* Add packet to the interface output queue. */
+  ospf_packet_add (oi, op);
+
+  /* Hook thread to write packet. */
+  OSPF_ISM_WRITE_ON ();
+
+  /* Remove old DD packet, then copy new one and keep in neighbor structure. */
+  if (nbr->last_send)
+    ospf_packet_free (nbr->last_send);
+  nbr->last_send = ospf_packet_dup (op);
+  gettimeofday (&nbr->last_send_ts, NULL);
+}
+
+/* Re-send Database Description. */
+void
+ospf_db_desc_resend (struct ospf_neighbor *nbr)
+{
+  struct ospf_interface *oi;
+
+  oi = nbr->oi;
+
+  /* Add packet to the interface output queue. */
+  ospf_packet_add (oi, ospf_packet_dup (nbr->last_send));
+
+  /* Hook thread to write packet. */
+  OSPF_ISM_WRITE_ON ();
+}
+
+/* Send Link State Request. */
+void
+ospf_ls_req_send (struct ospf_neighbor *nbr)
+{
+  struct ospf_interface *oi;
+  struct ospf_packet *op;
+  u_int16_t length = OSPF_HEADER_SIZE;
+
+  oi = nbr->oi;
+  op = ospf_packet_new (oi->ifp->mtu);
+
+  /* Prepare OSPF common header. */
+  ospf_make_header (OSPF_MSG_LS_REQ, oi, op->s);
+
+  /* Prepare OSPF Link State Request body. */
+  length += ospf_make_ls_req (nbr, op->s);
+  if (length == OSPF_HEADER_SIZE)
+    {
+      ospf_packet_free (op);
+      return;
+    }
+
+  /* Fill OSPF header. */
+  ospf_fill_header (oi, op->s, length);
+
+  /* Set packet length. */
+  op->length = length;
+
+  /* Decide destination address. */
+  op->dst = nbr->address.u.prefix4;
+
+  /* Add packet to the interface output queue. */
+  ospf_packet_add (oi, op);
+
+  /* Hook thread to write packet. */
+  OSPF_ISM_WRITE_ON ();
+
+  /* Add Link State Request Retransmission Timer. */
+  OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
+}
+
+/* Send Link State Update with an LSA. */
+void
+ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
+                     int flag)
+{
+  list update;
+
+  update = list_new ();
+
+  listnode_add (update, lsa);
+  ospf_ls_upd_send (nbr, update, flag);
+
+  list_delete (update);
+}
+
+static void
+ospf_ls_upd_queue_send (struct ospf_interface *oi, list update,
+                       struct in_addr addr)
+{
+  struct ospf_packet *op;
+  u_int16_t length = OSPF_HEADER_SIZE;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr));
+
+  op = ospf_packet_new (oi->ifp->mtu);
+
+  /* Prepare OSPF common header. */
+  ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s);
+
+  /* Prepare OSPF Link State Update body. */
+  /* Includes Type-7 translation. */
+  length += ospf_make_ls_upd (oi, update, op->s);
+
+  /* Fill OSPF header. */
+  ospf_fill_header (oi, op->s, length);
+
+  /* Set packet length. */
+  op->length = length;
+
+  /* Decide destination address. */
+  op->dst.s_addr = addr.s_addr;
+
+  /* Add packet to the interface output queue. */
+  ospf_packet_add (oi, op);
+
+  /* Hook thread to write packet. */
+  OSPF_ISM_WRITE_ON ();
+}
+
+static int
+ospf_ls_upd_send_queue_event (struct thread *thread)
+{
+  struct ospf_interface *oi = THREAD_ARG(thread);
+  struct route_node *rn;
+  
+  oi->t_ls_upd_event = NULL;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_ls_upd_send_queue start");
+
+  for (rn = route_top (oi->ls_upd_queue); rn; rn = route_next (rn))
+    {
+      if (rn->info == NULL)
+       continue;
+
+      while (!list_isempty ((list)rn->info))
+       ospf_ls_upd_queue_send (oi, rn->info, rn->p.u.prefix4);
+
+      list_delete (rn->info);
+      rn->info = NULL;
+      
+      route_unlock_node (rn);
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_ls_upd_send_queue stop");
+  return 0;
+}
+
+void
+ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag)
+{
+  struct ospf_interface *oi;
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  listnode n;
+  
+  oi = nbr->oi;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  
+  /* Decide destination address. */
+  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+    p.prefix = oi->vl_data->peer_addr;
+  else if (flag == OSPF_SEND_PACKET_DIRECT)
+     p.prefix = nbr->address.u.prefix4;
+  else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+     p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else if ((oi->type == OSPF_IFTYPE_POINTOPOINT) 
+          && (flag == OSPF_SEND_PACKET_INDIRECT))
+     p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else
+     p.prefix.s_addr = htonl (OSPF_ALLDROUTERS);
+
+  if (oi->type == OSPF_IFTYPE_NBMA)
+    {
+      if (flag == OSPF_SEND_PACKET_INDIRECT)
+       zlog_warn ("* LS-Update is directly sent on NBMA network.");
+      if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr))
+       zlog_warn ("* LS-Update is sent to myself.");
+    }
+
+  rn = route_node_get (oi->ls_upd_queue, (struct prefix *) &p);
+
+  if (rn->info == NULL)
+    rn->info = list_new ();
+
+  for (n = listhead (update); n; nextnode (n))
+    listnode_add (rn->info, ospf_lsa_lock (getdata (n)));
+
+  if (oi->t_ls_upd_event == NULL)
+    oi->t_ls_upd_event =
+      thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0);
+}
+
+static void
+ospf_ls_ack_send_list (struct ospf_interface *oi, list ack, struct in_addr dst)
+{
+  struct ospf_packet *op;
+  u_int16_t length = OSPF_HEADER_SIZE;
+
+  op = ospf_packet_new (oi->ifp->mtu);
+
+  /* Prepare OSPF common header. */
+  ospf_make_header (OSPF_MSG_LS_ACK, oi, op->s);
+
+  /* Prepare OSPF Link State Acknowledgment body. */
+  length += ospf_make_ls_ack (oi, ack, op->s);
+
+  /* Fill OSPF header. */
+  ospf_fill_header (oi, op->s, length);
+
+  /* Set packet length. */
+  op->length = length;
+
+  /* Set destination IP address. */
+  op->dst = dst;
+  
+  /* Add packet to the interface output queue. */
+  ospf_packet_add (oi, op);
+
+  /* Hook thread to write packet. */
+  OSPF_ISM_WRITE_ON ();
+}
+
+static int
+ospf_ls_ack_send_event (struct thread *thread)
+{
+  struct ospf_interface *oi = THREAD_ARG (thread);
+
+  oi->t_ls_ack_direct = NULL;
+  
+  while (listcount (oi->ls_ack_direct.ls_ack))
+    ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack,
+                          oi->ls_ack_direct.dst);
+
+  return 0;
+}
+
+void
+ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+  struct ospf_interface *oi = nbr->oi;
+
+  if (listcount (oi->ls_ack_direct.ls_ack) == 0)
+    oi->ls_ack_direct.dst = nbr->address.u.prefix4;
+  
+  listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa));
+  
+  if (oi->t_ls_ack_direct == NULL)
+    oi->t_ls_ack_direct =
+      thread_add_event (master, ospf_ls_ack_send_event, oi, 0);
+}
+
+/* Send Link State Acknowledgment delayed. */
+void
+ospf_ls_ack_send_delayed (struct ospf_interface *oi)
+{
+  struct in_addr dst;
+  
+  /* Decide destination address. */
+  /* RFC2328 Section 13.5                           On non-broadcast
+       networks, delayed Link State Acknowledgment packets must be
+       unicast separately over each adjacency (i.e., neighbor whose
+       state is >= Exchange).  */
+  if (oi->type == OSPF_IFTYPE_NBMA)
+    {
+      struct ospf_neighbor *nbr;
+      struct route_node *rn;
+
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info) != NULL)
+         if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
+           while (listcount (oi->ls_ack))
+             ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4);
+      return;
+    }
+  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+    dst.s_addr = oi->vl_data->peer_addr.s_addr;
+  else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+    dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+    dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else
+    dst.s_addr = htonl (OSPF_ALLDROUTERS);
+
+  while (listcount (oi->ls_ack))
+    ospf_ls_ack_send_list (oi, oi->ls_ack, dst);
+}
diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h
new file mode 100644 (file)
index 0000000..81a104c
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * OSPF Sending and Receiving OSPF Packets.
+ * Copyright (C) 1999 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_PACKET_H
+#define _ZEBRA_OSPF_PACKET_H
+
+#define OSPF_HEADER_SIZE         24
+#define OSPF_AUTH_SIMPLE_SIZE     8
+#define OSPF_AUTH_MD5_SIZE       16
+
+#define OSPF_MAX_PACKET_SIZE  65535   /* includes IP Header size. */
+#define OSPF_HELLO_MIN_SIZE      20   /* not including neighbors */
+#define OSPF_DB_DESC_MIN_SIZE     8
+#define OSPF_LS_REQ_MIN_SIZE      0
+#define OSPF_LS_UPD_MIN_SIZE      4
+#define OSPF_LS_ACK_MIN_SIZE      0
+
+#define OSPF_MSG_HELLO         1  /* OSPF Hello Message. */
+#define OSPF_MSG_DB_DESC       2  /* OSPF Database Descriptoin Message. */
+#define OSPF_MSG_LS_REQ        3  /* OSPF Link State Request Message. */
+#define OSPF_MSG_LS_UPD        4  /* OSPF Link State Update Message. */
+#define OSPF_MSG_LS_ACK        5  /* OSPF Link State Acknoledgement Message. */
+
+#define OSPF_SEND_PACKET_DIRECT         1
+#define OSPF_SEND_PACKET_INDIRECT       2
+
+#ifdef HAVE_NSSA
+#define OSPF_SEND_PACKET_LOOP           3
+#endif /* HAVE_NSSA */
+
+#define OSPF_HELLO_REPLY_DELAY          1
+
+struct ospf_packet
+{
+  struct ospf_packet *next;
+
+  /* Pointer to data stream. */
+  struct stream *s;
+
+  /* IP destination address. */
+  struct in_addr dst;
+
+  /* OSPF packet length. */
+  u_int16_t length;
+};
+
+/* OSPF packet queue structure. */
+struct ospf_fifo
+{
+  unsigned long count;
+
+  struct ospf_packet *head;
+  struct ospf_packet *tail;
+};
+
+/* OSPF packet header structure. */
+struct ospf_header
+{
+  u_char version;                       /* OSPF Version. */
+  u_char type;                          /* Packet Type. */
+  u_int16_t length;                     /* Packet Length. */
+  struct in_addr router_id;             /* Router ID. */
+  struct in_addr area_id;               /* Area ID. */
+  u_int16_t checksum;                   /* Check Sum. */
+  u_int16_t auth_type;                  /* Authentication Type. */
+  /* Authentication Data. */
+  union
+  {
+    /* Simple Authentication. */
+    u_char auth_data [OSPF_AUTH_SIMPLE_SIZE];
+    /* Cryptographic Authentication. */
+    struct
+    {
+      u_int16_t zero;                   /* Should be 0. */
+      u_char key_id;                    /* Key ID. */
+      u_char auth_data_len;             /* Auth Data Length. */
+      u_int32_t crypt_seqnum;           /* Cryptographic Sequence Number. */
+    } crypt;
+  } u;
+};
+
+/* OSPF Hello body format. */
+struct ospf_hello
+{
+  struct in_addr network_mask;
+  u_int16_t hello_interval;
+  u_char options;
+  u_char priority;
+  u_int32_t dead_interval;
+  struct in_addr d_router;
+  struct in_addr bd_router;
+  struct in_addr neighbors[1];
+};
+
+/* OSPF Database Description body format. */
+struct ospf_db_desc
+{
+  u_int16_t mtu;
+  u_char options;
+  u_char flags;
+  u_int32_t dd_seqnum;
+};
+
+
+/* Macros. */
+#define OSPF_PACKET_MAX(oi)     ospf_packet_max (oi)
+/*
+#define OSPF_PACKET_MAX(oi)     (((oi)->ifp->mtu - ((oi)->auth_md5 ? OSPF_AUTH_MD5_SIZE : 0)) - 88)
+*/
+
+#define OSPF_OUTPUT_PNT(S)      ((S)->data + (S)->putp)
+#define OSPF_OUTPUT_LENGTH(S)   ((S)->endp)
+
+#define IS_SET_DD_MS(X)         ((X) & OSPF_DD_FLAG_MS)
+#define IS_SET_DD_M(X)          ((X) & OSPF_DD_FLAG_M)
+#define IS_SET_DD_I(X)          ((X) & OSPF_DD_FLAG_I)
+#define IS_SET_DD_ALL(X)        ((X) & OSPF_DD_FLAG_ALL)
+
+/* Prototypes. */
+void ospf_output_forward (struct stream *, int);
+struct ospf_packet *ospf_packet_new (size_t);
+void ospf_packet_free (struct ospf_packet *);
+struct ospf_fifo *ospf_fifo_new ();
+void ospf_fifo_push (struct ospf_fifo *, struct ospf_packet *);
+struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *);
+struct ospf_packet *ospf_fifo_head (struct ospf_fifo *);
+void ospf_fifo_flush (struct ospf_fifo *);
+void ospf_fifo_free (struct ospf_fifo *);
+void ospf_packet_add (struct ospf_interface *, struct ospf_packet *);
+void ospf_packet_delete (struct ospf_interface *);
+struct stream *ospf_stream_dup (struct stream *);
+struct ospf_packet *ospf_packet_dup (struct ospf_packet *);
+
+int ospf_read (struct thread *);
+void ospf_hello_send (struct ospf_interface *);
+void ospf_db_desc_send (struct ospf_neighbor *);
+void ospf_db_desc_resend (struct ospf_neighbor *);
+void ospf_ls_req_send (struct ospf_neighbor *);
+void ospf_ls_upd_send_lsa (struct ospf_neighbor *, struct ospf_lsa *, int);
+void ospf_ls_upd_send (struct ospf_neighbor *, list, int);
+void ospf_ls_ack_send (struct ospf_neighbor *, struct ospf_lsa *);
+void ospf_ls_ack_send_delayed (struct ospf_interface *);
+void ospf_ls_retransmit (struct ospf_interface *, struct ospf_lsa *);
+void ospf_ls_req_event (struct ospf_neighbor *);
+
+int ospf_ls_upd_timer (struct thread *);
+int ospf_ls_ack_timer (struct thread *);
+int ospf_poll_timer (struct thread *);
+int ospf_hello_reply_timer (struct thread *);
+void ospf_hello_send_sub (struct ospf_interface *, struct in_addr *);
+
+#endif /* _ZEBRA_OSPF_PACKET_H */
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
new file mode 100644 (file)
index 0000000..96f7531
--- /dev/null
@@ -0,0 +1,1026 @@
+/*
+ * OSPF routing table.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "linklist.h"
+#include "log.h"
+#include "if.h"
+#include "command.h"
+#include "sockunion.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+struct ospf_route *
+ospf_route_new ()
+{
+  struct ospf_route *new;
+
+  new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route));
+
+  new->ctime = time (NULL);
+  new->mtime = new->ctime;
+
+  return new;
+}
+
+void
+ospf_route_free (struct ospf_route *or)
+{
+  listnode node;
+
+  if (or->path)
+    {
+      for (node = listhead (or->path); node; nextnode (node))
+       ospf_path_free (node->data);
+
+      list_delete (or->path);
+    }
+
+  XFREE (MTYPE_OSPF_ROUTE, or);
+}
+
+struct ospf_path *
+ospf_path_new ()
+{
+  struct ospf_path *new;
+
+  new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path));
+
+  return new;
+}
+
+struct ospf_path *
+ospf_path_dup (struct ospf_path *path)
+{
+  struct ospf_path *new;
+
+  new = ospf_path_new ();
+  memcpy (new, path, sizeof (struct ospf_path));
+
+  return new;
+}
+
+void
+ospf_path_free (struct ospf_path *op)
+{
+  XFREE (MTYPE_OSPF_PATH, op);
+}
+
+void
+ospf_route_delete (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL)
+      {
+       if (or->type == OSPF_DESTINATION_NETWORK)
+         ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p,
+                                      or);
+       else if (or->type == OSPF_DESTINATION_DISCARD)
+         ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
+      }
+}
+
+void
+ospf_route_table_free (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL)
+      {
+       ospf_route_free (or);
+
+       rn->info = NULL;
+       route_unlock_node (rn);
+      }
+
+   route_table_finish (rt);
+}
+
+/* If a prefix and a nexthop match any route in the routing table,
+   then return 1, otherwise return 0. */
+int
+ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix,
+                      struct ospf_route *newor)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct ospf_path *op;
+  struct ospf_path *newop;
+  listnode n1;
+  listnode n2;
+
+  if (! rt || ! prefix)
+    return 0;
+
+   rn = route_node_lookup (rt, (struct prefix *) prefix);
+   if (! rn || ! rn->info)
+     return 0;
+   route_unlock_node (rn);
+
+   or = rn->info;
+   if (or->type == newor->type && or->cost == newor->cost)
+     {
+       if (or->type == OSPF_DESTINATION_NETWORK)
+        {
+          if (or->path->count != newor->path->count)
+            return 0;
+
+          /* Check each path. */
+          for (n1 = listhead (or->path), n2 = listhead (newor->path);
+               n1 && n2; nextnode (n1), nextnode (n2))
+            { 
+              op = getdata (n1);
+              newop = getdata (n2);
+
+              if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
+                return 0;
+            }
+          return 1;
+        }
+       else if (prefix_same (&rn->p, (struct prefix *) prefix))
+        return 1;
+     }
+  return 0;
+}
+
+/* rt: Old, cmprt: New */
+void
+ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL) 
+      if (or->path_type == OSPF_PATH_INTRA_AREA ||
+         or->path_type == OSPF_PATH_INTER_AREA)
+       {
+         if (or->type == OSPF_DESTINATION_NETWORK)
+           {
+             if (! ospf_route_match_same (cmprt, 
+                                          (struct prefix_ipv4 *) &rn->p, or))
+               ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
+           }
+         else if (or->type == OSPF_DESTINATION_DISCARD)
+           if (! ospf_route_match_same (cmprt,
+                                        (struct prefix_ipv4 *) &rn->p, or))
+             ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
+       }
+}
+
+/* Install routes to table. */
+void
+ospf_route_install (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+
+  /* rt contains new routing table, new_table contains an old one.
+     updating pointers */
+  if (ospf_top->old_table)
+    ospf_route_table_free (ospf_top->old_table);
+  ospf_top->old_table = ospf_top->new_table;
+  ospf_top->new_table = rt;
+
+  /* Delete old routes. */
+  if (ospf_top->old_table)
+    ospf_route_delete_uniq (ospf_top->old_table, rt);
+
+  /* Install new routes. */
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL)
+      {
+       if (or->type == OSPF_DESTINATION_NETWORK)
+         {
+           if (! ospf_route_match_same (ospf_top->old_table,
+                                        (struct prefix_ipv4 *)&rn->p, or))
+             ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
+         }
+       else if (or->type == OSPF_DESTINATION_DISCARD)
+         if (! ospf_route_match_same (ospf_top->old_table,
+                                      (struct prefix_ipv4 *) &rn->p, or))
+           ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p);
+      }
+}
+
+void
+ospf_intra_route_add (struct route_table *rt, struct vertex *v,
+                     struct ospf_area *area)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct prefix_ipv4 p;
+  struct ospf_path *path;
+  struct vertex_nexthop *nexthop;
+  listnode nnode;
+
+  p.family = AF_INET;
+  p.prefix = v->id;
+  if (v->type == OSPF_VERTEX_ROUTER)
+    p.prefixlen = IPV4_MAX_BITLEN;
+  else
+    {
+      struct network_lsa *lsa = (struct network_lsa *) v->lsa;
+      p.prefixlen = ip_masklen (lsa->mask);
+    }
+  apply_mask_ipv4 (&p);
+
+  rn = route_node_get (rt, (struct prefix *) &p);
+  if (rn->info)
+    {
+      zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id));
+      route_unlock_node (rn);
+      return;
+    }
+
+  or = ospf_route_new ();
+
+  if (v->type == OSPF_VERTEX_NETWORK)
+    {
+      or->type = OSPF_DESTINATION_NETWORK;
+      or->path = list_new ();
+
+      for (nnode = listhead (v->nexthop); nnode; nextnode (nnode))
+       {
+         nexthop = getdata (nnode);
+         path = ospf_path_new ();
+         path->nexthop = nexthop->router;
+         listnode_add (or->path, path);
+       }
+    }
+  else
+    or->type = OSPF_DESTINATION_ROUTER;
+
+  or->id = v->id;
+  or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+  or->u.std.external_routing= area->external_routing;
+#endif /* HAVE_NSSA */
+  or->path_type = OSPF_PATH_INTRA_AREA;
+  or->cost = v->distance;
+
+  rn->info = or;
+}
+
+/* RFC2328 16.1. (4). For "router". */
+void
+ospf_intra_add_router (struct route_table *rt, struct vertex *v,
+                      struct ospf_area *area)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct prefix_ipv4 p;
+  struct router_lsa *lsa;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_router: Start");
+
+  lsa = (struct router_lsa *) v->lsa;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_router: LS ID: %s",
+              inet_ntoa (lsa->header.id));
+
+  ospf_vl_up_check (area, lsa->header.id, v);
+
+  if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT))
+    area->shortcut_capability = 0;
+
+  /* If the newly added vertex is an area border router or AS boundary
+     router, a routing table entry is added whose destination type is
+     "router". */
+  if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa))
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_intra_add_router: "
+                  "this router is neither ASBR nor ABR, skipping it");
+      return;
+    }
+
+  /* Update ABR and ASBR count in this area. */
+  if (IS_ROUTER_LSA_BORDER (lsa))
+    area->abr_count++;
+  if (IS_ROUTER_LSA_EXTERNAL (lsa))
+    area->asbr_count++;
+
+  /* The Options field found in the associated router-LSA is copied
+     into the routing table entry's Optional capabilities field. Call
+     the newly added vertex Router X. */
+  or = ospf_route_new ();
+
+  or->id = v->id;
+  or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+  or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+  or->path_type = OSPF_PATH_INTRA_AREA;
+  or->cost = v->distance;
+  or->type = OSPF_DESTINATION_ROUTER;
+  or->u.std.origin = (struct lsa_header *) lsa;
+  or->u.std.options = lsa->header.options;
+  or->u.std.flags = lsa->flags;
+
+  /* If Router X is the endpoint of one of the calculating router's
+     virtual links, and the virtual link uses Area A as Transit area:
+     the virtual link is declared up, the IP address of the virtual
+     interface is set to the IP address of the outgoing interface
+     calculated above for Router X, and the virtual neighbor's IP
+     address is set to Router X's interface address (contained in
+     Router X's router-LSA) that points back to the root of the
+     shortest- path tree; equivalently, this is the interface that
+     points back to Router X's parent vertex on the shortest-path tree
+     (similar to the calculation in Section 16.1.1). */
+
+  p.family = AF_INET;
+  p.prefix = v->id;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_router: talking about %s/%d",
+              inet_ntoa (p.prefix), p.prefixlen);
+
+  rn = route_node_get (rt, (struct prefix *) &p);
+
+  /* Note that we keep all routes to ABRs and ASBRs, not only the best */
+  if (rn->info == NULL)
+    rn->info = list_new ();
+  else
+    route_unlock_node (rn);
+
+  ospf_route_copy_nexthops_from_vertex (or, v);
+
+  listnode_add (rn->info, or);
+
+  zlog_info ("ospf_intra_add_router: Start");
+}
+
+/* RFC2328 16.1. (4).  For transit network. */
+void
+ospf_intra_add_transit (struct route_table *rt, struct vertex *v,
+                       struct ospf_area *area)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct prefix_ipv4 p;
+  struct network_lsa *lsa;
+
+  lsa = (struct network_lsa*) v->lsa;
+
+  /* If the newly added vertex is a transit network, the routing table
+     entry for the network is located.  The entry's Destination ID is
+     the IP network number, which can be obtained by masking the
+     Vertex ID (Link State ID) with its associated subnet mask (found
+     in the body of the associated network-LSA). */
+  p.family = AF_INET;
+  p.prefix = v->id;
+  p.prefixlen = ip_masklen (lsa->mask);
+  apply_mask_ipv4 (&p);
+
+  rn = route_node_get (rt, (struct prefix *) &p);
+
+  /* If the routing table entry already exists (i.e., there is already
+     an intra-area route to the destination installed in the routing
+     table), multiple vertices have mapped to the same IP network.
+     For example, this can occur when a new Designated Router is being
+     established.  In this case, the current routing table entry
+     should be overwritten if and only if the newly found path is just
+     as short and the current routing table entry's Link State Origin
+     has a smaller Link State ID than the newly added vertex' LSA. */
+  if (rn->info)
+    {
+      struct ospf_route *cur_or;
+
+      route_unlock_node (rn);
+      cur_or = rn->info;
+
+      if (v->distance > cur_or->cost ||
+          IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0)
+       return;
+      
+      ospf_route_free (rn->info);
+    }
+
+  or = ospf_route_new ();
+
+  or->id = v->id;
+  or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+  or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+  or->path_type = OSPF_PATH_INTRA_AREA;
+  or->cost = v->distance;
+  or->type = OSPF_DESTINATION_NETWORK;
+  or->u.std.origin = (struct lsa_header *) lsa;
+
+  ospf_route_copy_nexthops_from_vertex (or, v);
+  
+  rn->info = or;
+}
+
+/* RFC2328 16.1. second stage. */
+void
+ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link,
+                    struct vertex *v, struct ospf_area *area)
+{
+  u_int32_t cost;
+  struct route_node *rn;
+  struct ospf_route *or;
+  struct prefix_ipv4 p;
+  struct router_lsa *lsa;
+  struct ospf_interface *oi;
+  struct ospf_path *path;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_stub(): Start");
+
+  lsa = (struct router_lsa *) v->lsa;
+
+  p.family = AF_INET;
+  p.prefix = link->link_id;
+  p.prefixlen = ip_masklen (link->link_data);
+  apply_mask_ipv4 (&p);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_stub(): processing route to %s/%d",  
+              inet_ntoa (p.prefix), p.prefixlen);
+
+  /* (1) Calculate the distance D of stub network from the root.  D is
+     equal to the distance from the root to the router vertex
+     (calculated in stage 1), plus the stub network link's advertised
+     cost. */
+  cost = v->distance + ntohs (link->m[0].metric);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", 
+              v->distance, ntohs(link->m[0].metric), cost);
+
+  rn = route_node_get (rt, (struct prefix *) &p);
+
+  /* Lookup current routing table. */
+  if (rn->info)
+    {
+      struct ospf_route *cur_or;
+
+      route_unlock_node (rn);
+
+      cur_or = rn->info;
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_intra_add_stub(): "
+                  "another route to the same prefix found");
+
+      /* Compare this distance to the current best cost to the stub
+        network.  This is done by looking up the stub network's
+        current routing table entry.  If the calculated distance D is
+        larger, go on to examine the next stub network link in the
+        LSA. */
+      if (cost > cur_or->cost)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_intra_add_stub(): old route is better, exit");
+         return;
+       }
+
+      /* (2) If this step is reached, the stub network's routing table
+        entry must be updated.  Calculate the set of next hops that
+        would result from using the stub network link.  This
+        calculation is shown in Section 16.1.1; input to this
+        calculation is the destination (the stub network) and the
+        parent vertex (the router vertex). If the distance D is the
+        same as the current routing table cost, simply add this set
+        of next hops to the routing table entry's list of next hops.
+        In this case, the routing table already has a Link State
+        Origin.  If this Link State Origin is a router-LSA whose Link
+        State ID is smaller than V's Router ID, reset the Link State
+        Origin to V's router-LSA. */
+
+      if (cost == cur_or->cost)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_intra_add_stub(): routes are equal, merge");
+
+         ospf_route_copy_nexthops_from_vertex (cur_or, v);
+
+         if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0)
+           cur_or->u.std.origin = (struct lsa_header *) lsa;
+         return;
+       }
+
+      /* Otherwise D is smaller than the routing table cost.
+        Overwrite the current routing table entry by setting the
+        routing table entry's cost to D, and by setting the entry's
+        list of next hops to the newly calculated set.  Set the
+        routing table entry's Link State Origin to V's router-LSA.
+        Then go on to examine the next stub network link. */
+
+      if (cost < cur_or->cost)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_intra_add_stub(): new route is better, set it");
+
+         cur_or->cost = cost;
+
+         list_delete (cur_or->path);
+         cur_or->path = NULL;
+
+         ospf_route_copy_nexthops_from_vertex (cur_or, v);
+
+         cur_or->u.std.origin = (struct lsa_header *) lsa;
+         return;
+       }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_intra_add_stub(): installing new route");
+
+  or = ospf_route_new ();
+
+  or->id = v->id;
+  or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+  or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+  or->path_type = OSPF_PATH_INTRA_AREA;
+  or->cost = cost;
+  or->type = OSPF_DESTINATION_NETWORK;
+  or->u.std.origin = (struct lsa_header *) lsa;
+  or->path = list_new ();
+
+  /* Nexthop is depend on connection type. */
+  if (v != area->spf)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_intra_add_stub(): this network is on remote router");
+      ospf_route_copy_nexthops_from_vertex (or, v);
+    }
+  else
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_intra_add_stub(): this network is on this router");
+
+      if ((oi = ospf_if_lookup_by_prefix (&p)))
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_intra_add_stub(): the interface is %s",
+                      IF_NAME (oi));
+
+         path = ospf_path_new ();
+         path->nexthop.s_addr = 0;
+         path->oi = oi;
+         listnode_add (or->path, path);
+       }
+      else
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_intra_add_stub(): where's the interface ?");
+       }
+    }
+
+  rn->info = or;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info("ospf_intra_add_stub(): Stop");
+}
+
+char *ospf_path_type_str[] =
+{
+  "unknown-type",
+  "intra-area",
+  "inter-area",
+  "type1-external",
+  "type2-external"
+};
+
+void
+ospf_route_table_dump (struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+  listnode pnode;
+  struct ospf_path *path;
+
+#if 0
+  zlog_info ("Type   Dest   Area   Path         Type    Cost   Next     Adv.");
+  zlog_info ("                                 Hop(s)   Router(s)");
+#endif /* 0 */
+
+  zlog_info ("========== OSPF routing table ==========");
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL)
+      {
+        if (or->type == OSPF_DESTINATION_NETWORK)
+         {
+           zlog_info ("N %s/%d\t%s\t%s\t%d", 
+                      inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
+                      rn->p.prefixlen,
+                      inet_ntop (AF_INET, &or->u.std.area_id, buf2,
+                                 BUFSIZ),
+                      ospf_path_type_str[or->path_type],
+                      or->cost);
+           for (pnode = listhead (or->path); pnode; nextnode (pnode))
+             {
+               path = getdata (pnode);
+               zlog_info ("  -> %s", inet_ntoa (path->nexthop));
+             }
+         }
+        else
+         zlog_info ("R %s\t%s\t%s\t%d", 
+                    inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
+                    inet_ntop (AF_INET, &or->u.std.area_id, buf2,
+                               BUFSIZ),
+                    ospf_path_type_str[or->path_type],
+                    or->cost);
+      }
+  zlog_info ("========================================");
+}
+
+void
+ospf_terminate ()
+{
+  if (ospf_top)
+    {
+      if (ospf_top->new_table)
+       ospf_route_delete (ospf_top->new_table);
+      if (ospf_top->old_external_route)
+       ospf_route_delete (ospf_top->old_external_route);
+    }
+}
+
+/* This is 16.4.1 implementation.
+   o Intra-area paths using non-backbone areas are always the most preferred.
+   o The other paths, intra-area backbone paths and inter-area paths,
+     are of equal preference. */
+int
+ospf_asbr_route_cmp (struct ospf_route *r1, struct ospf_route *r2)
+{
+  u_char r1_type, r2_type;
+
+  r1_type = r1->path_type;
+  r2_type = r2->path_type;
+
+  /* If RFC1583Compat flag is on -- all paths are equal. */
+  if (CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+    return 0;
+
+  /* r1/r2 itself is backbone, and it's Inter-area path. */
+  if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id))
+    r1_type = OSPF_PATH_INTER_AREA;
+  if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id))
+    r2_type = OSPF_PATH_INTER_AREA;
+
+  return (r1_type - r2_type);
+}
+
+/* Compare two routes.
+ ret <  0 -- r1 is better.
+ ret == 0 -- r1 and r2 are the same.
+ ret >  0 -- r2 is better. */
+int
+ospf_route_cmp (struct ospf_route *r1, struct ospf_route *r2)
+{
+  int ret = 0;
+
+  /* Path types of r1 and r2 are not the same. */
+  if ((ret = (r1->path_type - r2->path_type)))
+    return ret;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Route[Compare]: Path types are the same.");
+  /* Path types are the same, compare any cost. */
+  switch (r1->path_type)
+    {
+    case OSPF_PATH_INTRA_AREA:
+    case OSPF_PATH_INTER_AREA:
+      break;
+    case OSPF_PATH_TYPE1_EXTERNAL:
+      if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+       {
+         ret = ospf_asbr_route_cmp (r1->u.ext.asbr, r2->u.ext.asbr);
+         if (ret != 0)
+           return ret;
+       }
+      break;
+    case OSPF_PATH_TYPE2_EXTERNAL:
+      if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost)))
+       return ret;
+
+      if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+       {
+         ret = ospf_asbr_route_cmp (r1->u.ext.asbr, r2->u.ext.asbr);
+         if (ret != 0)
+           return ret;
+       }
+      break;
+    }      
+
+  /* Anyway, compare the costs. */
+  return (r1->cost - r2->cost);
+}
+
+int
+ospf_path_exist (struct list *plist, struct in_addr nexthop,
+                struct ospf_interface *oi)
+{
+  listnode node;
+  struct ospf_path *path;
+
+  for (node = listhead (plist); node; nextnode (node))
+    {
+      path = node->data;
+
+      if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) && path->oi == oi)
+       return 1;
+    }
+  return 0;
+}
+
+void
+ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
+                                     struct vertex *v)
+{
+  listnode nnode;
+  struct ospf_path *path;
+  struct vertex_nexthop *nexthop;
+
+  if (to->path == NULL)
+    to->path = list_new ();
+
+  for (nnode = listhead (v->nexthop); nnode; nextnode (nnode))
+    {
+      nexthop = getdata (nnode);
+
+      if (nexthop->oi != NULL) 
+       {
+         if (! ospf_path_exist (to->path, nexthop->router, nexthop->oi))
+           {
+             path = ospf_path_new ();
+             path->nexthop = nexthop->router;
+             path->oi = nexthop->oi;
+             listnode_add (to->path, path);
+           }
+       }
+    }
+}
+
+struct ospf_path *
+ospf_path_lookup (list plist, struct ospf_path *path)
+{
+  listnode node;
+
+  for (node = listhead (plist); node; nextnode (node))
+    {
+      struct ospf_path *op = node->data;
+
+      if (IPV4_ADDR_SAME (&op->nexthop, &path->nexthop) &&
+         IPV4_ADDR_SAME (&op->adv_router, &path->adv_router))
+       return op;
+    }
+
+  return NULL;
+}
+
+void
+ospf_route_copy_nexthops (struct ospf_route *to, list from)
+{
+  listnode node;
+
+  if (to->path == NULL)
+    to->path = list_new ();
+
+  for (node = listhead (from); node; nextnode (node))
+    /* The same routes are just discarded. */
+    if (!ospf_path_lookup (to->path, node->data))
+      listnode_add (to->path, ospf_path_dup (node->data));
+}
+
+void
+ospf_route_subst_nexthops (struct ospf_route *to, list from)
+{
+  listnode node;
+  struct ospf_path *op;
+
+  for (node = listhead (to->path); node; nextnode (node))
+    if ((op = getdata (node)) != NULL)
+      {
+       ospf_path_free (op);
+       node->data = NULL;
+      }
+
+  list_delete_all_node (to->path);
+  ospf_route_copy_nexthops (to, from);
+}
+
+void
+ospf_route_subst (struct route_node *rn, struct ospf_route *new_or,
+                 struct ospf_route *over)
+{
+  route_lock_node (rn);
+  ospf_route_free (rn->info);
+
+  ospf_route_copy_nexthops (new_or, over->path);
+  rn->info = new_or;
+  route_unlock_node (rn);
+}
+
+void
+ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p,
+               struct ospf_route *new_or, struct ospf_route *over)
+{
+  struct route_node *rn;
+
+  rn = route_node_get (rt, (struct prefix *) p);
+
+  ospf_route_copy_nexthops (new_or, over->path);
+
+  if (rn->info)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_route_add(): something's wrong !");
+      route_unlock_node (rn);
+      return;
+    }
+
+  rn->info = new_or;
+}
+
+void
+ospf_prune_unreachable_networks (struct route_table *rt)
+{
+  struct route_node *rn, *next;
+  struct ospf_route *or;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Pruning unreachable networks");
+
+  for (rn = route_top (rt); rn; rn = next)
+    {
+      next = route_next (rn);
+      if (rn->info != NULL)
+       {
+         or = rn->info;
+         if (listcount (or->path) == 0)
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("Pruning route to %s/%d",
+                          inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+
+             ospf_route_free (or);
+             rn->info = NULL;
+             route_unlock_node (rn);
+           }
+       }
+    }
+}
+
+void
+ospf_prune_unreachable_routers (struct route_table *rtrs)
+{
+  struct route_node *rn, *next;
+  struct ospf_route *or;
+  listnode node, nnext;
+  list paths;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Pruning unreachable routers");
+
+  for (rn = route_top (rtrs); rn; rn = next)
+    {
+      next = route_next (rn);
+      if ((paths = rn->info) == NULL)
+       continue;
+
+      for (node = listhead (paths); node; node = nnext) 
+       {
+         nnext = node->next;
+
+         or = getdata (node);
+
+         if (listcount (or->path) == 0)
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               {
+                 zlog_info ("Pruning route to rtr %s",
+                            inet_ntoa (rn->p.u.prefix4));
+                 zlog_info ("               via area %s",
+                            inet_ntoa (or->u.std.area_id));
+               }
+
+             listnode_delete (paths, or);
+             ospf_route_free (or);
+           }
+       }
+
+      if (listcount (paths) == 0)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4));
+
+         list_delete (paths);
+         rn->info = NULL;
+         route_unlock_node (rn);
+       }
+    }
+}
+
+int
+ospf_add_discard_route (struct route_table *rt, struct ospf_area *area,
+                       struct prefix_ipv4 *p)
+{
+  struct route_node *rn;
+  struct ospf_route *or, *new_or;
+
+  rn = route_node_get (rt, (struct prefix *) p);
+
+  if (rn == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_add_discard_route(): router installation error");
+      return 0;
+    }
+
+  if (rn->info) /* If the route to the same destination is found */
+    {
+      route_unlock_node (rn);
+
+      or = rn->info;
+
+      if (or->path_type == OSPF_PATH_INTRA_AREA)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_add_discard_route(): "
+                      "an intra-area route exists");
+         return 0;
+       }
+
+      if (or->type == OSPF_DESTINATION_DISCARD)
+       {
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info ("ospf_add_discard_route(): "
+                      "discard entry already installed");
+         return 0;
+       }
+
+      ospf_route_free (rn->info);
+  }
+
+  new_or = ospf_route_new ();
+  new_or->type = OSPF_DESTINATION_DISCARD;
+  new_or->id.s_addr = 0;
+  new_or->cost = 0;
+  new_or->u.std.area_id = area->area_id;
+#ifdef HAVE_NSSA
+  new_or->u.std.external_routing = area->external_routing;
+#endif /* HAVE_NSSA */
+  new_or->path_type = OSPF_PATH_INTER_AREA;
+  rn->info = new_or;
+
+  ospf_zebra_add_discard (p);
+
+  return 1;
+}
+
+void
+ospf_delete_discard_route (struct prefix_ipv4 *p)
+{
+  ospf_zebra_delete_discard(p);
+}
+
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
new file mode 100644 (file)
index 0000000..81f59c4
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * OSPF routing table.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_ROUTE_H
+#define _ZEBRA_OSPF_ROUTE_H
+
+#define OSPF_DESTINATION_ROUTER                1
+#define OSPF_DESTINATION_NETWORK       2
+#define OSPF_DESTINATION_DISCARD       3
+
+#define OSPF_PATH_MIN                  0
+#define OSPF_PATH_INTRA_AREA           1
+#define OSPF_PATH_INTER_AREA           2
+#define OSPF_PATH_TYPE1_EXTERNAL       3
+#define OSPF_PATH_TYPE2_EXTERNAL       4
+#define OSPF_PATH_MAX                  5
+
+/* OSPF Path. */
+struct ospf_path
+{
+  struct in_addr nexthop;
+  struct in_addr adv_router;
+  struct ospf_interface *oi;
+};
+
+/* Below is the structure linked to every
+   route node. Note that for Network routing
+   entries a single ospf_route is kept, while
+   for ABRs and ASBRs (Router routing entries),
+   we link an instance of ospf_router_route
+   where a list of paths is maintained, so
+
+   nr->info is a (struct ospf_route *) for OSPF_DESTINATION_NETWORK
+   but
+   nr->info is a (struct ospf_router_route *) for OSPF_DESTINATION_ROUTER
+*/
+
+struct route_standard
+{
+  /* Link Sate Origin. */
+  struct lsa_header *origin;
+
+  /* Associated Area. */
+  struct in_addr area_id;      /* The area the route belongs to */
+
+#ifdef HAVE_NSSA
+  /*  Area Type */
+  int external_routing;
+#endif /* HAVE_NSSA */
+
+  /* Optional Capability. */
+  u_char options;              /* Get from LSA header. */
+
+  /*  */
+  u_char flags;                /* From router-LSA */
+};
+
+struct route_external
+{
+  /* Link State Origin. */
+  struct ospf_lsa *origin;
+
+  /* Link State Cost Type2. */
+  u_int32_t type2_cost;
+
+  /* Tag value. */
+  u_int32_t tag;
+
+  /* ASBR route. */
+  struct ospf_route *asbr;
+};
+
+struct ospf_route
+{
+  /* Create time. */
+  time_t ctime;
+
+  /* Modified time. */
+  time_t mtime;
+
+  /* Destination Type. */
+  u_char type;
+
+  /* Destination ID. */                /* i.e. Link State ID. */
+  struct in_addr id;
+
+  /* Address Mask. */
+  struct in_addr mask;         /* Only valid for networks. */
+
+  /* Path Type. */
+  u_char path_type;
+
+  /* List of Paths. */
+  list path;
+
+  /* Link State Cost. */
+  u_int32_t cost;              /* i.e. metric. */
+
+  /* Route specific info. */
+  union
+  {
+    struct route_standard std;
+    struct route_external ext;
+  } u;
+};
+
+struct ospf_path *ospf_path_new ();
+void ospf_path_free (struct ospf_path *op);
+struct ospf_path *ospf_path_lookup (list, struct ospf_path *);
+struct ospf_route *ospf_route_new ();
+void ospf_route_free (struct ospf_route *or);
+void ospf_route_delete (struct route_table *rt);
+void ospf_route_table_free (struct route_table *rt);
+
+void ospf_route_install (struct route_table *);
+void ospf_route_table_dump (struct route_table *);
+
+void ospf_intra_add_router (struct route_table *, struct vertex *,
+                           struct ospf_area *);
+
+void ospf_intra_add_transit (struct route_table *, struct vertex *,
+                            struct ospf_area *);
+
+void ospf_intra_add_stub (struct route_table *, struct router_lsa_link *,
+                         struct vertex *, struct ospf_area *);
+
+int ospf_route_cmp (struct ospf_route *, struct ospf_route *);
+void ospf_route_copy_nexthops (struct ospf_route *, list);
+void ospf_route_copy_nexthops_from_vertex (struct ospf_route *,
+                                          struct vertex * );
+
+void ospf_route_subst (struct route_node *, struct ospf_route *,
+                      struct ospf_route *);
+void ospf_route_add (struct route_table *, struct prefix_ipv4 *,
+                    struct ospf_route *, struct ospf_route *);
+
+void ospf_route_subst_nexthops (struct ospf_route *, list);
+void ospf_prune_unreachable_networks (struct route_table *);
+void ospf_prune_unreachable_routers (struct route_table *);
+int ospf_add_discard_route (struct route_table *, struct ospf_area *, 
+                           struct prefix_ipv4 *);
+void ospf_delete_discard_route (struct prefix_ipv4 *);
+int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *,
+                          struct ospf_route *);
+
+#endif /* _ZEBRA_OSPF_ROUTE_H */
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
new file mode 100644 (file)
index 0000000..a2b257f
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+ * Route map function of ospfd.
+ * Copyright (C) 2000 IP Infusion Inc.
+ *
+ * Written by Toshiaki Takada.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "routemap.h"
+#include "command.h"
+#include "log.h"
+#include "plist.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+
+/* Hook function for updating route_map assignment. */
+void
+ospf_route_map_update (char *name)
+{
+  int type;
+
+  /* If OSPF instatnce does not exist, return right now. */
+  if (!ospf_top)
+    return;
+
+  /* Update route-map */
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    {
+      if (ROUTEMAP_NAME (type) && strcmp (ROUTEMAP_NAME (type), name) == 0)
+       {
+         /* Keep old route-map. */
+         struct route_map *old = ROUTEMAP (type);
+
+         /* Update route-map. */
+         ROUTEMAP (type) = route_map_lookup_by_name (ROUTEMAP_NAME (type));
+
+         /* No update for this distribute type. */
+         if (old == NULL && ROUTEMAP (type) == NULL)
+           continue;
+
+         ospf_distribute_list_update (type);
+       }
+    }
+}
+
+void
+ospf_route_map_event (route_map_event_t event, char *name)
+{
+  int type;
+
+  /* If OSPF instatnce does not exist, return right now. */
+  if (!ospf_top)
+    return;
+
+  /* Update route-map. */
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    {
+      if (ROUTEMAP_NAME (type) &&  ROUTEMAP (type) &&
+          !strcmp (ROUTEMAP_NAME (type), name))
+        {
+          ospf_distribute_list_update (type);
+        }
+    }
+}
+
+/* Delete rip route map rule. */
+int
+ospf_route_match_delete (struct vty *vty, struct route_map_index *index,
+                        char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_route_match_add (struct vty *vty, struct route_map_index *index,
+                     char *command, char *arg)
+{                                                                              
+  int ret;
+
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_route_set_add (struct vty *vty, struct route_map_index *index,
+                   char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+ospf_route_set_delete (struct vty *vty, struct route_map_index *index,
+                      char *command, char *arg)
+{                                              
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+          break;
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* `match ip netxthop ' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_nexthop (void *rule, struct prefix *prefix,
+                       route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  struct external_info *ei = object;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_OSPF)
+    {
+      p.family = AF_INET;
+      p.prefix = ei->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+        return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, &p) == FILTER_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement. `arg' should be
+   access-list name. */
+void *
+route_match_ip_nexthop_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_nexthop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_ip_nexthop_cmd =
+{
+  "ip next-hop",
+  route_match_ip_nexthop,
+  route_match_ip_nexthop_compile,
+  route_match_ip_nexthop_free
+};
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+  struct external_info *ei = object;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_OSPF)
+    {
+      p.family = AF_INET;
+      p.prefix = ei->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_next_hop_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+  "ip next-hop prefix-list",
+  route_match_ip_next_hop_prefix_list,
+  route_match_ip_next_hop_prefix_list_compile,
+  route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match ip address IP_ACCESS_LIST' */
+/* Match function should return 1 if match is success else return
+   zero. */
+route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix,
+                        route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  /* struct prefix_ipv4 match; */
+
+  if (type == RMAP_OSPF)
+    {
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+        return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, prefix) == FILTER_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement.  `arg' should be
+   access-list name. */
+void *
+route_match_ip_address_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_address_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+  "ip address",
+  route_match_ip_address,
+  route_match_ip_address_compile,
+  route_match_ip_address_free
+};
+
+/* `match ip address prefix-list PREFIX_LIST' */
+route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+
+  if (type == RMAP_OSPF)
+    {
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_address_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+  "ip address prefix-list",
+  route_match_ip_address_prefix_list,
+  route_match_ip_address_prefix_list_compile,
+  route_match_ip_address_prefix_list_free
+};
+
+/* `match interface IFNAME' */
+/* Match function should return 1 if match is success else return
+   zero. */
+route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+                      route_map_object_t type, void *object)
+{
+  struct interface *ifp;
+  struct external_info *ei;
+
+  if (type == RMAP_OSPF)
+    {
+      ei = object;
+      ifp = if_lookup_by_name ((char *)rule);
+
+      if (ifp == NULL || ifp->ifindex != ei->ifindex)
+       return RMAP_NOMATCH;
+
+      return RMAP_MATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `interface' match statement.  `arg' should be
+   interface name. */
+void *
+route_match_interface_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `interface' value. */
+void
+route_match_interface_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+  "interface",
+  route_match_interface,
+  route_match_interface_compile,
+  route_match_interface_free
+};
+
+/* `set metric METRIC' */
+/* Set metric to attribute. */
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix,
+                  route_map_object_t type, void *object)
+{
+  u_int32_t *metric;
+  struct external_info *ei;
+
+  if (type == RMAP_OSPF)
+    {
+      /* Fetch routemap's rule information. */
+      metric = rule;
+      ei = object;
+
+      /* Set metric out value. */
+      ei->route_map_set.metric = *metric;
+    }
+  return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+void *
+route_set_metric_compile (char *arg)
+{
+  u_int32_t *metric;
+
+  metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *metric = atoi (arg);
+
+  if (*metric >= 0)
+    return metric;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+  return NULL;
+}
+
+/* Free route map's compiled `set metric' value. */
+void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_cmd =
+{
+  "metric",
+  route_set_metric,
+  route_set_metric_compile,
+  route_set_metric_free,
+};
+
+/* `set metric-type TYPE' */
+/* Set metric-type to attribute. */
+route_map_result_t
+route_set_metric_type (void *rule, struct prefix *prefix,
+                      route_map_object_t type, void *object)
+{
+  u_int32_t *metric_type;
+  struct external_info *ei;
+
+  if (type == RMAP_OSPF)
+    {
+      /* Fetch routemap's rule information. */
+      metric_type = rule;
+      ei = object;
+
+      /* Set metric out value. */
+      ei->route_map_set.metric_type = *metric_type;
+    }
+  return RMAP_OKAY;
+}
+
+/* set metric-type compilation. */
+void *
+route_set_metric_type_compile (char *arg)
+{
+  u_int32_t *metric_type;
+
+  metric_type = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  if (strcmp (arg, "type-1") == 0)
+    *metric_type = EXTERNAL_METRIC_TYPE_1;
+  else if (strcmp (arg, "type-2") == 0)
+    *metric_type = EXTERNAL_METRIC_TYPE_2;
+
+  if (*metric_type == EXTERNAL_METRIC_TYPE_1 ||
+      *metric_type == EXTERNAL_METRIC_TYPE_2)
+    return metric_type;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric_type);
+  return NULL;
+}
+
+/* Free route map's compiled `set metric-type' value. */
+void
+route_set_metric_type_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_type_cmd =
+{
+  "metric-type",
+  route_set_metric_type,
+  route_set_metric_type_compile,
+  route_set_metric_type_free,
+};
+
+DEFUN (match_ip_nexthop,
+       match_ip_nexthop_cmd,
+       "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP access-list name\n")
+{
+  return ospf_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_nexthop,
+       no_match_ip_nexthop_cmd,
+       "no match ip next-hop",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n")
+{
+  if (argc == 0)
+    return ospf_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return ospf_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_nexthop,
+       no_match_ip_nexthop_val_cmd,
+       "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+       match_ip_next_hop_prefix_list_cmd,
+       "match ip next-hop prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return ospf_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+                              argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_cmd,
+       "no match ip next-hop prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list",
+                                   NULL);
+  return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list",
+                                 argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_val_cmd,
+       "no match ip next-hop prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_ip_address,
+       match_ip_address_cmd,
+       "match ip address (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP access-list name\n")
+{
+  return ospf_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address,
+       no_match_ip_address_cmd,
+       "no match ip address",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n")
+{
+  if (argc == 0)
+    return ospf_route_match_delete (vty, vty->index, "ip address", NULL);
+
+  return ospf_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address,
+       no_match_ip_address_val_cmd,
+       "no match ip address (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP access-list name\n")
+
+DEFUN (match_ip_address_prefix_list,
+       match_ip_address_prefix_list_cmd,
+       "match ip address prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return ospf_route_match_add (vty, vty->index, "ip address prefix-list",
+                              argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_cmd,
+       "no match ip address prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return ospf_route_match_delete (vty, vty->index, "ip address prefix-list",
+                                   NULL);
+  return ospf_route_match_delete (vty, vty->index, "ip address prefix-list",
+                                 argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_val_cmd,
+       "no match ip address prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_interface,
+       match_interface_cmd,
+       "match interface WORD",
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+{
+  return ospf_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+       no_match_interface_cmd,
+       "no match interface",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n")
+{
+  if (argc == 0)
+    return ospf_route_match_delete (vty, vty->index, "interface", NULL);
+
+  return ospf_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+       no_match_interface_val_cmd,
+       "no match interface WORD",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+{
+  return ospf_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n")
+{
+  if (argc == 0)
+    return ospf_route_set_delete (vty, vty->index, "metric", NULL);
+
+  return ospf_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+       no_set_metric_val_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+
+DEFUN (set_metric_type,
+       set_metric_type_cmd,
+       "set metric-type (type-1|type-2)",
+       SET_STR
+       "Type of metric for destination routing protocol\n"
+       "OSPF external type 1 metric\n"
+       "OSPF external type 2 metric\n")
+{
+  if (strcmp (argv[0], "1") == 0)
+    return ospf_route_set_add (vty, vty->index, "metric-type", "type-1");
+  if (strcmp (argv[0], "2") == 0)
+    return ospf_route_set_add (vty, vty->index, "metric-type", "type-2");
+
+  return ospf_route_set_add (vty, vty->index, "metric-type", argv[0]);
+}
+
+DEFUN (no_set_metric_type,
+       no_set_metric_type_cmd,
+       "no set metric-type",
+       NO_STR
+       SET_STR
+       "Type of metric for destination routing protocol\n")
+{
+  if (argc == 0)
+    return ospf_route_set_delete (vty, vty->index, "metric-type", NULL);
+
+  return ospf_route_set_delete (vty, vty->index, "metric-type", argv[0]);
+}
+
+ALIAS (no_set_metric_type,
+       no_set_metric_type_val_cmd,
+       "no set metric-type (type-1|type-2)",
+       NO_STR
+       SET_STR
+       "Type of metric for destination routing protocol\n"
+       "OSPF external type 1 metric\n"
+       "OSPF external type 2 metric\n")
+
+/* Route-map init */
+void
+ospf_route_map_init (void)
+{
+  route_map_init ();
+  route_map_init_vty ();
+
+  route_map_add_hook (ospf_route_map_update);
+  route_map_delete_hook (ospf_route_map_update);
+  route_map_event_hook (ospf_route_map_event);
+  
+  route_map_install_match (&route_match_ip_nexthop_cmd);
+  route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+  route_map_install_match (&route_match_ip_address_cmd);
+  route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+  route_map_install_match (&route_match_interface_cmd);
+
+  route_map_install_set (&route_set_metric_cmd);
+  route_map_install_set (&route_set_metric_type_cmd);
+
+  install_element (RMAP_NODE, &match_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_nexthop_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+  install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_val_cmd);
+
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_val_cmd);
+  install_element (RMAP_NODE, &set_metric_type_cmd);
+  install_element (RMAP_NODE, &no_set_metric_type_cmd);
+  install_element (RMAP_NODE, &no_set_metric_type_val_cmd);
+}
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
new file mode 100644 (file)
index 0000000..6187977
--- /dev/null
@@ -0,0 +1,2443 @@
+/* OSPFv2 SNMP support
+ * Copyright (C) 2000 IP Infusion Inc.
+ *
+ * Written by 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.  
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "memory.h"
+#include "smux.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+\f
+/* OSPF2-MIB. */
+#define OSPF2MIB 1,3,6,1,2,1,14
+
+/* Zebra enterprise OSPF MIB.  This variable is used for register
+   OSPF MIB to SNMP agent under SMUX protocol.  */
+#define OSPFDOID 1,3,6,1,4,1,3317,1,2,5
+
+/* OSPF MIB General Group values. */
+#define OSPFROUTERID                     1
+#define OSPFADMINSTAT                    2
+#define OSPFVERSIONNUMBER                3
+#define OSPFAREABDRRTRSTATUS             4
+#define OSPFASBDRRTRSTATUS               5
+#define OSPFEXTERNLSACOUNT               6
+#define OSPFEXTERNLSACKSUMSUM            7
+#define OSPFTOSSUPPORT                   8
+#define OSPFORIGINATENEWLSAS             9
+#define OSPFRXNEWLSAS                    10
+#define OSPFEXTLSDBLIMIT                 11
+#define OSPFMULTICASTEXTENSIONS          12
+#define OSPFEXITOVERFLOWINTERVAL         13
+#define OSPFDEMANDEXTENSIONS             14
+
+/* OSPF MIB ospfAreaTable. */
+#define OSPFAREAID                       1
+#define OSPFAUTHTYPE                     2
+#define OSPFIMPORTASEXTERN               3
+#define OSPFSPFRUNS                      4
+#define OSPFAREABDRRTRCOUNT              5
+#define OSPFASBDRRTRCOUNT                6
+#define OSPFAREALSACOUNT                 7
+#define OSPFAREALSACKSUMSUM              8
+#define OSPFAREASUMMARY                  9
+#define OSPFAREASTATUS                   10
+
+/* OSPF MIB ospfStubAreaTable. */
+#define OSPFSTUBAREAID                   1
+#define OSPFSTUBTOS                      2
+#define OSPFSTUBMETRIC                   3
+#define OSPFSTUBSTATUS                   4
+#define OSPFSTUBMETRICTYPE               5
+
+/* OSPF MIB ospfLsdbTable. */
+#define OSPFLSDBAREAID                   1
+#define OSPFLSDBTYPE                     2
+#define OSPFLSDBLSID                     3
+#define OSPFLSDBROUTERID                 4
+#define OSPFLSDBSEQUENCE                 5
+#define OSPFLSDBAGE                      6
+#define OSPFLSDBCHECKSUM                 7
+#define OSPFLSDBADVERTISEMENT            8
+
+/* OSPF MIB ospfAreaRangeTable. */
+#define OSPFAREARANGEAREAID              1
+#define OSPFAREARANGENET                 2
+#define OSPFAREARANGEMASK                3
+#define OSPFAREARANGESTATUS              4
+#define OSPFAREARANGEEFFECT              5
+
+/* OSPF MIB ospfHostTable. */
+#define OSPFHOSTIPADDRESS                1
+#define OSPFHOSTTOS                      2
+#define OSPFHOSTMETRIC                   3
+#define OSPFHOSTSTATUS                   4
+#define OSPFHOSTAREAID                   5
+
+/* OSPF MIB ospfIfTable. */
+#define OSPFIFIPADDRESS                  1
+#define OSPFADDRESSLESSIF                2
+#define OSPFIFAREAID                     3
+#define OSPFIFTYPE                       4
+#define OSPFIFADMINSTAT                  5
+#define OSPFIFRTRPRIORITY                6
+#define OSPFIFTRANSITDELAY               7
+#define OSPFIFRETRANSINTERVAL            8
+#define OSPFIFHELLOINTERVAL              9
+#define OSPFIFRTRDEADINTERVAL            10
+#define OSPFIFPOLLINTERVAL               11
+#define OSPFIFSTATE                      12
+#define OSPFIFDESIGNATEDROUTER           13
+#define OSPFIFBACKUPDESIGNATEDROUTER     14
+#define OSPFIFEVENTS                     15
+#define OSPFIFAUTHKEY                    16
+#define OSPFIFSTATUS                     17
+#define OSPFIFMULTICASTFORWARDING        18
+#define OSPFIFDEMAND                     19
+#define OSPFIFAUTHTYPE                   20
+
+/* OSPF MIB ospfIfMetricTable. */
+#define OSPFIFMETRICIPADDRESS            1
+#define OSPFIFMETRICADDRESSLESSIF        2
+#define OSPFIFMETRICTOS                  3
+#define OSPFIFMETRICVALUE                4
+#define OSPFIFMETRICSTATUS               5
+
+/* OSPF MIB ospfVirtIfTable. */
+#define OSPFVIRTIFAREAID                 1
+#define OSPFVIRTIFNEIGHBOR               2
+#define OSPFVIRTIFTRANSITDELAY           3
+#define OSPFVIRTIFRETRANSINTERVAL        4
+#define OSPFVIRTIFHELLOINTERVAL          5
+#define OSPFVIRTIFRTRDEADINTERVAL        6
+#define OSPFVIRTIFSTATE                  7
+#define OSPFVIRTIFEVENTS                 8
+#define OSPFVIRTIFAUTHKEY                9
+#define OSPFVIRTIFSTATUS                 10
+#define OSPFVIRTIFAUTHTYPE               11
+
+/* OSPF MIB ospfNbrTable. */
+#define OSPFNBRIPADDR                    1
+#define OSPFNBRADDRESSLESSINDEX          2
+#define OSPFNBRRTRID                     3
+#define OSPFNBROPTIONS                   4
+#define OSPFNBRPRIORITY                  5
+#define OSPFNBRSTATE                     6
+#define OSPFNBREVENTS                    7
+#define OSPFNBRLSRETRANSQLEN             8
+#define OSPFNBMANBRSTATUS                9
+#define OSPFNBMANBRPERMANENCE            10
+#define OSPFNBRHELLOSUPPRESSED           11
+
+/* OSPF MIB ospfVirtNbrTable. */
+#define OSPFVIRTNBRAREA                  1
+#define OSPFVIRTNBRRTRID                 2
+#define OSPFVIRTNBRIPADDR                3
+#define OSPFVIRTNBROPTIONS               4
+#define OSPFVIRTNBRSTATE                 5
+#define OSPFVIRTNBREVENTS                6
+#define OSPFVIRTNBRLSRETRANSQLEN         7
+#define OSPFVIRTNBRHELLOSUPPRESSED       8
+
+/* OSPF MIB ospfExtLsdbTable. */
+#define OSPFEXTLSDBTYPE                  1
+#define OSPFEXTLSDBLSID                  2
+#define OSPFEXTLSDBROUTERID              3
+#define OSPFEXTLSDBSEQUENCE              4
+#define OSPFEXTLSDBAGE                   5
+#define OSPFEXTLSDBCHECKSUM              6
+#define OSPFEXTLSDBADVERTISEMENT         7
+
+/* OSPF MIB ospfAreaAggregateTable. */
+#define OSPFAREAAGGREGATEAREAID          1
+#define OSPFAREAAGGREGATELSDBTYPE        2
+#define OSPFAREAAGGREGATENET             3
+#define OSPFAREAAGGREGATEMASK            4
+#define OSPFAREAAGGREGATESTATUS          5
+#define OSPFAREAAGGREGATEEFFECT          6
+
+/* SYNTAX Status from OSPF-MIB. */
+#define OSPF_STATUS_ENABLED  1
+#define OSPF_STATUS_DISABLED 2
+
+/* SNMP value hack. */
+#define COUNTER     ASN_COUNTER
+#define INTEGER     ASN_INTEGER
+#define GAUGE       ASN_GAUGE
+#define TIMETICKS   ASN_TIMETICKS
+#define IPADDRESS   ASN_IPADDRESS
+#define STRING      ASN_OCTET_STR
+\f
+/* Declare static local variables for convenience. */
+SNMP_LOCAL_VARIABLES
+
+/* OSPF-MIB instances. */
+oid ospf_oid [] = { OSPF2MIB };
+oid ospfd_oid [] = { OSPFDOID };
+
+/* IP address 0.0.0.0. */
+static struct in_addr ospf_empty_addr = {0};
+
+/* Hook functions. */
+static u_char *ospfGeneralGroup ();
+static u_char *ospfAreaEntry ();
+static u_char *ospfStubAreaEntry ();
+static u_char *ospfLsdbEntry ();
+static u_char *ospfAreaRangeEntry ();
+static u_char *ospfHostEntry ();
+static u_char *ospfIfEntry ();
+static u_char *ospfIfMetricEntry ();
+static u_char *ospfVirtIfEntry ();
+static u_char *ospfNbrEntry ();
+static u_char *ospfVirtNbrEntry ();
+static u_char *ospfExtLsdbEntry ();
+static u_char *ospfAreaAggregateEntry ();
+
+struct variable ospf_variables[] = 
+{
+  /* OSPF general variables */
+  {OSPFROUTERID,              IPADDRESS, RWRITE, ospfGeneralGroup,
+   2, {1, 1}},
+  {OSPFADMINSTAT,             INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 2}},
+  {OSPFVERSIONNUMBER,         INTEGER, RONLY, ospfGeneralGroup,
+   2, {1, 3}},
+  {OSPFAREABDRRTRSTATUS,      INTEGER, RONLY, ospfGeneralGroup,
+   2, {1, 4}},
+  {OSPFASBDRRTRSTATUS,        INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 5}},
+  {OSPFEXTERNLSACOUNT,        GAUGE, RONLY, ospfGeneralGroup,
+   2, {1, 6}},
+  {OSPFEXTERNLSACKSUMSUM,     INTEGER, RONLY, ospfGeneralGroup,
+   2, {1, 7}},
+  {OSPFTOSSUPPORT,            INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 8}},
+  {OSPFORIGINATENEWLSAS,      COUNTER, RONLY, ospfGeneralGroup,
+   2, {1, 9}},
+  {OSPFRXNEWLSAS,             COUNTER, RONLY, ospfGeneralGroup,
+   2, {1, 10}},
+  {OSPFEXTLSDBLIMIT,          INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 11}},
+  {OSPFMULTICASTEXTENSIONS,   INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 12}},
+  {OSPFEXITOVERFLOWINTERVAL,  INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 13}},
+  {OSPFDEMANDEXTENSIONS,      INTEGER, RWRITE, ospfGeneralGroup,
+   2, {1, 14}},
+
+  /* OSPF area data structure. */
+  {OSPFAREAID,                IPADDRESS, RONLY, ospfAreaEntry,
+   3, {2, 1, 1}},
+  {OSPFAUTHTYPE,              INTEGER, RWRITE, ospfAreaEntry,
+   3, {2, 1, 2}},
+  {OSPFIMPORTASEXTERN,        INTEGER, RWRITE, ospfAreaEntry,
+   3, {2, 1, 3}},
+  {OSPFSPFRUNS,               COUNTER, RONLY, ospfAreaEntry,
+   3, {2, 1, 4}},
+  {OSPFAREABDRRTRCOUNT,       GAUGE, RONLY, ospfAreaEntry,
+   3, {2, 1, 5}},
+  {OSPFASBDRRTRCOUNT,         GAUGE, RONLY, ospfAreaEntry,
+   3, {2, 1, 6}},
+  {OSPFAREALSACOUNT,          GAUGE, RONLY, ospfAreaEntry,
+   3, {2, 1, 7}},
+  {OSPFAREALSACKSUMSUM,       INTEGER, RONLY, ospfAreaEntry,
+   3, {2, 1, 8}},
+  {OSPFAREASUMMARY,           INTEGER, RWRITE, ospfAreaEntry,
+   3, {2, 1, 9}},
+  {OSPFAREASTATUS,            INTEGER, RWRITE, ospfAreaEntry,
+   3, {2, 1, 10}},
+
+  /* OSPF stub area information. */
+  {OSPFSTUBAREAID,            IPADDRESS, RONLY, ospfStubAreaEntry,
+   3, {3, 1, 1}},
+  {OSPFSTUBTOS,               INTEGER, RONLY, ospfStubAreaEntry,
+   3, {3, 1, 2}},
+  {OSPFSTUBMETRIC,            INTEGER, RWRITE, ospfStubAreaEntry,
+   3, {3, 1, 3}},
+  {OSPFSTUBSTATUS,            INTEGER, RWRITE, ospfStubAreaEntry,
+   3, {3, 1, 4}},
+  {OSPFSTUBMETRICTYPE,        INTEGER, RWRITE, ospfStubAreaEntry,
+   3, {3, 1, 5}},
+
+  /* OSPF link state database. */
+  {OSPFLSDBAREAID,            IPADDRESS, RONLY, ospfLsdbEntry,
+   3, {4, 1, 1}},
+  {OSPFLSDBTYPE,              INTEGER, RONLY, ospfLsdbEntry,
+   3, {4, 1, 2}},
+  {OSPFLSDBLSID,              IPADDRESS, RONLY, ospfLsdbEntry,
+   3, {4, 1, 3}},
+  {OSPFLSDBROUTERID,          IPADDRESS, RONLY, ospfLsdbEntry,
+   3, {4, 1, 4}},
+  {OSPFLSDBSEQUENCE,          INTEGER, RONLY, ospfLsdbEntry,
+   3, {4, 1, 5}},
+  {OSPFLSDBAGE,               INTEGER, RONLY, ospfLsdbEntry,
+   3, {4, 1, 6}},
+  {OSPFLSDBCHECKSUM,          INTEGER, RONLY, ospfLsdbEntry,
+   3, {4, 1, 7}},
+  {OSPFLSDBADVERTISEMENT,     STRING, RONLY, ospfLsdbEntry,
+   3, {4, 1, 8}},
+
+  /* Area range table. */
+  {OSPFAREARANGEAREAID,       IPADDRESS, RONLY, ospfAreaRangeEntry,
+   3, {5, 1, 1}},
+  {OSPFAREARANGENET,          IPADDRESS, RONLY, ospfAreaRangeEntry,
+   3, {5, 1, 2}},
+  {OSPFAREARANGEMASK,         IPADDRESS, RWRITE, ospfAreaRangeEntry,
+   3, {5, 1, 3}},
+  {OSPFAREARANGESTATUS,       INTEGER, RWRITE, ospfAreaRangeEntry,
+   3, {5, 1, 4}},
+  {OSPFAREARANGEEFFECT,       INTEGER, RWRITE, ospfAreaRangeEntry,
+   3, {5, 1, 5}},
+
+  /* OSPF host table. */
+  {OSPFHOSTIPADDRESS,         IPADDRESS, RONLY, ospfHostEntry,
+   3, {6, 1, 1}},
+  {OSPFHOSTTOS,               INTEGER, RONLY, ospfHostEntry,
+   3, {6, 1, 2}},
+  {OSPFHOSTMETRIC,            INTEGER, RWRITE, ospfHostEntry,
+   3, {6, 1, 3}},
+  {OSPFHOSTSTATUS,            INTEGER, RWRITE, ospfHostEntry,
+   3, {6, 1, 4}},
+  {OSPFHOSTAREAID,            IPADDRESS, RONLY, ospfHostEntry,
+   3, {6, 1, 5}},
+
+  /* OSPF interface table. */
+  {OSPFIFIPADDRESS,           IPADDRESS, RONLY, ospfIfEntry,
+   3, {7, 1, 1}},
+  {OSPFADDRESSLESSIF,         INTEGER, RONLY, ospfIfEntry,
+   3, {7, 1, 2}},
+  {OSPFIFAREAID,              IPADDRESS, RWRITE, ospfIfEntry,
+   3, {7, 1, 3}},
+  {OSPFIFTYPE,                INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 4}},
+  {OSPFIFADMINSTAT,           INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 5}},
+  {OSPFIFRTRPRIORITY,         INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 6}},
+  {OSPFIFTRANSITDELAY,        INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 7}},
+  {OSPFIFRETRANSINTERVAL,     INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 8}},
+  {OSPFIFHELLOINTERVAL,       INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 9}},
+  {OSPFIFRTRDEADINTERVAL,     INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 10}},
+  {OSPFIFPOLLINTERVAL,        INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 11}},
+  {OSPFIFSTATE,               INTEGER, RONLY, ospfIfEntry,
+   3, {7, 1, 12}},
+  {OSPFIFDESIGNATEDROUTER,    IPADDRESS, RONLY, ospfIfEntry,
+   3, {7, 1, 13}},
+  {OSPFIFBACKUPDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry,
+   3, {7, 1, 14}},
+  {OSPFIFEVENTS,              COUNTER, RONLY, ospfIfEntry,
+   3, {7, 1, 15}},
+  {OSPFIFAUTHKEY,             STRING,  RWRITE, ospfIfEntry,
+   3, {7, 1, 16}},
+  {OSPFIFSTATUS,              INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 17}},
+  {OSPFIFMULTICASTFORWARDING, INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 18}},
+  {OSPFIFDEMAND,              INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 19}},
+  {OSPFIFAUTHTYPE,            INTEGER, RWRITE, ospfIfEntry,
+   3, {7, 1, 20}},
+
+  /* OSPF interface metric table. */
+  {OSPFIFMETRICIPADDRESS,     IPADDRESS, RONLY, ospfIfMetricEntry,
+   3, {8, 1, 1}},
+  {OSPFIFMETRICADDRESSLESSIF, INTEGER, RONLY, ospfIfMetricEntry,
+   3, {8, 1, 2}},
+  {OSPFIFMETRICTOS,           INTEGER, RONLY, ospfIfMetricEntry,
+   3, {8, 1, 3}},
+  {OSPFIFMETRICVALUE,         INTEGER, RWRITE, ospfIfMetricEntry,
+   3, {8, 1, 4}},
+  {OSPFIFMETRICSTATUS,        INTEGER, RWRITE, ospfIfMetricEntry,
+   3, {8, 1, 5}},
+
+  /* OSPF virtual interface table. */
+  {OSPFVIRTIFAREAID,          IPADDRESS, RONLY, ospfVirtIfEntry,
+   3, {9, 1, 1}},
+  {OSPFVIRTIFNEIGHBOR,        IPADDRESS, RONLY, ospfVirtIfEntry,
+   3, {9, 1, 2}},
+  {OSPFVIRTIFTRANSITDELAY,    INTEGER, RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 3}},
+  {OSPFVIRTIFRETRANSINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 4}},
+  {OSPFVIRTIFHELLOINTERVAL,   INTEGER, RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 5}},
+  {OSPFVIRTIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 6}},
+  {OSPFVIRTIFSTATE,           INTEGER, RONLY, ospfVirtIfEntry,
+   3, {9, 1, 7}},
+  {OSPFVIRTIFEVENTS,          COUNTER, RONLY, ospfVirtIfEntry,
+   3, {9, 1, 8}},
+  {OSPFVIRTIFAUTHKEY,         STRING,  RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 9}},
+  {OSPFVIRTIFSTATUS,          INTEGER, RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 10}},
+  {OSPFVIRTIFAUTHTYPE,        INTEGER, RWRITE, ospfVirtIfEntry,
+   3, {9, 1, 11}},
+
+  /* OSPF neighbor table. */
+  {OSPFNBRIPADDR,             IPADDRESS, RONLY, ospfNbrEntry,
+   3, {10, 1, 1}},
+  {OSPFNBRADDRESSLESSINDEX,   INTEGER, RONLY, ospfNbrEntry,
+   3, {10, 1, 2}},
+  {OSPFNBRRTRID,              IPADDRESS, RONLY, ospfNbrEntry,
+   3, {10, 1, 3}},
+  {OSPFNBROPTIONS,            INTEGER, RONLY, ospfNbrEntry,
+   3, {10, 1, 4}},
+  {OSPFNBRPRIORITY,           INTEGER, RWRITE, ospfNbrEntry,
+   3, {10, 1, 5}},
+  {OSPFNBRSTATE,              INTEGER, RONLY, ospfNbrEntry,
+   3, {10, 1, 6}},
+  {OSPFNBREVENTS,             COUNTER, RONLY, ospfNbrEntry,
+   3, {10, 1, 7}},
+  {OSPFNBRLSRETRANSQLEN,      GAUGE, RONLY, ospfNbrEntry,
+   3, {10, 1, 8}},
+  {OSPFNBMANBRSTATUS,         INTEGER, RWRITE, ospfNbrEntry,
+   3, {10, 1, 9}},
+  {OSPFNBMANBRPERMANENCE,     INTEGER, RONLY, ospfNbrEntry,
+   3, {10, 1, 10}},
+  {OSPFNBRHELLOSUPPRESSED,    INTEGER, RONLY, ospfNbrEntry,
+   3, {10, 1, 11}},
+
+  /* OSPF virtual neighbor table. */
+  {OSPFVIRTNBRAREA,           IPADDRESS, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 1}},
+  {OSPFVIRTNBRRTRID,          IPADDRESS, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 2}},
+  {OSPFVIRTNBRIPADDR,         IPADDRESS, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 3}},
+  {OSPFVIRTNBROPTIONS,        INTEGER, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 4}},
+  {OSPFVIRTNBRSTATE,          INTEGER, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 5}},
+  {OSPFVIRTNBREVENTS,         COUNTER, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 6}},
+  {OSPFVIRTNBRLSRETRANSQLEN,  INTEGER, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 7}},
+  {OSPFVIRTNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfVirtNbrEntry,
+   3, {11, 1, 8}},
+
+  /* OSPF link state database, external. */
+  {OSPFEXTLSDBTYPE,           INTEGER, RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 1}},
+  {OSPFEXTLSDBLSID,           IPADDRESS, RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 2}},
+  {OSPFEXTLSDBROUTERID,       IPADDRESS, RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 3}},
+  {OSPFEXTLSDBSEQUENCE,       INTEGER, RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 4}},
+  {OSPFEXTLSDBAGE,            INTEGER, RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 5}},
+  {OSPFEXTLSDBCHECKSUM,       INTEGER, RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 6}},
+  {OSPFEXTLSDBADVERTISEMENT,  STRING,  RONLY, ospfExtLsdbEntry,
+   3, {12, 1, 7}},
+
+  /* OSPF area aggregate table. */
+  {OSPFAREAAGGREGATEAREAID,   IPADDRESS, RONLY, ospfAreaAggregateEntry, 
+   3, {14, 1, 1}},
+  {OSPFAREAAGGREGATELSDBTYPE, INTEGER, RONLY, ospfAreaAggregateEntry, 
+   3, {14, 1, 2}},
+  {OSPFAREAAGGREGATENET,      IPADDRESS, RONLY, ospfAreaAggregateEntry, 
+   3, {14, 1, 3}},
+  {OSPFAREAAGGREGATEMASK,     IPADDRESS, RONLY, ospfAreaAggregateEntry, 
+   3, {14, 1, 4}},
+  {OSPFAREAAGGREGATESTATUS,   INTEGER, RWRITE, ospfAreaAggregateEntry,
+   3, {14, 1, 5}},
+  {OSPFAREAAGGREGATEEFFECT,   INTEGER, RWRITE, ospfAreaAggregateEntry,
+   3, {14, 1, 6}}
+};
+\f
+/* The administrative status of OSPF.  When OSPF is enbled on at least
+   one interface return 1. */
+int
+ospf_admin_stat ()
+{
+  listnode node;
+  struct ospf_interface *oi;
+
+  if (! ospf_top)
+    return 0;
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      oi = getdata (node);
+
+      if (oi && oi->address)
+       return 1;
+    }
+  return 0;
+}
+
+static u_char *
+ospfGeneralGroup (struct variable *v, oid *name, size_t *length,
+                 int exact, size_t *var_len, WriteMethod **write_method)
+{
+  /* Check whether the instance identifier is valid */
+  if (smux_header_generic (v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFROUTERID:         /* 1 */
+      /* Router-ID of this OSPF instance. */
+      if (ospf_top)
+       return SNMP_IPADDRESS (ospf_top->router_id);
+      else
+       return SNMP_IPADDRESS (ospf_empty_addr);
+      break;
+    case OSPFADMINSTAT:                /* 2 */
+      /* The administrative status of OSPF in the router. */
+      if (ospf_admin_stat ())
+       return SNMP_INTEGER (OSPF_STATUS_ENABLED);
+      else
+       return SNMP_INTEGER (OSPF_STATUS_DISABLED);
+      break;
+    case OSPFVERSIONNUMBER:    /* 3 */
+      /* OSPF version 2. */
+      return SNMP_INTEGER (OSPF_VERSION);
+      break;
+    case OSPFAREABDRRTRSTATUS: /* 4 */
+      /* Area Border router status. */
+      if (ospf_top && CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ABR))
+       return SNMP_INTEGER (SNMP_TRUE);
+      else
+       return SNMP_INTEGER (SNMP_FALSE);
+      break;
+    case OSPFASBDRRTRSTATUS:   /* 5 */
+      /* AS Border router status. */
+      if (ospf_top && CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ASBR))
+       return SNMP_INTEGER (SNMP_TRUE);
+      else
+       return SNMP_INTEGER (SNMP_FALSE);
+      break;
+    case OSPFEXTERNLSACOUNT:   /* 6 */
+      /* External LSA counts. */
+      if (ospf_top)
+       return SNMP_INTEGER (ospf_lsdb_count_all (ospf_top->lsdb));
+      else
+       return SNMP_INTEGER (0);
+      break;
+    case OSPFEXTERNLSACKSUMSUM:        /* 7 */
+      /* External LSA checksum. */
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFTOSSUPPORT:       /* 8 */
+      /* TOS is not supported. */
+      return SNMP_INTEGER (SNMP_FALSE);
+      break;
+    case OSPFORIGINATENEWLSAS: /* 9 */
+      /* The number of new link-state advertisements. */
+      if (ospf_top)
+       return SNMP_INTEGER (ospf_top->lsa_originate_count);
+      else
+       return SNMP_INTEGER (0);
+      break;
+    case OSPFRXNEWLSAS:                /* 10 */
+      /* The number of link-state advertisements received determined
+         to be new instantiations. */
+      if (ospf_top)
+       return SNMP_INTEGER (ospf_top->rx_lsa_count);
+      else
+       return SNMP_INTEGER (0);
+      break;
+    case OSPFEXTLSDBLIMIT:     /* 11 */
+      /* There is no limit for the number of non-default
+         AS-external-LSAs. */
+      return SNMP_INTEGER (-1);
+      break;
+    case OSPFMULTICASTEXTENSIONS: /* 12 */
+      /* Multicast Extensions to OSPF is not supported. */
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFEXITOVERFLOWINTERVAL: /* 13 */
+      /* Overflow is not supported. */
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFDEMANDEXTENSIONS: /* 14 */
+      /* Demand routing is not supported. */
+      return SNMP_INTEGER (SNMP_FALSE);
+      break;
+    default:
+      return NULL;
+    }
+  return NULL;
+}
+
+struct ospf_area *
+ospf_area_lookup_next (struct in_addr *area_id, int first)
+{
+  struct ospf_area *area;
+  listnode node;
+
+  if (! ospf_top)
+    return NULL;
+
+  if (first)
+    {
+      node = listhead (ospf_top->areas);
+      if (node)
+       {
+         area = getdata (node);
+         *area_id = area->area_id;
+         return area;
+       }
+      return NULL;
+    }
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr))
+       {
+         *area_id = area->area_id;
+         return area;
+       }
+    }
+  return NULL;
+}
+
+struct ospf_area *
+ospfAreaLookup (struct variable *v, oid name[], size_t *length,
+               struct in_addr *addr, int exact)
+{
+  int len;
+  struct ospf_area *area;
+
+  if (! ospf_top)
+    return NULL;
+
+  if (exact)
+    {
+      /* Length is insufficient to lookup OSPF area. */
+      if (*length - v->namelen != sizeof (struct in_addr))
+       return NULL;
+
+      oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
+
+      area = ospf_area_lookup_by_area_id (*addr);
+
+      return area;
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4)
+       len = 4;
+      
+      oid2in_addr (name + v->namelen, len, addr);
+
+      area = ospf_area_lookup_next (addr, len == 0 ? 1 : 0);
+
+      if (area == NULL)
+       return NULL;
+
+      oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
+      *length = sizeof (struct in_addr) + v->namelen;
+
+      return area;
+    }
+  return NULL;
+}
+
+static u_char *
+ospfAreaEntry (struct variable *v, oid *name, size_t *length, int exact,
+              size_t *var_len, WriteMethod **write_method)
+{
+  struct ospf_area *area;
+  struct in_addr addr;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+
+  area = ospfAreaLookup (v, name, length, &addr, exact);
+  if (! area)
+    return NULL;
+  
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFAREAID:           /* 1 */
+      return SNMP_IPADDRESS (area->area_id);
+      break;
+    case OSPFAUTHTYPE:         /* 2 */
+      return SNMP_INTEGER (area->auth_type);
+      break;
+    case OSPFIMPORTASEXTERN:   /* 3 */
+      return SNMP_INTEGER (area->external_routing + 1);
+      break;
+    case OSPFSPFRUNS:          /* 4 */
+      return SNMP_INTEGER (area->spf_calculation);
+      break;
+    case OSPFAREABDRRTRCOUNT:  /* 5 */
+      return SNMP_INTEGER (area->abr_count);
+      break;
+    case OSPFASBDRRTRCOUNT:    /* 6 */
+      return SNMP_INTEGER (area->asbr_count);
+      break;
+    case OSPFAREALSACOUNT:     /* 7 */
+      return SNMP_INTEGER (area->lsdb->total);
+      break;
+    case OSPFAREALSACKSUMSUM:  /* 8 */
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFAREASUMMARY:      /* 9 */
+#define OSPF_noAreaSummary   1
+#define OSPF_sendAreaSummary 2
+      if (area->no_summary)
+       return SNMP_INTEGER (OSPF_noAreaSummary);
+      else
+       return SNMP_INTEGER (OSPF_sendAreaSummary);
+      break;
+    case OSPFAREASTATUS:       /* 10 */
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+struct ospf_area *
+ospf_stub_area_lookup_next (struct in_addr *area_id, int first)
+{
+  struct ospf_area *area;
+  listnode node;
+
+  if (! ospf_top)
+    return NULL;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (area->external_routing == OSPF_AREA_STUB)
+       {
+         if (first)
+           {
+             *area_id = area->area_id;
+             return area;
+           }
+         else if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr))
+           {
+             *area_id = area->area_id;
+             return area;
+           }
+       }
+    }
+  return NULL;
+}
+
+struct ospf_area *
+ospfStubAreaLookup (struct variable *v, oid name[], size_t *length,
+                   struct in_addr *addr, int exact)
+{
+  int len;
+  struct ospf_area *area;
+
+  if (! ospf_top)
+    return NULL;
+
+  /* Exact lookup. */
+  if (exact)
+    {
+      /* ospfStubAreaID + ospfStubTOS. */
+      if (*length != v->namelen + sizeof (struct in_addr) + 1)
+       return NULL;
+
+      /* Check ospfStubTOS is zero. */
+      if (name[*length - 1] != 0)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
+
+      area = ospf_area_lookup_by_area_id (*addr);
+
+      if (area->external_routing == OSPF_AREA_STUB)
+       return area;
+      else
+       return NULL;
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4)
+       len = 4;
+      
+      oid2in_addr (name + v->namelen, len, addr);
+
+      area = ospf_stub_area_lookup_next (addr, len == 0 ? 1 : 0);
+
+      if (area == NULL)
+       return NULL;
+
+      oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
+      /* Set TOS 0. */
+      name[v->namelen + sizeof (struct in_addr)] = 0;
+      *length = v->namelen + sizeof (struct in_addr) + 1;
+
+      return area;
+    }
+  return NULL;
+}
+
+static u_char *
+ospfStubAreaEntry (struct variable *v, oid *name, size_t *length,
+                  int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct ospf_area *area;
+  struct in_addr addr;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+
+  area = ospfStubAreaLookup (v, name, length, &addr, exact);
+  if (! area)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFSTUBAREAID:       /* 1 */
+      /* OSPF stub area id. */
+      return SNMP_IPADDRESS (area->area_id);
+      break;
+    case OSPFSTUBTOS:          /* 2 */
+      /* TOS value is not supported. */
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFSTUBMETRIC:       /* 3 */
+      /* Default cost to stub area. */
+      return SNMP_INTEGER (area->default_cost);
+      break;
+    case OSPFSTUBSTATUS:       /* 4 */
+      /* Status of the stub area. */
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    case OSPFSTUBMETRICTYPE:   /* 5 */
+      /* OSPF Metric type. */
+#define OSPF_ospfMetric     1
+#define OSPF_comparableCost 2
+#define OSPF_nonComparable  3
+      return SNMP_INTEGER (OSPF_ospfMetric);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+struct ospf_lsa *
+lsdb_lookup_next (struct ospf_area *area, u_char *type, int type_next,
+                 struct in_addr *ls_id, int ls_id_next,
+                 struct in_addr *router_id, int router_id_next)
+{
+  struct ospf_lsa *lsa;
+  int i;
+
+  if (type_next)
+    i = OSPF_MIN_LSA;
+  else
+    i = *type;
+
+  for (; i < OSPF_MAX_LSA; i++)
+    {
+      *type = i;
+
+      lsa = ospf_lsdb_lookup_by_id_next (area->lsdb, *type, *ls_id, *router_id,
+                                       ls_id_next);
+      if (lsa)
+       return lsa;
+
+      ls_id_next = 1;
+    }
+  return NULL;
+}
+
+struct ospf_lsa *
+ospfLsdbLookup (struct variable *v, oid *name, size_t *length,
+               struct in_addr *area_id, u_char *type,
+               struct in_addr *ls_id, struct in_addr *router_id, int exact)
+{
+  struct ospf_area *area;
+  struct ospf_lsa *lsa;
+  int len;
+  int type_next;
+  int ls_id_next;
+  int router_id_next;
+  oid *offset;
+  int offsetlen;
+
+#define OSPF_LSDB_ENTRY_OFFSET \
+          (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE)
+
+  if (exact)
+    {
+      /* Area ID + Type + LS ID + Router ID. */
+      if (*length - v->namelen != OSPF_LSDB_ENTRY_OFFSET)
+       return NULL;
+      
+      /* Set OID offset for Area ID. */
+      offset = name + v->namelen;
+
+      /* Lookup area first. */
+      oid2in_addr (offset, IN_ADDR_SIZE, area_id);
+      area = ospf_area_lookup_by_area_id (*area_id);
+      if (! area)
+       return NULL;
+      offset += IN_ADDR_SIZE;
+
+      /* Type. */
+      *type = *offset;
+      offset++;
+
+      /* LS ID. */
+      oid2in_addr (offset, IN_ADDR_SIZE, ls_id);
+      offset += IN_ADDR_SIZE;
+
+      /* Router ID. */
+      oid2in_addr (offset, IN_ADDR_SIZE, router_id);
+
+      /* Lookup LSDB. */
+      return ospf_lsdb_lookup_by_id (area->lsdb, *type, *ls_id, *router_id);
+    }
+  else
+    {
+      /* Get variable length. */
+      offset = name + v->namelen;
+      offsetlen = *length - v->namelen;
+      len = offsetlen;
+
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+
+      oid2in_addr (offset, len, area_id);
+
+      /* First we search area. */
+      if (len == IN_ADDR_SIZE)
+       area = ospf_area_lookup_by_area_id (*area_id);
+      else
+       area = ospf_area_lookup_next (area_id, len == 0 ? 1 : 0);
+
+      if (area == NULL)
+       return NULL;
+
+      do 
+       {
+         /* Next we lookup type. */
+         offset += IN_ADDR_SIZE;
+         offsetlen -= IN_ADDR_SIZE;
+         len = offsetlen;
+
+         if (len <= 0)
+           type_next = 1;
+         else
+           {
+             len = 1;
+             type_next = 0;
+             *type = *offset;
+           }
+       
+         /* LS ID. */
+         offset++;
+         offsetlen--;
+         len = offsetlen;
+
+         if (len <= 0)
+           ls_id_next = 1;
+         else
+           {
+             ls_id_next = 0;
+             if (len > IN_ADDR_SIZE)
+               len = IN_ADDR_SIZE;
+
+             oid2in_addr (offset, len, ls_id);
+           }
+
+         /* Router ID. */
+         offset += IN_ADDR_SIZE;
+         offsetlen -= IN_ADDR_SIZE;
+         len = offsetlen;
+
+         if (len <= 0)
+           router_id_next = 1;
+         else
+           {
+             router_id_next = 0;
+             if (len > IN_ADDR_SIZE)
+               len = IN_ADDR_SIZE;
+
+             oid2in_addr (offset, len, router_id);
+           }
+
+         lsa = lsdb_lookup_next (area, type, type_next, ls_id, ls_id_next,
+                                 router_id, router_id_next);
+
+         if (lsa)
+           {
+             /* Fill in length. */
+             *length = v->namelen + OSPF_LSDB_ENTRY_OFFSET;
+
+             /* Fill in value. */
+             offset = name + v->namelen;
+             oid_copy_addr (offset, area_id, IN_ADDR_SIZE);
+             offset += IN_ADDR_SIZE;
+             *offset = lsa->data->type;
+             offset++;
+             oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE);
+             offset += IN_ADDR_SIZE;
+             oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE);
+           
+             return lsa;
+           }
+       }
+      while ((area = ospf_area_lookup_next (area_id, 0)) != NULL);
+    }
+  return NULL;
+}
+
+static u_char *
+ospfLsdbEntry (struct variable *v, oid *name, size_t *length, int exact,
+              size_t *var_len, WriteMethod **write_method)
+{
+  struct ospf_lsa *lsa;
+  struct lsa_header *lsah;
+  struct in_addr area_id;
+  u_char type;
+  struct in_addr ls_id;
+  struct in_addr router_id;
+
+  /* INDEX { ospfLsdbAreaId, ospfLsdbType,
+     ospfLsdbLsid, ospfLsdbRouterId } */
+
+  memset (&area_id, 0, sizeof (struct in_addr));
+  type = 0;
+  memset (&ls_id, 0, sizeof (struct in_addr));
+  memset (&router_id, 0, sizeof (struct in_addr));
+
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  lsa = ospfLsdbLookup (v, name, length, &area_id, &type, &ls_id, &router_id,
+                       exact);
+  if (! lsa)
+    return NULL;
+
+  lsah = lsa->data;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFLSDBAREAID:       /* 1 */
+      return SNMP_IPADDRESS (lsa->area->area_id);
+      break;
+    case OSPFLSDBTYPE:         /* 2 */
+      return SNMP_INTEGER (lsah->type);
+      break;
+    case OSPFLSDBLSID:         /* 3 */
+      return SNMP_IPADDRESS (lsah->id);
+      break;
+    case OSPFLSDBROUTERID:     /* 4 */
+      return SNMP_IPADDRESS (lsah->adv_router);
+      break;
+    case OSPFLSDBSEQUENCE:     /* 5 */
+      return SNMP_INTEGER (lsah->ls_seqnum);
+      break;
+    case OSPFLSDBAGE:          /* 6 */
+      return SNMP_INTEGER (lsah->ls_age);
+      break;
+    case OSPFLSDBCHECKSUM:     /* 7 */
+      return SNMP_INTEGER (lsah->checksum);
+      break;
+    case OSPFLSDBADVERTISEMENT:        /* 8 */
+      *var_len = ntohs (lsah->length);
+      return (u_char *) lsah;
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+struct ospf_area_range *
+ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length,
+                    struct in_addr *area_id, struct in_addr *range_net,
+                    int exact)
+{
+  oid *offset;
+  int offsetlen;
+  int len;
+  struct ospf_area *area;
+  struct ospf_area_range *range;
+  struct prefix_ipv4 p;
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  if (exact) 
+    {
+      /* Area ID + Range Network. */
+      if (v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE != *length)
+       return NULL;
+
+      /* Set OID offset for Area ID. */
+      offset = name + v->namelen;
+
+      /* Lookup area first. */
+      oid2in_addr (offset, IN_ADDR_SIZE, area_id);
+
+      area = ospf_area_lookup_by_area_id (*area_id);
+      if (! area)
+       return NULL;
+
+      offset += IN_ADDR_SIZE;
+
+      /* Lookup area range. */
+      oid2in_addr (offset, IN_ADDR_SIZE, range_net);
+      p.prefix = *range_net;
+
+      return ospf_area_range_lookup (area, &p);
+    }
+  else
+    {
+      /* Set OID offset for Area ID. */
+      offset = name + v->namelen;
+      offsetlen = *length - v->namelen;
+
+      len = offsetlen;
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+
+      oid2in_addr (offset, len, area_id);
+
+      /* First we search area. */
+      if (len == IN_ADDR_SIZE)
+       area = ospf_area_lookup_by_area_id (*area_id);
+      else
+       area = ospf_area_lookup_next (area_id, len == 0 ? 1 : 0);
+
+      if (area == NULL)
+       return NULL;
+
+      do 
+       {
+         offset += IN_ADDR_SIZE;
+         offsetlen -= IN_ADDR_SIZE;
+         len = offsetlen;
+
+         if (len < 0)
+           len = 0;
+         if (len > IN_ADDR_SIZE)
+           len = IN_ADDR_SIZE;
+
+         oid2in_addr (offset, len, range_net);
+
+         range = ospf_area_range_lookup_next (area, range_net,
+                                              len == 0 ? 1 : 0);
+
+         if (range)
+           {
+             /* Fill in length. */
+             *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE;
+
+             /* Fill in value. */
+             offset = name + v->namelen;
+             oid_copy_addr (offset, area_id, IN_ADDR_SIZE);
+             offset += IN_ADDR_SIZE;
+             oid_copy_addr (offset, range_net, IN_ADDR_SIZE);
+
+             return range;
+           }
+       }
+      while ((area = ospf_area_lookup_next (area_id, 0)) != NULL);
+    }
+  return NULL;
+}
+
+static u_char *
+ospfAreaRangeEntry (struct variable *v, oid *name, size_t *length, int exact,
+                   size_t *var_len, WriteMethod **write_method)
+{
+  struct ospf_area_range *range;
+  struct in_addr area_id;
+  struct in_addr range_net;
+  struct in_addr mask;
+  
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  memset (&area_id, 0, IN_ADDR_SIZE);
+  memset (&range_net, 0, IN_ADDR_SIZE);
+
+  range = ospfAreaRangeLookup (v, name, length, &area_id, &range_net, exact);
+  if (! range)
+    return NULL;
+
+  /* Convert prefixlen to network mask format. */
+  masklen2ip (range->subst_masklen, &mask);
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFAREARANGEAREAID:  /* 1 */
+      return SNMP_IPADDRESS (area_id);
+      break;
+    case OSPFAREARANGENET:     /* 2 */
+      return SNMP_IPADDRESS (range_net);
+      break;
+    case OSPFAREARANGEMASK:    /* 3 */
+      return SNMP_IPADDRESS (mask);
+      break;
+    case OSPFAREARANGESTATUS:  /* 4 */
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    case OSPFAREARANGEEFFECT:  /* 5 */
+#define OSPF_advertiseMatching      1
+#define OSPF_doNotAdvertiseMatching 2
+      return SNMP_INTEGER (OSPF_advertiseMatching);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+struct ospf_nbr_nbma *
+ospfHostLookup (struct variable *v, oid *name, size_t *length,
+               struct in_addr *addr, int exact)
+{
+  int len;
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  if (! ospf_top)
+    return NULL;
+
+  if (exact)
+    {
+      /* INDEX { ospfHostIpAddress, ospfHostTOS } */
+      if (*length != v->namelen + IN_ADDR_SIZE + 1)
+       return NULL;
+
+      /* Check ospfHostTOS. */
+      if (name[*length - 1] != 0)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr);
+
+      nbr_nbma = ospf_nbr_nbma_lookup (ospf_top, *addr);
+
+      return nbr_nbma;
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4)
+       len = 4;
+      
+      oid2in_addr (name + v->namelen, len, addr);
+
+      nbr_nbma = ospf_nbr_nbma_lookup_next (addr, len == 0 ? 1 : 0);
+
+      if (nbr_nbma == NULL)
+       return NULL;
+
+      oid_copy_addr (name + v->namelen, addr, IN_ADDR_SIZE);
+
+      /* Set TOS 0. */
+      name[v->namelen + IN_ADDR_SIZE] = 0;
+
+      *length = v->namelen + IN_ADDR_SIZE + 1;
+
+      return nbr_nbma;
+    }
+  return NULL;
+}
+
+static u_char *
+ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact,
+              size_t *var_len, WriteMethod **write_method)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+  struct ospf_interface *oi;
+  struct in_addr addr;
+
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+
+  nbr_nbma = ospfHostLookup (v, name, length, &addr, exact);
+  if (nbr_nbma == NULL)
+    return NULL;
+
+  oi = nbr_nbma->oi;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFHOSTIPADDRESS:    /* 1 */
+      return SNMP_IPADDRESS (nbr_nbma->addr);
+      break;
+    case OSPFHOSTTOS:          /* 2 */
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFHOSTMETRIC:       /* 3 */
+      if (oi)
+       return SNMP_INTEGER (oi->output_cost);
+      else
+       return SNMP_INTEGER (1);
+      break;
+    case OSPFHOSTSTATUS:       /* 4 */
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    case OSPFHOSTAREAID:       /* 5 */
+      if (oi && oi->area)
+       return SNMP_IPADDRESS (oi->area->area_id);
+      else
+       return SNMP_IPADDRESS (ospf_empty_addr);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+struct list *ospf_snmp_iflist;
+
+struct ospf_snmp_if
+{
+  struct in_addr addr;
+  unsigned int ifindex;
+  struct interface *ifp;
+};
+
+struct ospf_snmp_if *
+ospf_snmp_if_new ()
+{
+  struct ospf_snmp_if *osif;
+
+  osif = XMALLOC (0, sizeof (struct ospf_snmp_if));
+  memset (osif, 0, sizeof (struct ospf_snmp_if));
+  return osif;
+}
+
+void
+ospf_snmp_if_free (struct ospf_snmp_if *osif)
+{
+  XFREE (0, osif);
+}
+
+void
+ospf_snmp_if_delete (struct interface *ifp)
+{
+  struct listnode *nn;
+  struct ospf_snmp_if *osif;
+
+  LIST_LOOP (ospf_snmp_iflist, osif, nn)
+    {
+      if (osif->ifp == ifp)
+       {
+         list_delete_node (ospf_snmp_iflist, nn);
+         ospf_snmp_if_free (osif);
+         return;
+       }
+    }
+}
+
+void
+ospf_snmp_if_update (struct interface *ifp)
+{
+  struct listnode *nn;
+  struct listnode *pn;
+  struct connected *ifc;
+  struct prefix *p;
+  struct ospf_snmp_if *osif;
+  struct in_addr *addr;
+  unsigned int ifindex;
+
+  ospf_snmp_if_delete (ifp);
+
+  p = NULL;
+  addr = NULL;
+  ifindex = 0;
+
+  /* Lookup first IPv4 address entry. */
+  LIST_LOOP (ifp->connected, ifc, nn)
+    {
+      if (if_is_pointopoint (ifp))
+       p = ifc->destination;
+      else
+       p = ifc->address;
+
+      if (p->family == AF_INET)
+       {
+         addr = &p->u.prefix4;
+         break;
+       }
+    }
+  if (! addr)
+    ifindex = ifp->ifindex;
+
+  /* Add interface to the list. */
+  pn = NULL;
+  LIST_LOOP (ospf_snmp_iflist, osif, nn)
+    {
+      if (addr)
+       {
+         if (ntohl (osif->addr.s_addr) > ntohl (addr->s_addr))
+           break;
+       }
+      else
+       {
+         /* Unnumbered interface. */
+         if (osif->addr.s_addr != 0 || osif->ifindex > ifindex)
+           break;
+       }
+      pn = nn;
+    }
+
+  osif = ospf_snmp_if_new ();
+  if (addr)
+    osif->addr = *addr;
+  else
+    osif->ifindex = ifindex;
+  osif->ifp = ifp;
+
+  listnode_add_after (ospf_snmp_iflist, pn, osif);
+}
+
+struct interface *
+ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex)
+{
+  struct listnode *nn;
+  struct ospf_snmp_if *osif;
+
+  LIST_LOOP (ospf_snmp_iflist, osif, nn)
+    {  
+      if (ifaddr->s_addr)
+       {
+         if (IPV4_ADDR_SAME (&osif->addr, ifaddr))
+           return osif->ifp;
+       }
+      else
+       {
+         if (osif->ifindex == *ifindex)
+           return osif->ifp;
+       }
+    }
+  return NULL;
+}
+
+struct interface *
+ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex,
+                         int ifaddr_next, int ifindex_next)
+{
+  struct ospf_snmp_if *osif;
+  struct listnode *nn;
+
+  if (ifaddr_next)
+    {
+      nn = listhead (ospf_snmp_iflist);
+      if (nn)
+       {
+         osif = getdata (nn);
+         *ifaddr = osif->addr;
+         *ifindex = osif->ifindex;
+         return osif->ifp;
+       }
+      return NULL;
+    }
+
+  LIST_LOOP (ospf_snmp_iflist, osif, nn)
+    {
+      if (ifaddr->s_addr)
+       {
+         if (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr))
+           {
+             *ifaddr = osif->addr;
+             *ifindex = osif->ifindex;
+             return osif->ifp;
+           }
+       }
+      else
+       {
+         if (osif->ifindex > *ifindex || osif->addr.s_addr)
+           {
+             *ifaddr = osif->addr;
+             *ifindex = osif->ifindex;
+             return osif->ifp;
+           }
+       }
+    }
+  return NULL;
+}
+
+int
+ospf_snmp_iftype (struct interface *ifp)
+{
+#define ospf_snmp_iftype_broadcast         1
+#define ospf_snmp_iftype_nbma              2
+#define ospf_snmp_iftype_pointToPoint      3
+#define ospf_snmp_iftype_pointToMultipoint 5
+  if (if_is_broadcast (ifp))
+    return ospf_snmp_iftype_broadcast;
+  if (if_is_pointopoint (ifp))
+    return ospf_snmp_iftype_pointToPoint;
+  return ospf_snmp_iftype_broadcast;
+}
+
+struct interface *
+ospfIfLookup (struct variable *v, oid *name, size_t *length,
+             struct in_addr *ifaddr, unsigned int *ifindex, int exact)
+{
+  int len;
+  int ifaddr_next = 0;
+  int ifindex_next = 0;
+  struct interface *ifp;
+  oid *offset;
+
+  if (exact)
+    {
+      if (*length != v->namelen + IN_ADDR_SIZE + 1)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr);
+      *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+      return ospf_snmp_if_lookup (ifaddr, ifindex);
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len >= IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+      if (len <= 0)
+       ifaddr_next = 1;
+
+      oid2in_addr (name + v->namelen, len, ifaddr);
+
+      len = *length - v->namelen - IN_ADDR_SIZE;
+      if (len >= 1)
+       len = 1;
+      else
+       ifindex_next = 1;
+
+      if (len == 1)
+       *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+      ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
+                                     ifindex_next);
+      if (ifp)
+       {
+         *length = v->namelen + IN_ADDR_SIZE + 1;
+         offset = name + v->namelen;
+         oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE);
+         offset += IN_ADDR_SIZE;
+         *offset = *ifindex;
+         return ifp;
+       }
+    }
+  return NULL;
+}
+
+static u_char *
+ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact,
+            size_t  *var_len, WriteMethod **write_method)
+{
+  struct interface *ifp;
+  unsigned int ifindex;
+  struct in_addr ifaddr;
+  struct ospf_interface *oi;
+
+  ifindex = 0;
+  memset (&ifaddr, 0, sizeof (struct in_addr));
+
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  ifp = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact);
+  if (ifp == NULL)
+    return NULL;
+
+  oi = ospf_if_lookup_by_local_addr (ifp, ifaddr);
+  if (oi == NULL)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFIFIPADDRESS:      /* 1 */
+      return SNMP_IPADDRESS (ifaddr);
+      break;
+    case OSPFADDRESSLESSIF:    /* 2 */
+      return SNMP_INTEGER (ifindex);
+      break;
+    case OSPFIFAREAID:         /* 3 */
+      if (oi->area)
+       return SNMP_IPADDRESS (oi->area->area_id);
+      else
+       return SNMP_IPADDRESS (ospf_empty_addr);
+      break;
+    case OSPFIFTYPE:           /* 4 */
+      return SNMP_INTEGER (ospf_snmp_iftype (ifp));
+      break;
+    case OSPFIFADMINSTAT:      /* 5 */
+      if (oi)
+       return SNMP_INTEGER (OSPF_STATUS_ENABLED);
+      else
+       return SNMP_INTEGER (OSPF_STATUS_DISABLED);
+      break;
+    case OSPFIFRTRPRIORITY:    /* 6 */
+      return SNMP_INTEGER (PRIORITY (oi));
+      break;
+    case OSPFIFTRANSITDELAY:   /* 7 */
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay));
+      break;
+    case OSPFIFRETRANSINTERVAL:        /* 8 */
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval));
+      break;
+    case OSPFIFHELLOINTERVAL:  /* 9 */
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello));
+      break;
+    case OSPFIFRTRDEADINTERVAL:        /* 10 */
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait));
+      break;
+    case OSPFIFPOLLINTERVAL:   /* 11 */
+      return SNMP_INTEGER (OSPF_POLL_INTERVAL_DEFAULT);
+      break;
+    case OSPFIFSTATE:          /* 12 */
+      return SNMP_INTEGER (oi->state);
+      break;
+    case OSPFIFDESIGNATEDROUTER: /* 13 */
+      return SNMP_IPADDRESS (DR (oi));
+      break;
+    case OSPFIFBACKUPDESIGNATEDROUTER: /* 14 */
+      return SNMP_IPADDRESS (BDR (oi));
+      break;
+    case OSPFIFEVENTS:         /* 15 */
+      return SNMP_INTEGER (oi->state_change);
+      break;
+    case OSPFIFAUTHKEY:                /* 16 */
+      *var_len = 0;
+      return (u_char *) OSPF_IF_PARAM (oi, auth_simple);
+      break;
+    case OSPFIFSTATUS:         /* 17 */
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    case OSPFIFMULTICASTFORWARDING: /* 18 */
+#define ospf_snmp_multiforward_blocked    1
+#define ospf_snmp_multiforward_multicast  2
+#define ospf_snmp_multiforward_unicast    3
+      return SNMP_INTEGER (ospf_snmp_multiforward_blocked);
+      break;
+    case OSPFIFDEMAND:         /* 19 */
+      return SNMP_INTEGER (SNMP_FALSE);
+      break;
+    case OSPFIFAUTHTYPE:       /* 20 */
+      if (oi->area)
+       return SNMP_INTEGER (oi->area->auth_type);
+      else
+       return SNMP_INTEGER (0);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+#define OSPF_SNMP_METRIC_VALUE 1
+
+struct interface *
+ospfIfMetricLookup (struct variable *v, oid *name, size_t *length,
+                   struct in_addr *ifaddr, unsigned int *ifindex, int exact)
+{
+  int len;
+  int ifaddr_next = 0;
+  int ifindex_next = 0;
+  struct interface *ifp;
+  oid *offset;
+  int metric;
+
+  if (exact)
+    {
+      if (*length != v->namelen + IN_ADDR_SIZE + 1 + 1)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr);
+      *ifindex = name[v->namelen + IN_ADDR_SIZE];
+      metric = name[v->namelen + IN_ADDR_SIZE + 1];
+
+      if (metric != OSPF_SNMP_METRIC_VALUE)
+       return NULL;
+
+      return ospf_snmp_if_lookup (ifaddr, ifindex);
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len >= IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+      else
+       ifaddr_next = 1;
+
+      oid2in_addr (name + v->namelen, len, ifaddr);
+
+      len = *length - v->namelen - IN_ADDR_SIZE;
+      if (len >= 1)
+       len = 1;
+      else
+       ifindex_next = 1;
+
+      if (len == 1)
+       *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+      ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
+                                     ifindex_next);
+      if (ifp)
+       {
+         *length = v->namelen + IN_ADDR_SIZE + 1 + 1;
+         offset = name + v->namelen;
+         oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE);
+         offset += IN_ADDR_SIZE;
+         *offset = *ifindex;
+         offset++;
+         *offset = OSPF_SNMP_METRIC_VALUE;
+         return ifp;
+       }
+    }
+  return NULL;
+}
+
+static u_char *
+ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact,
+                  size_t *var_len, WriteMethod **write_method)
+{
+  /* Currently we support metric 1 only. */
+  struct interface *ifp;
+  unsigned int ifindex;
+  struct in_addr ifaddr;
+  struct ospf_interface *oi;
+
+  ifindex = 0;
+  memset (&ifaddr, 0, sizeof (struct in_addr));
+
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  ifp = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact);
+  if (ifp == NULL)
+    return NULL;
+
+  oi = ospf_if_lookup_by_local_addr (ifp, ifaddr);
+  if (oi == NULL)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFIFMETRICIPADDRESS:
+      return SNMP_IPADDRESS (ifaddr);
+      break;
+    case OSPFIFMETRICADDRESSLESSIF:
+      return SNMP_INTEGER (ifindex);
+      break;
+    case OSPFIFMETRICTOS:
+      return SNMP_INTEGER (0);
+      break;
+    case OSPFIFMETRICVALUE:
+      return SNMP_INTEGER (OSPF_SNMP_METRIC_VALUE);
+      break;
+    case OSPFIFMETRICSTATUS:
+      return SNMP_INTEGER (1);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+struct route_table *ospf_snmp_vl_table;
+
+void
+ospf_snmp_vl_add (struct ospf_vl_data *vl_data)
+{
+  struct prefix_ls lp;
+  struct route_node *rn;
+
+  memset (&lp, 0, sizeof (struct prefix_ls));
+  lp.family = 0;
+  lp.prefixlen = 64;
+  lp.id = vl_data->vl_area_id;
+  lp.adv_router = vl_data->vl_peer;
+
+  rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp);
+  rn->info = vl_data;
+}
+
+void
+ospf_snmp_vl_delete (struct ospf_vl_data *vl_data)
+{
+  struct prefix_ls lp;
+  struct route_node *rn;
+
+  memset (&lp, 0, sizeof (struct prefix_ls));
+  lp.family = 0;
+  lp.prefixlen = 64;
+  lp.id = vl_data->vl_area_id;
+  lp.adv_router = vl_data->vl_peer;
+
+  rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp);
+  if (! rn)
+    return;
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+}
+
+struct ospf_vl_data *
+ospf_snmp_vl_lookup (struct in_addr *area_id, struct in_addr *neighbor)
+{
+  struct prefix_ls lp;
+  struct route_node *rn;
+  struct ospf_vl_data *vl_data;
+
+  memset (&lp, 0, sizeof (struct prefix_ls));
+  lp.family = 0;
+  lp.prefixlen = 64;
+  lp.id = *area_id;
+  lp.adv_router = *neighbor;
+
+  rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp);
+  if (rn)
+    {
+      vl_data = rn->info;
+      route_unlock_node (rn);
+      return vl_data;
+    }
+  return NULL;
+}
+
+struct ospf_vl_data *
+ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor,
+                         int first)
+{
+  struct prefix_ls lp;
+  struct route_node *rn;
+  struct ospf_vl_data *vl_data;
+
+  memset (&lp, 0, sizeof (struct prefix_ls));
+  lp.family = 0;
+  lp.prefixlen = 64;
+  lp.id = *area_id;
+  lp.adv_router = *neighbor;
+
+  if (first)
+    rn = route_top (ospf_snmp_vl_table);
+  else
+    {
+      rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp);
+      rn = route_next (rn);
+    }
+
+  for (; rn; rn = route_next (rn))
+    if (rn->info)
+      break;
+
+  if (rn && rn->info)
+    {
+      vl_data = rn->info;
+      *area_id = vl_data->vl_area_id;
+      *neighbor = vl_data->vl_peer;
+      route_unlock_node (rn);
+      return vl_data;
+    }
+  return NULL;
+}
+
+struct ospf_vl_data *
+ospfVirtIfLookup (struct variable *v, oid *name, size_t *length,
+                 struct in_addr *area_id, struct in_addr *neighbor, int exact)
+{
+  int first;
+  int len;
+  struct ospf_vl_data *vl_data;
+
+  if (exact)
+    {
+      if (*length != v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, area_id);
+      oid2in_addr (name + v->namelen + IN_ADDR_SIZE, IN_ADDR_SIZE, neighbor);
+
+      return ospf_snmp_vl_lookup (area_id, neighbor);
+    }
+  else
+    {
+      first = 0;
+
+      len = *length - v->namelen;
+      if (len <= 0)
+       first = 1;
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+      oid2in_addr (name + v->namelen, len, area_id);
+
+      len = *length - v->namelen - IN_ADDR_SIZE;
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+      oid2in_addr (name + v->namelen + IN_ADDR_SIZE, len, neighbor);
+
+      vl_data = ospf_snmp_vl_lookup_next (area_id, neighbor, first);
+
+      if (vl_data)
+       {
+         *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE;
+         oid_copy_addr (name + v->namelen, area_id, IN_ADDR_SIZE);
+         oid_copy_addr (name + v->namelen + IN_ADDR_SIZE, neighbor,
+                        IN_ADDR_SIZE);
+         return vl_data;
+       }
+    }
+  return NULL;
+}
+
+static u_char *
+ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact,
+                size_t  *var_len, WriteMethod **write_method)
+{
+  struct ospf_vl_data *vl_data;
+  struct ospf_interface *oi;
+  struct in_addr area_id;
+  struct in_addr neighbor;
+
+  memset (&area_id, 0, sizeof (struct in_addr));
+  memset (&neighbor, 0, sizeof (struct in_addr));
+
+  vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact);
+  if (! vl_data)
+    return NULL;
+  oi = vl_data->vl_oi;
+  if (! oi)
+    return NULL;
+  
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFVIRTIFAREAID:
+      return SNMP_IPADDRESS (area_id);
+      break;
+    case OSPFVIRTIFNEIGHBOR:
+      return SNMP_IPADDRESS (neighbor);
+      break;
+    case OSPFVIRTIFTRANSITDELAY:
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay));
+      break;
+    case OSPFVIRTIFRETRANSINTERVAL:
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval));
+      break;
+    case OSPFVIRTIFHELLOINTERVAL:
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello));
+      break;
+    case OSPFVIRTIFRTRDEADINTERVAL:
+      return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait));
+      break;
+    case OSPFVIRTIFSTATE:
+      return SNMP_INTEGER (oi->state);
+      break;
+    case OSPFVIRTIFEVENTS:
+      return SNMP_INTEGER (oi->state_change);
+      break;
+    case OSPFVIRTIFAUTHKEY:
+      *var_len = 0;
+      return (u_char *) OSPF_IF_PARAM (oi, auth_simple);
+      break;
+    case OSPFVIRTIFSTATUS:
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    case OSPFVIRTIFAUTHTYPE:
+      if (oi->area)
+       return SNMP_INTEGER (oi->area->auth_type);
+      else
+       return SNMP_INTEGER (0);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+struct ospf_neighbor *
+ospf_snmp_nbr_lookup (struct in_addr *nbr_addr, unsigned int *ifindex)
+{
+  struct listnode *nn;
+  struct ospf_interface *oi;
+  struct ospf_neighbor *nbr;
+  struct route_node *rn;
+
+  LIST_LOOP (ospf_top->oiflist, oi, nn)
+    {
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info) != NULL
+           && nbr != oi->nbr_self
+           && nbr->state != NSM_Down
+           && nbr->src.s_addr != 0)
+         {
+           if (IPV4_ADDR_SAME (&nbr->src, nbr_addr))
+             {
+               route_unlock_node (rn);
+               return nbr;
+             }
+         }
+    }
+  return NULL;
+}
+
+struct ospf_neighbor *
+ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex,
+                          int first)
+{
+  struct listnode *nn;
+  struct ospf_interface *oi;
+  struct ospf_neighbor *nbr;
+  struct route_node *rn;
+  struct ospf_neighbor *min = NULL;
+
+  LIST_LOOP (ospf_top->oiflist, oi, nn)
+    {
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info) != NULL
+           && nbr != oi->nbr_self
+           && nbr->state != NSM_Down
+           && nbr->src.s_addr != 0)
+         {
+           if (first)
+             {
+               if (! min)
+                 min = nbr;
+               else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
+                 min = nbr;
+             }
+           else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr))
+             {
+               if (! min)
+                 min = nbr;
+               else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
+                 min = nbr;
+             }
+         }
+    }
+  if (min)
+    {
+      *nbr_addr = min->src;
+      *ifindex = 0;
+      return min;
+    }
+  return NULL;
+}
+
+struct ospf_neighbor *
+ospfNbrLookup (struct variable *v, oid *name, size_t *length,
+              struct in_addr *nbr_addr, unsigned int *ifindex, int exact)
+{
+  int len;
+  int first;
+  struct ospf_neighbor *nbr;
+
+  if (exact)
+    {
+      if (*length != v->namelen + IN_ADDR_SIZE + 1)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr);
+      *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+      return ospf_snmp_nbr_lookup (nbr_addr, ifindex);
+    }
+  else
+    {
+      first = 0;
+      len = *length - v->namelen;
+
+      if (len <= 0)
+       first = 1;
+
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+
+      oid2in_addr (name + v->namelen, len, nbr_addr);
+
+      len = *length - v->namelen - IN_ADDR_SIZE;
+      if (len >= 1)
+       *ifindex = name[v->namelen + IN_ADDR_SIZE];
+      
+      nbr = ospf_snmp_nbr_lookup_next (nbr_addr, ifindex, first);
+
+      if (nbr)
+       {
+         *length = v->namelen + IN_ADDR_SIZE + 1;
+         oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE);
+         name[v->namelen + IN_ADDR_SIZE] = *ifindex;
+         return nbr;
+       }
+    }
+  return NULL;
+}
+
+static u_char *
+ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact,
+             size_t  *var_len, WriteMethod **write_method)
+{
+  struct in_addr nbr_addr;
+  unsigned int ifindex;
+  struct ospf_neighbor *nbr;
+  struct ospf_interface *oi;
+
+  memset (&nbr_addr, 0, sizeof (struct in_addr));
+  ifindex = 0;
+  
+  nbr = ospfNbrLookup (v, name, length, &nbr_addr, &ifindex, exact);
+  if (! nbr)
+    return NULL;
+  oi = nbr->oi;
+  if (! oi)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFNBRIPADDR:
+      return SNMP_IPADDRESS (nbr_addr);
+      break;
+    case OSPFNBRADDRESSLESSINDEX:
+      return SNMP_INTEGER (ifindex);
+      break;
+    case OSPFNBRRTRID:
+      return SNMP_IPADDRESS (nbr->router_id);
+      break;
+    case OSPFNBROPTIONS:
+      return SNMP_INTEGER (oi->nbr_self->options);
+      break;
+    case OSPFNBRPRIORITY:
+      return SNMP_INTEGER (nbr->priority);
+      break;
+    case OSPFNBRSTATE:
+      return SNMP_INTEGER (nbr->state);
+      break;
+    case OSPFNBREVENTS:
+      return SNMP_INTEGER (nbr->state_change);
+      break;
+    case OSPFNBRLSRETRANSQLEN:
+      return SNMP_INTEGER (ospf_ls_retransmit_count (nbr));
+      break;
+    case OSPFNBMANBRSTATUS:
+      return SNMP_INTEGER (SNMP_VALID);
+      break;
+    case OSPFNBMANBRPERMANENCE:
+      return SNMP_INTEGER (2);
+      break;
+    case OSPFNBRHELLOSUPPRESSED:
+      return SNMP_INTEGER (SNMP_FALSE);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+static u_char *
+ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact,
+                 size_t  *var_len, WriteMethod **write_method)
+{
+  struct ospf_vl_data *vl_data;
+  struct in_addr area_id;
+  struct in_addr neighbor;
+
+  memset (&area_id, 0, sizeof (struct in_addr));
+  memset (&neighbor, 0, sizeof (struct in_addr));
+
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact);
+  if (! vl_data)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFVIRTNBRAREA:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBRRTRID:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBRIPADDR:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBROPTIONS:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBRSTATE:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBREVENTS:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBRLSRETRANSQLEN:
+      return (u_char *) NULL;
+      break;
+    case OSPFVIRTNBRHELLOSUPPRESSED:
+      return (u_char *) NULL;
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+struct ospf_lsa *
+ospfExtLsdbLookup (struct variable *v, oid *name, size_t *length, u_char *type,
+                  struct in_addr *ls_id, struct in_addr *router_id, int exact)
+{
+  int first;
+  oid *offset;
+  int offsetlen;
+  u_char lsa_type;
+  int len;
+  struct ospf_lsa *lsa;
+
+  if (exact)
+    {
+      if (*length != v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE)
+       return NULL;
+      
+      offset = name + v->namelen;
+
+      /* Make it sure given value match to type. */
+      lsa_type = *offset;
+      offset++;
+
+      if (lsa_type != *type)
+       return NULL;
+      
+      /* LS ID. */
+      oid2in_addr (offset, IN_ADDR_SIZE, ls_id);
+      offset += IN_ADDR_SIZE;
+
+      /* Router ID. */
+      oid2in_addr (offset, IN_ADDR_SIZE, router_id);
+
+      return ospf_lsdb_lookup_by_id (ospf_top->lsdb, *type, *ls_id, *router_id);
+    }
+  else
+    {
+      /* Get variable length. */
+      first = 0;
+      offset = name + v->namelen;
+      offsetlen = *length - v->namelen;
+
+      /* LSA type value. */
+      lsa_type = *offset;
+      offset++;
+      offsetlen--;
+
+      if (offsetlen <= 0 || lsa_type < OSPF_AS_EXTERNAL_LSA)
+       first = 1;
+
+      /* LS ID. */
+      len = offsetlen;
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+
+      oid2in_addr (offset, len, ls_id);
+
+      offset += IN_ADDR_SIZE;
+      offsetlen -= IN_ADDR_SIZE;
+
+      /* Router ID. */
+      len = offsetlen;
+      if (len > IN_ADDR_SIZE)
+       len = IN_ADDR_SIZE;
+
+      oid2in_addr (offset, len, router_id);
+
+      lsa = ospf_lsdb_lookup_by_id_next (ospf_top->lsdb, *type, *ls_id,
+                                       *router_id, first);
+
+      if (lsa)
+       {
+         /* Fill in length. */
+         *length = v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE;
+
+         /* Fill in value. */
+         offset = name + v->namelen;
+
+         *offset = OSPF_AS_EXTERNAL_LSA;
+         offset++;
+         oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE);
+         offset += IN_ADDR_SIZE;
+         oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE);
+           
+         return lsa;
+       }
+    }
+  return NULL;
+}
+
+static u_char *
+ospfExtLsdbEntry (struct variable *v, oid *name, size_t *length, int exact,
+                 size_t  *var_len, WriteMethod **write_method)
+{
+  struct ospf_lsa *lsa;
+  struct lsa_header *lsah;
+  u_char type;
+  struct in_addr ls_id;
+  struct in_addr router_id;
+
+  type = OSPF_AS_EXTERNAL_LSA;
+  memset (&ls_id, 0, sizeof (struct in_addr));
+  memset (&router_id, 0, sizeof (struct in_addr));
+
+  /* Check OSPF instance. */
+  if (! ospf_top)
+    return NULL;
+
+  lsa = ospfExtLsdbLookup (v, name, length, &type, &ls_id, &router_id, exact);
+  if (! lsa)
+    return NULL;
+
+  lsah = lsa->data;
+
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFEXTLSDBTYPE:
+      return SNMP_INTEGER (OSPF_AS_EXTERNAL_LSA);
+      break;
+    case OSPFEXTLSDBLSID:
+      return SNMP_IPADDRESS (lsah->id);
+      break;
+    case OSPFEXTLSDBROUTERID:
+      return SNMP_IPADDRESS (lsah->adv_router);
+      break;
+    case OSPFEXTLSDBSEQUENCE:
+      return SNMP_INTEGER (lsah->ls_seqnum);
+      break;
+    case OSPFEXTLSDBAGE:
+      return SNMP_INTEGER (lsah->ls_age);
+      break;
+    case OSPFEXTLSDBCHECKSUM:
+      return SNMP_INTEGER (lsah->checksum);
+      break;
+    case OSPFEXTLSDBADVERTISEMENT:
+      *var_len = ntohs (lsah->length);
+      return (u_char *) lsah;
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+static u_char *
+ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length,
+                       int exact, size_t *var_len, WriteMethod **write_method)
+{
+  /* Return the current value of the variable */
+  switch (v->magic) 
+    {
+    case OSPFAREAAGGREGATEAREAID:
+      return (u_char *) NULL;
+      break;
+    case OSPFAREAAGGREGATELSDBTYPE:
+      return (u_char *) NULL;
+      break;
+    case OSPFAREAAGGREGATENET:
+      return (u_char *) NULL;
+      break;
+    case OSPFAREAAGGREGATEMASK:
+      return (u_char *) NULL;
+      break;
+    case OSPFAREAAGGREGATESTATUS:
+      return (u_char *) NULL;
+      break;
+    case OSPFAREAAGGREGATEEFFECT:
+      return (u_char *) NULL;
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+\f
+/* Register OSPF2-MIB. */
+void
+ospf_snmp_init ()
+{
+  ospf_snmp_iflist = list_new ();
+  ospf_snmp_vl_table = route_table_init ();
+  smux_init (ospfd_oid, sizeof (ospfd_oid) / sizeof (oid));
+  REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid);
+  smux_start ();
+}
+#endif /* HAVE_SNMP */
diff --git a/ospfd/ospf_snmp.h b/ospfd/ospf_snmp.h
new file mode 100644 (file)
index 0000000..d82f87b
--- /dev/null
@@ -0,0 +1,33 @@
+/* OSPFv2 SNMP support
+ * Copyright (C) 2000 IP Infusion Inc.
+ *
+ * Written by 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.  
+ */
+
+#ifndef _ZEBRA_OSPF_SNMP_H
+#define _ZEBRA_OSPF_SNMP_H
+
+void ospf_snmp_if_update (struct interface *);
+void ospf_snmp_if_delete (struct interface *);
+
+void ospf_snmp_vl_add (struct ospf_vl_data *);
+void ospf_snmp_vl_delete (struct ospf_vl_data *);
+
+#endif /* _ZEBRA_OSPF_SNMP_H */
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
new file mode 100644 (file)
index 0000000..d625471
--- /dev/null
@@ -0,0 +1,1088 @@
+/* OSPF SPF calculation.
+   Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "log.h"
+#include "sockunion.h"          /* for inet_ntop () */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ia.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_dump.h"
+
+#define DEBUG
+
+struct vertex_nexthop *
+vertex_nexthop_new (struct vertex *parent)
+{
+  struct vertex_nexthop *new;
+
+  new = XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop));
+  new->parent = parent;
+
+  return new;
+}
+
+void
+vertex_nexthop_free (struct vertex_nexthop *nh)
+{
+  XFREE (MTYPE_OSPF_NEXTHOP, nh);
+}
+
+struct vertex_nexthop *
+vertex_nexthop_dup (struct vertex_nexthop *nh)
+{
+  struct vertex_nexthop *new;
+
+  new = vertex_nexthop_new (nh->parent);
+
+  new->oi = nh->oi;
+  new->router = nh->router;
+
+  return new;
+}
+
+\f
+struct vertex *
+ospf_vertex_new (struct ospf_lsa *lsa)
+{
+  struct vertex *new;
+
+  new = XMALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex));
+  memset (new, 0, sizeof (struct vertex));
+
+  new->flags = 0;
+  new->type = lsa->data->type;
+  new->id = lsa->data->id;
+  new->lsa = lsa->data;
+  new->distance = 0;
+  new->child = list_new ();
+  new->nexthop = list_new ();
+
+  return new;
+}
+
+void
+ospf_vertex_free (struct vertex *v)
+{
+  listnode node;
+
+  list_delete (v->child);
+
+  if (listcount (v->nexthop) > 0)
+    for (node = listhead (v->nexthop); node; nextnode (node))
+      vertex_nexthop_free (node->data);
+
+  list_delete (v->nexthop);
+
+  XFREE (MTYPE_OSPF_VERTEX, v);
+}
+
+void
+ospf_vertex_add_parent (struct vertex *v)
+{
+  struct vertex_nexthop *nh;
+  listnode node;
+
+  for (node = listhead (v->nexthop); node; nextnode (node))
+    {
+      nh = (struct vertex_nexthop *) getdata (node);
+
+      /* No need to add two links from the same parent. */
+      if (listnode_lookup (nh->parent->child, v) == NULL)
+       listnode_add (nh->parent->child, v);
+    }
+}
+\f
+void
+ospf_spf_init (struct ospf_area *area)
+{
+  struct vertex *v;
+
+  /* Create root node. */
+  v = ospf_vertex_new (area->router_lsa_self);
+
+  area->spf = v;
+
+  /* Reset ABR and ASBR router counts. */
+  area->abr_count = 0;
+  area->asbr_count = 0;
+}
+
+int
+ospf_spf_has_vertex (struct route_table *rv, struct route_table *nv,
+                     struct lsa_header *lsa)
+{
+  struct prefix p;
+  struct route_node *rn;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.u.prefix4 = lsa->id;
+
+  if (lsa->type == OSPF_ROUTER_LSA)
+    rn = route_node_get (rv, &p);
+  else
+    rn = route_node_get (nv, &p);
+
+  if (rn->info != NULL)
+    {
+      route_unlock_node (rn);
+      return 1;
+    }
+  return 0;
+}
+
+listnode
+ospf_vertex_lookup (list vlist, struct in_addr id, int type)
+{
+  listnode node;
+  struct vertex *v;
+
+  for (node = listhead (vlist); node; nextnode (node))
+    {
+      v = (struct vertex *) getdata (node);
+      if (IPV4_ADDR_SAME (&id, &v->id) && type == v->type)
+        return node;
+    }
+
+  return NULL;
+}
+
+int
+ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v)
+{
+  int i;
+  int length;
+  struct router_lsa *rl;
+  struct network_lsa *nl;
+
+  /* In case of W is Network LSA. */
+  if (w->type == OSPF_NETWORK_LSA)
+    {
+      if (v->type == OSPF_NETWORK_LSA)
+        return 0;
+
+      nl = (struct network_lsa *) w;
+      length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
+      
+      for (i = 0; i < length; i++)
+        if (IPV4_ADDR_SAME (&nl->routers[i], &v->id))
+          return 1;
+      return 0;
+    }
+
+  /* In case of W is Router LSA. */
+  if (w->type == OSPF_ROUTER_LSA)
+    {
+      rl = (struct router_lsa *) w;
+
+      length = ntohs (w->length);
+
+      for (i = 0;
+          i < ntohs (rl->links) && length >= sizeof (struct router_lsa);
+          i++, length -= 12)
+        {
+          switch (rl->link[i].type)
+            {
+            case LSA_LINK_TYPE_POINTOPOINT:
+            case LSA_LINK_TYPE_VIRTUALLINK:
+              /* Router LSA ID. */
+              if (v->type == OSPF_ROUTER_LSA &&
+                  IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
+                {
+                  return 1;
+                }
+              break;
+            case LSA_LINK_TYPE_TRANSIT:
+              /* Network LSA ID. */
+              if (v->type == OSPF_NETWORK_LSA &&
+                  IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
+                {
+                  return 1;
+               }
+              break;
+            case LSA_LINK_TYPE_STUB:
+              /* Not take into count? */
+              continue;
+            default:
+              break;
+            }
+        }
+    }
+  return 0;
+}
+
+/* Add the nexthop to the list, only if it is unique.
+ * If it's not unique, free the nexthop entry.
+ */
+void
+ospf_nexthop_add_unique (struct vertex_nexthop *new, list nexthop)
+{
+  struct vertex_nexthop *nh;
+  listnode node;
+  int match;
+
+  match = 0;
+  for (node = listhead (nexthop); node; nextnode (node))
+    {
+      nh = node->data;
+
+      /* Compare the two entries. */
+      /* XXX
+       * Comparing the parent preserves the shortest path tree
+       * structure even when the nexthops are identical.
+       */
+      if (nh->oi == new->oi &&
+         IPV4_ADDR_SAME (&nh->router, &new->router) &&
+         nh->parent == new->parent)
+       {
+         match = 1;
+         break;
+       }
+    }
+
+  if (!match)
+    listnode_add (nexthop, new);
+  else
+    vertex_nexthop_free (new);
+}
+
+/* Merge entries in list b into list a. */
+void
+ospf_nexthop_merge (list a, list b)
+{
+  struct listnode *n;
+
+  for (n = listhead (b); n; nextnode (n))
+    {
+      ospf_nexthop_add_unique (n->data, a);
+    }
+}
+
+#define ROUTER_LSA_MIN_SIZE 12
+#define ROUTER_LSA_TOS_SIZE 4
+
+struct router_lsa_link *
+ospf_get_next_link (struct vertex *v, struct vertex *w,
+                   struct router_lsa_link *prev_link)
+{
+  u_char *p;
+  u_char *lim;
+  struct router_lsa_link *l;
+
+  if (prev_link == NULL)
+    p = ((u_char *) v->lsa) + 24;
+  else
+    {
+      p = (u_char *)prev_link;
+      p += (ROUTER_LSA_MIN_SIZE +
+            (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
+    }
+  
+  lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
+
+  while (p < lim)
+    {
+      l = (struct router_lsa_link *) p;
+
+      p += (ROUTER_LSA_MIN_SIZE +
+            (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
+
+      if (l->m[0].type == LSA_LINK_TYPE_STUB)
+        continue;
+
+      /* Defer NH calculation via VLs until summaries from
+         transit areas area confidered             */
+
+      if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
+        continue; 
+
+      if (IPV4_ADDR_SAME (&l->link_id, &w->id))
+          return l;
+    }
+
+  return NULL;
+}
+
+/* Calculate nexthop from root to vertex W. */
+void
+ospf_nexthop_calculation (struct ospf_area *area,
+                          struct vertex *v, struct vertex *w)
+{
+  listnode node;
+  struct vertex_nexthop *nh, *x;
+  struct ospf_interface *oi = NULL;
+  struct router_lsa_link *l = NULL;
+         
+    
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_nexthop_calculation(): Start");
+
+  /* W's parent is root. */
+  if (v == area->spf)
+    {
+      if (w->type == OSPF_VERTEX_ROUTER)
+       {
+         while ((l = ospf_get_next_link (v, w, l)))
+           {
+             struct router_lsa_link *l2 = NULL;
+             
+             if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
+               {
+                 while ((l2 = ospf_get_next_link (w, v, l2)))
+                   {
+                     oi = ospf_if_is_configured (&(l2->link_data));
+                     
+                     if (oi == NULL)
+                       continue;
+                     
+                     if (! IPV4_ADDR_SAME (&oi->address->u.prefix4,
+                                           &l->link_data))
+                       continue;
+                     
+                     break;
+                   }
+                 
+                 if (oi && l2)
+                   {
+                     nh = vertex_nexthop_new (v);
+                     nh->oi = oi;
+                     nh->router = l2->link_data;
+                     listnode_add (w->nexthop, nh);
+                   }
+               }
+           }
+       }
+      else
+       {
+         while ((l = ospf_get_next_link (v, w, l)))
+           {
+             oi = ospf_if_is_configured (&(l->link_data));
+             if (oi)
+               {
+                 nh = vertex_nexthop_new (v);
+                 nh->oi = oi;
+                 nh->router.s_addr = 0;
+                 listnode_add (w->nexthop, nh);
+               }
+           }
+       }
+      return;
+    }
+  /* In case of W's parent is network connected to root. */
+  else if (v->type == OSPF_VERTEX_NETWORK)
+    {
+      for (node = listhead (v->nexthop); node; nextnode (node))
+        {
+          x = (struct vertex_nexthop *) getdata (node);
+          if (x->parent == area->spf)
+            {
+             while ((l = ospf_get_next_link (w, v, l)))
+               {
+                 nh = vertex_nexthop_new (v);
+                 nh->oi = x->oi;
+                 nh->router = l->link_data;
+                 listnode_add (w->nexthop, nh);
+               }
+             return;
+           }
+        }
+    }
+
+  /* Inherit V's nexthop. */
+  for (node = listhead (v->nexthop); node; nextnode (node))
+    {
+      nh = vertex_nexthop_dup (node->data);
+      nh->parent = v;
+      ospf_nexthop_add_unique (nh, w->nexthop);
+    }
+}
+
+void
+ospf_install_candidate (list candidate, struct vertex *w)
+{
+  listnode node;
+  struct vertex *cw;
+
+  if (list_isempty (candidate))
+    {
+      listnode_add (candidate, w);
+      return;
+    }
+
+  /* Install vertex with sorting by distance. */
+  for (node = listhead (candidate); node; nextnode (node))
+    {
+      cw = (struct vertex *) getdata (node);
+      if (cw->distance > w->distance)
+        {
+          list_add_node_prev (candidate, node, w);
+          break;
+        }
+      else if (node->next == NULL)
+        {
+          list_add_node_next (candidate, node, w);
+          break;
+        }
+    }
+}
+
+/* RFC2328 Section 16.1 (2). */
+void
+ospf_spf_next (struct vertex *v, struct ospf_area *area,
+               list candidate, struct route_table *rv,
+               struct route_table *nv)
+{
+  struct ospf_lsa *w_lsa = NULL;
+  struct vertex *w, *cw;
+  u_char *p;
+  u_char *lim;
+  struct router_lsa_link *l = NULL;
+  struct in_addr *r;
+  listnode node;
+  int type = 0;
+
+  /* If this is a router-LSA, and bit V of the router-LSA (see Section
+     A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE.  */
+  if (v->type == OSPF_VERTEX_ROUTER)
+    {
+      if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa))
+        area->transit = OSPF_TRANSIT_TRUE;
+    }
+
+  p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
+  lim =  ((u_char *) v->lsa) + ntohs (v->lsa->length);
+    
+  while (p < lim)
+    {
+      /* In case of V is Router-LSA. */
+      if (v->lsa->type == OSPF_ROUTER_LSA)
+        {
+          l = (struct router_lsa_link *) p;
+
+          p += (ROUTER_LSA_MIN_SIZE + 
+                (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
+
+          /* (a) If this is a link to a stub network, examine the next
+             link in V's LSA.  Links to stub networks will be
+             considered in the second stage of the shortest path
+             calculation. */
+          if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
+            continue;
+
+          /* (b) Otherwise, W is a transit vertex (router or transit
+             network).  Look up the vertex W's LSA (router-LSA or
+             network-LSA) in Area A's link state database. */
+          switch (type)
+            {
+            case LSA_LINK_TYPE_POINTOPOINT:
+            case LSA_LINK_TYPE_VIRTUALLINK:
+              if (type == LSA_LINK_TYPE_VIRTUALLINK)
+               {
+                 if (IS_DEBUG_OSPF_EVENT)
+                   zlog_info ("looking up LSA through VL: %s",
+                              inet_ntoa (l->link_id));
+               }
+
+              w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id,
+                                       l->link_id);
+              if (w_lsa)
+               {
+                 if (IS_DEBUG_OSPF_EVENT)
+                 zlog_info("found the LSA");
+               }
+              break;
+            case LSA_LINK_TYPE_TRANSIT:
+                 if (IS_DEBUG_OSPF_EVENT)
+
+              zlog_info ("Looking up Network LSA, ID: %s",
+                         inet_ntoa(l->link_id));
+              w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA,
+                                            l->link_id);
+              if (w_lsa)
+                 if (IS_DEBUG_OSPF_EVENT)
+                zlog_info("found the LSA");
+              break;
+            default:
+             zlog_warn ("Invalid LSA link type %d", type);
+              continue;
+            }
+        }
+      else
+        {
+          /* In case of V is Network-LSA. */
+          r = (struct in_addr *) p ;
+          p += sizeof (struct in_addr);
+
+          /* Lookup the vertex W's LSA. */
+          w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r);
+        }
+
+      /* (b cont.) If the LSA does not exist, or its LS age is equal
+         to MaxAge, or it does not have a link back to vertex V,
+         examine the next link in V's LSA.[23] */
+      if (w_lsa == NULL)
+        continue;
+
+      if (IS_LSA_MAXAGE (w_lsa))
+        continue;
+
+      if (! ospf_lsa_has_link (w_lsa->data, v->lsa))
+        {
+                 if (IS_DEBUG_OSPF_EVENT)
+         zlog_info ("The LSA doesn't have a link back");
+          continue;
+        }
+
+      /* (c) If vertex W is already on the shortest-path tree, examine
+         the next link in the LSA. */
+      if (ospf_spf_has_vertex (rv, nv, w_lsa->data))
+        {
+                 if (IS_DEBUG_OSPF_EVENT)
+          zlog_info ("The LSA is already in SPF");
+          continue;
+        }
+
+      /* (d) Calculate the link state cost D of the resulting path
+         from the root to vertex W.  D is equal to the sum of the link
+         state cost of the (already calculated) shortest path to
+         vertex V and the advertised cost of the link between vertices
+         V and W.  If D is: */
+
+      /* prepare vertex W. */
+      w = ospf_vertex_new (w_lsa);
+
+      /* calculate link cost D. */
+      if (v->lsa->type == OSPF_ROUTER_LSA)
+        w->distance = v->distance + ntohs (l->m[0].metric);
+      else
+        w->distance = v->distance;
+
+      /* Is there already vertex W in candidate list? */
+      node = ospf_vertex_lookup (candidate, w->id, w->type);
+      if (node == NULL)
+        {
+          /* Calculate nexthop to W. */
+          ospf_nexthop_calculation (area, v, w);
+
+          ospf_install_candidate (candidate, w);
+        }
+      else
+        {
+          cw = (struct vertex *) getdata (node);
+
+          /* if D is greater than. */
+          if (cw->distance < w->distance)
+            {
+              ospf_vertex_free (w);
+              continue;
+            }
+          /* equal to. */
+          else if (cw->distance == w->distance)
+            {
+              /* Calculate nexthop to W. */
+              ospf_nexthop_calculation (area, v, w);
+              ospf_nexthop_merge (cw->nexthop, w->nexthop);
+              list_delete_all_node (w->nexthop);
+              ospf_vertex_free (w);
+            }
+          /* less than. */
+          else
+            {
+              /* Calculate nexthop. */
+              ospf_nexthop_calculation (area, v, w);
+
+              /* Remove old vertex from candidate list. */
+              ospf_vertex_free (cw);
+              listnode_delete (candidate, cw);
+
+              /* Install new to candidate. */
+              ospf_install_candidate (candidate, w);
+            }
+        }
+    }
+}
+
+/* Add vertex V to SPF tree. */
+void
+ospf_spf_register (struct vertex *v, struct route_table *rv,
+                  struct route_table *nv)
+{
+  struct prefix p;
+  struct route_node *rn;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.u.prefix4 = v->id;
+
+  if (v->type == OSPF_VERTEX_ROUTER)
+    rn = route_node_get (rv, &p);
+  else
+    rn = route_node_get (nv, &p);
+
+  rn->info = v;
+}
+
+void
+ospf_spf_route_free (struct route_table *table)
+{
+  struct route_node *rn;
+  struct vertex *v;
+
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    {
+      if ((v = rn->info))
+       {
+         ospf_vertex_free (v);
+         rn->info = NULL;
+       }
+
+      route_unlock_node (rn);
+    }
+
+  route_table_finish (table);
+}
+
+void
+ospf_spf_dump (struct vertex *v, int i)
+{
+  listnode cnode;
+  listnode nnode;
+  struct vertex_nexthop *nexthop;
+
+  if (v->type == OSPF_VERTEX_ROUTER)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id));
+    }
+  else
+    {
+      struct network_lsa *lsa = (struct network_lsa *) v->lsa;
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id),
+                  ip_masklen (lsa->mask));
+
+      for (nnode = listhead (v->nexthop); nnode; nextnode (nnode))
+        {
+          nexthop = getdata (nnode);
+         if (IS_DEBUG_OSPF_EVENT)
+           zlog_info (" nexthop %s", inet_ntoa (nexthop->router));
+        }
+    }
+
+  i++;
+
+  for (cnode = listhead (v->child); cnode; nextnode (cnode))
+    {
+      v = getdata (cnode);
+      ospf_spf_dump (v, i);
+    }
+}
+
+/* Second stage of SPF calculation. */
+void
+ospf_spf_process_stubs (struct ospf_area *area, struct vertex * v,
+                        struct route_table *rt)
+{
+  listnode cnode;
+  struct vertex *child;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_process_stub():processing stubs for area %s",
+              inet_ntoa (area->area_id));
+  if (v->type == OSPF_VERTEX_ROUTER)
+    {
+      u_char *p;
+      u_char *lim;
+      struct router_lsa_link *l;
+      struct router_lsa *rlsa;
+
+  if (IS_DEBUG_OSPF_EVENT)
+      zlog_info ("ospf_process_stub():processing router LSA, id: %s",
+                 inet_ntoa (v->lsa->id));
+      rlsa = (struct router_lsa *) v->lsa;
+
+
+  if (IS_DEBUG_OSPF_EVENT)
+      zlog_info ("ospf_process_stub(): we have %d links to process",
+                 ntohs (rlsa->links));
+      p = ((u_char *) v->lsa) + 24;
+      lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
+
+      while (p < lim)
+        {
+          l = (struct router_lsa_link *) p;
+
+          p += (ROUTER_LSA_MIN_SIZE +
+                (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
+
+          if (l->m[0].type == LSA_LINK_TYPE_STUB)
+            ospf_intra_add_stub (rt, l, v, area);
+        }
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+  zlog_info ("children of V:");
+  for (cnode = listhead (v->child); cnode; nextnode (cnode))
+    {
+      child = getdata (cnode);
+  if (IS_DEBUG_OSPF_EVENT)
+      zlog_info (" child : %s", inet_ntoa (child->id));
+    }
+
+  for (cnode = listhead (v->child); cnode; nextnode (cnode))
+    {
+      child = getdata (cnode);
+
+      if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED))
+       continue;
+
+      ospf_spf_process_stubs (area, child, rt);
+
+      SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED);
+    }
+}
+
+void
+ospf_rtrs_free (struct route_table *rtrs)
+{
+  struct route_node *rn;
+  list or_list;
+  listnode node;
+
+  if (IS_DEBUG_OSPF_EVENT)
+  zlog_info ("Route: Router Routing Table free");
+
+  for (rn = route_top (rtrs); rn; rn = route_next (rn))
+    if ((or_list = rn->info) != NULL)
+      {
+       for (node = listhead (or_list); node; nextnode (node))
+         ospf_route_free (node->data);
+
+       list_delete (or_list);
+
+       /* Unlock the node. */
+       rn->info = NULL;
+       route_unlock_node (rn);
+      }
+  route_table_finish (rtrs);
+}
+
+void
+ospf_rtrs_print (struct route_table *rtrs)
+{
+  struct route_node *rn;
+  list or_list;
+  listnode ln;
+  listnode pnode;
+  struct ospf_route *or;
+  struct ospf_path *path;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_rtrs_print() start");
+
+  for (rn = route_top (rtrs); rn; rn = route_next (rn))
+    if ((or_list = rn->info) != NULL)
+      for (ln = listhead (or_list); ln; nextnode (ln))
+        {
+          or = getdata (ln);
+
+          switch (or->path_type)
+            {
+            case OSPF_PATH_INTRA_AREA:
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("%s   [%d] area: %s", 
+                          inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost,
+                          inet_ntop (AF_INET, &or->u.std.area_id,
+                                     buf2, BUFSIZ));
+              break;
+            case OSPF_PATH_INTER_AREA:
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("%s IA [%d] area: %s", 
+                          inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost,
+                          inet_ntop (AF_INET, &or->u.std.area_id,
+                                     buf2, BUFSIZ));
+              break;
+            default:
+              break;
+            }
+
+          for (pnode = listhead (or->path); pnode; nextnode (pnode))
+            {
+              path = getdata (pnode);
+              if (path->nexthop.s_addr == 0)
+               {
+                 if (IS_DEBUG_OSPF_EVENT)
+                   zlog_info ("   directly attached to %s\r\n",
+                              IF_NAME (path->oi));
+               }
+              else 
+               {
+                 if (IS_DEBUG_OSPF_EVENT)
+                   zlog_info ("   via %s, %s\r\n",
+                              inet_ntoa (path->nexthop), IF_NAME (path->oi));
+               }
+            }
+        }
+
+  zlog_info ("ospf_rtrs_print() end");
+}
+
+/* Calculating the shortest-path tree for an area. */
+void
+ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, 
+                    struct route_table *new_rtrs)
+{
+  list candidate;
+  listnode node;
+  struct vertex *v;
+  struct route_table *rv;
+  struct route_table *nv;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    {
+      zlog_info ("ospf_spf_calculate: Start");
+      zlog_info ("ospf_spf_calculate: running Dijkstra for area %s", 
+                inet_ntoa (area->area_id));
+    }
+
+  /* Check router-lsa-self.  If self-router-lsa is not yet allocated,
+     return this area's calculation. */
+  if (! area->router_lsa_self)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("ospf_spf_calculate: "
+                  "Skip area %s's calculation due to empty router_lsa_self",
+                  inet_ntoa (area->area_id));
+      return;
+    }
+
+  /* RFC2328 16.1. (1). */
+  /* Initialize the algorithm's data structures. */ 
+  rv = route_table_init ();
+  nv = route_table_init ();
+
+  /* Clear the list of candidate vertices. */ 
+  candidate = list_new ();
+
+  /* Initialize the shortest-path tree to only the root (which is the
+     router doing the calculation). */
+  ospf_spf_init (area);
+  v = area->spf;
+  ospf_spf_register (v, rv, nv);
+
+  /* Set Area A's TransitCapability to FALSE. */
+  area->transit = OSPF_TRANSIT_FALSE;
+  area->shortcut_capability = 1;
+
+  for (;;)
+    {
+      /* RFC2328 16.1. (2). */
+      ospf_spf_next (v, area, candidate, rv, nv);
+
+      /* RFC2328 16.1. (3). */
+      /* If at this step the candidate list is empty, the shortest-
+         path tree (of transit vertices) has been completely built and
+         this stage of the procedure terminates. */
+      if (listcount (candidate) == 0)
+        break;
+
+      /* Otherwise, choose the vertex belonging to the candidate list
+         that is closest to the root, and add it to the shortest-path
+         tree (removing it from the candidate list in the
+         process). */ 
+      node = listhead (candidate);
+      v = getdata (node);
+      ospf_vertex_add_parent (v);
+
+      /* Reveve from the candidate list. */
+      listnode_delete (candidate, v);
+
+      /* Add to SPF tree. */
+      ospf_spf_register (v, rv, nv);
+
+      /* Note that when there is a choice of vertices closest to the
+         root, network vertices must be chosen before router vertices
+         in order to necessarily find all equal-cost paths. */
+      /* We don't do this at this moment, we should add the treatment
+         above codes. -- kunihiro. */
+
+      /* RFC2328 16.1. (4). */
+      if (v->type == OSPF_VERTEX_ROUTER)
+        ospf_intra_add_router (new_rtrs, v, area);
+      else 
+        ospf_intra_add_transit (new_table, v, area);
+
+      /* RFC2328 16.1. (5). */
+      /* Iterate the algorithm by returning to Step 2. */
+    }
+
+  if (IS_DEBUG_OSPF_EVENT)
+    {
+      ospf_spf_dump (area->spf, 0);
+      ospf_route_table_dump (new_table);
+    }
+
+  /* Second stage of SPF calculation procedure's  */
+  ospf_spf_process_stubs (area, area->spf, new_table);
+
+  /* Free all vertices which allocated for SPF calculation */
+  ospf_spf_route_free (rv);
+  ospf_spf_route_free (nv);
+
+  /* Free candidate list */
+  list_free (candidate);
+
+  /* Increment SPF Calculation Counter. */
+  area->spf_calculation++;
+
+  ospf_top->ts_spf = time (NULL);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("ospf_spf_calculate: Stop");
+}
+\f
+/* Timer for SPF calculation. */
+int
+ospf_spf_calculate_timer (struct thread *t)
+{
+  struct route_table *new_table, *new_rtrs;
+  struct ospf *ospf;
+  /* struct ospf_area *area; */
+  listnode node;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("SPF: Timer (SPF calculation expire)");
+  
+  ospf = THREAD_ARG (t);
+  ospf->t_spf_calc = NULL;
+
+  /* Allocate new table tree. */
+  new_table = route_table_init ();
+  new_rtrs  = route_table_init ();
+
+  ospf_vl_unapprove ();
+
+  /* Calculate SPF for each area. */
+  for (node = listhead (ospf->areas); node; node = nextnode (node))
+    ospf_spf_calculate (node->data, new_table, new_rtrs);
+
+  ospf_vl_shut_unapproved ();
+
+  ospf_ia_routing (new_table, new_rtrs);
+
+  ospf_prune_unreachable_networks (new_table);
+  ospf_prune_unreachable_routers (new_rtrs);
+
+  /* AS-external-LSA calculation should not be performed here. */
+
+  /* If new Router Route is installed,
+     then schedule re-calculate External routes. */
+  if (1)
+    ospf_ase_calculate_schedule ();
+
+  ospf_ase_calculate_timer_add ();
+
+  /* Update routing table. */
+  ospf_route_install (new_table);
+
+  /* Update ABR/ASBR routing table */
+  if (ospf_top->old_rtrs)
+    {
+      /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */
+      /* ospf_route_delete (ospf_top->old_rtrs); */
+      ospf_rtrs_free (ospf_top->old_rtrs);
+    }
+
+  ospf_top->old_rtrs = ospf_top->new_rtrs;
+  ospf_top->new_rtrs = new_rtrs;
+
+  if (OSPF_IS_ABR) 
+    ospf_abr_task (new_table, new_rtrs);
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("SPF: calculation complete");
+
+  return 0;
+}
+
+/* Add schedule for SPF calculation.  To avoid frequenst SPF calc, we
+   set timer for SPF calc. */
+void
+ospf_spf_calculate_schedule ()
+{
+  time_t ht, delay;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("SPF: calculation timer scheduled");
+
+  /* OSPF instance does not exist. */
+  if (!ospf_top)
+    return;
+
+  /* SPF calculation timer is already scheduled. */
+  if (ospf_top->t_spf_calc)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("SPF: calculation timer is already scheduled: %p",
+                  ospf_top->t_spf_calc);
+      return;
+    }
+
+  ht = time (NULL) - ospf_top->ts_spf;
+
+  /* Get SPF calculation delay time. */
+  if (ht < ospf_top->spf_holdtime)
+    {
+      if (ospf_top->spf_holdtime - ht < ospf_top->spf_delay)
+       delay = ospf_top->spf_delay;
+      else
+       delay = ospf_top->spf_holdtime - ht;
+    }
+  else
+    delay = ospf_top->spf_delay;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("SPF: calculation timer delay = %ld", delay);
+  ospf_top->t_spf_calc =
+    thread_add_timer (master, ospf_spf_calculate_timer, ospf_top, delay);
+}
+
diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h
new file mode 100644 (file)
index 0000000..7fe682e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * OSPF calculation.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#define OSPF_VERTEX_ROUTER  1
+#define OSPF_VERTEX_NETWORK 2
+
+#define OSPF_VERTEX_PROCESSED      0x01
+
+
+struct vertex
+{
+  u_char flags;
+  u_char type;
+  struct in_addr id;
+  struct lsa_header *lsa;
+  u_int32_t distance;
+  list child;
+  list nexthop;
+};
+
+struct vertex_nexthop
+{
+  struct ospf_interface *oi;
+  struct in_addr router;
+  struct vertex *parent;
+};
+
+void ospf_spf_calculate_schedule ();
+void ospf_rtrs_free (struct route_table *);
+
+/* void ospf_spf_calculate_timer_add (); */
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
new file mode 100644 (file)
index 0000000..aedac32
--- /dev/null
@@ -0,0 +1,1921 @@
+/*
+ * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt
+ * Copyright (C) 2001 KDD R&D Laboratories, Inc.
+ * http://www.kddlabs.co.jp/
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/***** MTYPE definition is not reflected to "memory.h" yet. *****/
+#define MTYPE_OSPF_MPLS_TE_LINKPARAMS  0
+
+#include <zebra.h>
+
+#ifdef HAVE_OSPF_TE
+#ifndef HAVE_OPAQUE_LSA
+#error "Wrong configure option"
+#endif /* HAVE_OPAQUE_LSA */
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h"         /* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_te.h"
+
+/* Following structure are internal use only. */
+struct ospf_mpls_te
+{
+  enum { disabled, enabled } status;
+
+  /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */
+  list iflist;
+
+  /* Store Router-TLV in network byte order. */
+  struct te_tlv_router_addr router_addr;
+};
+
+struct mpls_te_link
+{
+  /*
+   * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field
+   * is subdivided into 8-bit "unused" field and 16-bit "instance" field.
+   * In this implementation, each Link-TLV has its own instance.
+   */
+  u_int32_t instance;
+
+  /* Reference pointer to a Zebra-interface. */
+  struct interface *ifp;
+
+  /* Area info in which this MPLS-TE link belongs to. */
+  struct ospf_area *area;
+
+  /* Flags to manage this link parameters. */
+  u_int32_t flags;
+#define LPFLG_LOOKUP_DONE              0x1
+#define LPFLG_LSA_ENGAGED              0x2
+#define LPFLG_LSA_FORCED_REFRESH       0x4
+
+  /* Store Link-TLV in network byte order. */
+  struct te_tlv_link link_header;
+  struct te_link_subtlv_link_type link_type;
+  struct te_link_subtlv_link_id link_id;
+  struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr;
+  struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr;
+  struct te_link_subtlv_te_metric te_metric;
+  struct te_link_subtlv_max_bw max_bw;
+  struct te_link_subtlv_max_rsv_bw max_rsv_bw;
+  struct te_link_subtlv_unrsv_bw unrsv_bw;
+  struct te_link_subtlv_rsc_clsclr rsc_clsclr;
+};
+
+/*
+ * Global variable to manage Opaque-LSA/MPLS-TE on this node.
+ * Note that all parameter values are stored in network byte order.
+ */
+static struct ospf_mpls_te OspfMplsTE;
+
+enum oifstate {
+  OI_ANY, OI_DOWN, OI_UP
+};
+
+enum sched_opcode {
+  REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA
+};
+
+/*------------------------------------------------------------------------*
+ * Followings are initialize/terminate functions for MPLS-TE handling.
+ *------------------------------------------------------------------------*/
+
+static int ospf_mpls_te_new_if (struct interface *ifp);
+static int ospf_mpls_te_del_if (struct interface *ifp);
+static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status);
+static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status);
+static void ospf_mpls_te_config_write_router (struct vty *vty);
+static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp);
+static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa);
+static int ospf_mpls_te_lsa_originate (void *arg);
+static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
+static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode);
+
+static void del_mpls_te_link (void *val);
+static void ospf_mpls_te_register_vty (void);
+
+int
+ospf_mpls_te_init (void)
+{
+  int rc;
+
+  rc = ospf_register_opaque_functab (
+                OSPF_OPAQUE_AREA_LSA,
+                OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA,
+               ospf_mpls_te_new_if,
+               ospf_mpls_te_del_if,
+               ospf_mpls_te_ism_change,
+               ospf_mpls_te_nsm_change,
+               ospf_mpls_te_config_write_router,
+               ospf_mpls_te_config_write_if,
+               NULL,/* ospf_mpls_te_config_write_debug */
+                ospf_mpls_te_show_info,
+                ospf_mpls_te_lsa_originate,
+                ospf_mpls_te_lsa_refresh,
+               NULL,/* ospf_mpls_te_new_lsa_hook */
+               NULL /* ospf_mpls_te_del_lsa_hook */);
+  if (rc != 0)
+    {
+      zlog_warn ("ospf_mpls_te_init: Failed to register functions");
+      goto out;
+    }
+
+  memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te));
+  OspfMplsTE.status = disabled;
+  OspfMplsTE.iflist = list_new ();
+  OspfMplsTE.iflist->del = del_mpls_te_link;
+
+  ospf_mpls_te_register_vty ();
+
+out:
+  return rc;
+}
+
+void
+ospf_mpls_te_term (void)
+{
+  list_delete (OspfMplsTE.iflist);
+
+  OspfMplsTE.iflist = NULL;
+  OspfMplsTE.status = disabled;
+
+  ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA,
+                              OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are control functions for MPLS-TE parameters management.
+ *------------------------------------------------------------------------*/
+
+static void
+del_mpls_te_link (void *val)
+{
+  XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val);
+  return;
+}
+
+static u_int32_t
+get_mpls_te_instance_value ()
+{
+  static u_int32_t seqno = 0;
+
+  if (LEGAL_TE_INSTANCE_RANGE (seqno + 1))
+    seqno += 1;
+  else
+    seqno  = 1; /* Avoid zero. */
+
+  return seqno;
+}
+
+static struct ospf_interface *
+lookup_oi_by_ifp (struct interface *ifp,
+                  struct ospf_area *area, enum oifstate oifstate)
+{
+  struct ospf_interface *oi = NULL;
+  struct route_node *rn;
+
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      if ((oi = rn->info) == NULL)
+        continue;
+
+      switch (oifstate)
+        {
+        case OI_ANY:
+          break;
+        case OI_DOWN:
+          if (ospf_if_is_enable (oi))
+            continue;
+          break;
+        case OI_UP:
+          if (! ospf_if_is_enable (oi))
+            continue;
+          break;
+        default:
+          zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate);
+          goto out;
+        }
+
+      if (area == NULL || oi->area == area)
+        return oi;
+    }
+out:
+  return NULL;
+}
+
+static struct mpls_te_link *
+lookup_linkparams_by_ifp (struct interface *ifp)
+{
+  listnode node;
+  struct mpls_te_link *lp;
+
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    if ((lp = getdata (node)) != NULL)
+      if (lp->ifp == ifp)
+        return lp;
+
+  return NULL;
+}
+
+static struct mpls_te_link *
+lookup_linkparams_by_instance (struct ospf_lsa *lsa)
+{
+  listnode node;
+  struct mpls_te_link *lp;
+  int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr));
+
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    if ((lp = getdata (node)) != NULL)
+      if (lp->instance == key)
+        return lp;
+
+  zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key);
+  return NULL;
+}
+
+static void
+ospf_mpls_te_foreach_area (
+  void (*func)(struct mpls_te_link *lp, enum sched_opcode),
+  enum sched_opcode sched_opcode)
+{
+  listnode node, node2;
+  struct mpls_te_link *lp;
+  struct ospf_area *area;
+
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    {
+      if ((lp = getdata (node)) == NULL)
+        continue;
+      if ((area = lp->area) == NULL)
+        continue;
+      if (lp->flags & LPFLG_LOOKUP_DONE)
+        continue;
+
+      if (func != NULL)
+        (* func)(lp, sched_opcode);
+
+      for (node2 = nextnode (node); node2; nextnode (node2))
+        if ((lp = getdata (node2)) != NULL)
+          if (lp->area != NULL)
+            if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id))
+              lp->flags |= LPFLG_LOOKUP_DONE;
+    }
+
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    if ((lp = getdata (node)) != NULL)
+      if (lp->area != NULL)
+        lp->flags &= ~LPFLG_LOOKUP_DONE;
+
+  return;
+}
+
+static void
+set_mpls_te_router_addr (struct in_addr ipv4)
+{
+  OspfMplsTE.router_addr.header.type   = htons (TE_TLV_ROUTER_ADDR);
+  OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4));
+  OspfMplsTE.router_addr.value = ipv4;
+  return;
+}
+
+static void
+set_linkparams_link_header (struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh;
+  u_int16_t length = 0;
+
+  /* TE_LINK_SUBTLV_LINK_TYPE */
+  if (ntohs (lp->link_type.header.type) != 0)
+    length += TLV_SIZE (&lp->link_type.header);
+
+  /* TE_LINK_SUBTLV_LINK_ID */
+  if (ntohs (lp->link_id.header.type) != 0)
+    length += TLV_SIZE (&lp->link_id.header);
+
+  /* TE_LINK_SUBTLV_LCLIF_IPADDR */
+  if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL
+  &&  ntohs (tlvh->type) != 0)
+    length += TLV_SIZE (tlvh);
+
+  /* TE_LINK_SUBTLV_RMTIF_IPADDR */
+  if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL
+  &&  ntohs (tlvh->type) != 0)
+    length += TLV_SIZE (tlvh);
+
+  /* TE_LINK_SUBTLV_TE_METRIC */
+  if (ntohs (lp->te_metric.header.type) != 0)
+    length += TLV_SIZE (&lp->te_metric.header);
+
+  /* TE_LINK_SUBTLV_MAX_BW */
+  if (ntohs (lp->max_bw.header.type) != 0)
+    length += TLV_SIZE (&lp->max_bw.header);
+
+  /* TE_LINK_SUBTLV_MAX_RSV_BW */
+  if (ntohs (lp->max_rsv_bw.header.type) != 0)
+    length += TLV_SIZE (&lp->max_rsv_bw.header);
+
+  /* TE_LINK_SUBTLV_UNRSV_BW */
+  if (ntohs (lp->unrsv_bw.header.type) != 0)
+    length += TLV_SIZE (&lp->unrsv_bw.header);
+
+  /* TE_LINK_SUBTLV_RSC_CLSCLR */
+  if (ntohs (lp->rsc_clsclr.header.type) != 0)
+    length += TLV_SIZE (&lp->rsc_clsclr.header);
+
+  lp->link_header.header.type   = htons (TE_TLV_LINK);
+  lp->link_header.header.length = htons (length);
+
+  return;
+}
+
+static void
+set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp)
+{
+  lp->link_type.header.type   = htons (TE_LINK_SUBTLV_LINK_TYPE);
+  lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value));
+
+  switch (oi->type)
+    {
+    case OSPF_IFTYPE_POINTOPOINT:
+      lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP;
+      break;
+    case OSPF_IFTYPE_BROADCAST:
+    case OSPF_IFTYPE_NBMA:
+      lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA;
+      break;
+    default:
+      /* Not supported yet. *//* XXX */
+      lp->link_type.header.type = htons (0);
+      break;
+    }
+  return;
+}
+
+static void
+set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp)
+{
+  struct ospf_neighbor *nbr;
+  int done = 0;
+
+  lp->link_id.header.type   = htons (TE_LINK_SUBTLV_LINK_ID);
+  lp->link_id.header.length = htons (sizeof (lp->link_id.value));
+
+  /*
+   * The Link ID is identical to the contents of the Link ID field
+   * in the Router LSA for these link types.
+   */
+  switch (oi->type)
+    {
+    case OSPF_IFTYPE_POINTOPOINT:
+      /* Take the router ID of the neighbor. */
+      if (((nbr = ospf_nbr_lookup_ptop (oi->nbrs, oi->area->top->router_id)))
+      &&  (nbr->state == NSM_Full))
+        {
+          lp->link_id.value = nbr->router_id;
+          done = 1;
+        }
+      break;
+    case OSPF_IFTYPE_BROADCAST:
+    case OSPF_IFTYPE_NBMA:
+      /* Take the interface address of the designated router. */
+      if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL)
+        break;
+
+      if (nbr->state == NSM_Full
+      || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
+      &&  ospf_nbr_count (oi->nbrs, NSM_Full) > 0))
+        {
+          lp->link_id.value = DR (oi);
+          done = 1;
+        }
+      break;
+    default:
+      /* Not supported yet. *//* XXX */
+      lp->link_id.header.type = htons (0);
+      break;
+    }
+
+  if (! done)
+    {
+      struct in_addr mask;
+      masklen2ip (oi->address->prefixlen, &mask);
+      lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+     }
+  return;
+}
+
+static void
+set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric)
+{
+  lp->te_metric.header.type   = htons (TE_LINK_SUBTLV_TE_METRIC);
+  lp->te_metric.header.length = htons (sizeof (lp->te_metric.value));
+  lp->te_metric.value = htonl (te_metric);
+  return;
+}
+
+static void
+set_linkparams_max_bw (struct mpls_te_link *lp, float *fp)
+{
+  lp->max_bw.header.type   = htons (TE_LINK_SUBTLV_MAX_BW);
+  lp->max_bw.header.length = htons (sizeof (lp->max_bw.value));
+  htonf (fp, &lp->max_bw.value);
+  return;
+}
+
+static void
+set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp)
+{
+  lp->max_rsv_bw.header.type   = htons (TE_LINK_SUBTLV_MAX_RSV_BW);
+  lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value));
+  htonf (fp, &lp->max_rsv_bw.value);
+  return;
+}
+
+static void
+set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp)
+{
+  /* Note that TLV-length field is the size of array. */
+  lp->unrsv_bw.header.type   = htons (TE_LINK_SUBTLV_UNRSV_BW);
+  lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value));
+  htonf (fp, &lp->unrsv_bw.value [priority]);
+  return;
+}
+
+static void
+set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor)
+{
+  lp->rsc_clsclr.header.type   = htons (TE_LINK_SUBTLV_RSC_CLSCLR);
+  lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value));
+  lp->rsc_clsclr.value = htonl (classcolor);
+  return;
+}
+
+static void
+initialize_linkparams (struct mpls_te_link *lp)
+{
+  struct interface *ifp = lp->ifp;
+  struct ospf_interface *oi;
+  float fval;
+  int i;
+
+  if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL)
+    return;
+
+  /*
+   * Try to set initial values those can be derived from
+   * zebra-interface information.
+   */
+  set_linkparams_link_type (oi, lp);
+
+  /*
+   * Linux and *BSD kernel holds bandwidth parameter as an "int" type.
+   * We may have to reconsider, if "ifp->bandwidth" type changes to float.
+   */
+  fval = (float)((ifp->bandwidth ? ifp->bandwidth
+                                 : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8);
+
+  set_linkparams_max_bw (lp, &fval);
+  set_linkparams_max_rsv_bw (lp, &fval);
+
+  for (i = 0; i < 8; i++)
+    set_linkparams_unrsv_bw (lp, i, &fval);
+
+  return;
+}
+
+static int
+is_mandated_params_set (struct mpls_te_link *lp)
+{
+  int rc = 0;
+
+  if (ntohs (OspfMplsTE.router_addr.header.type) == 0)
+    goto out;
+
+  if (ntohs (lp->link_type.header.type) == 0)
+    goto out;
+
+  if (ntohs (lp->link_id.header.type) == 0)
+    goto out;
+
+  rc = 1;
+out:
+  return rc;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are callback functions against generic Opaque-LSAs handling.
+ *------------------------------------------------------------------------*/
+
+static int
+ospf_mpls_te_new_if (struct interface *ifp)
+{
+  struct mpls_te_link *new;
+  int rc = -1;
+
+  if (lookup_linkparams_by_ifp (ifp) != NULL)
+    {
+      zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp);
+      rc = 0; /* Do nothing here. */
+      goto out;
+    }
+
+  if ((new = XMALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS,
+                  sizeof (struct mpls_te_link))) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", strerror (errno));
+      goto out;
+    }
+  memset (new, 0, sizeof (struct mpls_te_link));
+
+  new->area = NULL;
+  new->flags = 0;
+  new->instance = get_mpls_te_instance_value ();
+  new->ifp = ifp;
+
+  initialize_linkparams (new);
+
+  listnode_add (OspfMplsTE.iflist, new);
+
+  /* Schedule Opaque-LSA refresh. *//* XXX */
+
+  rc = 0;
+out:
+  return rc;
+}
+
+static int
+ospf_mpls_te_del_if (struct interface *ifp)
+{
+  struct mpls_te_link *lp;
+  int rc = -1;
+
+  if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)
+    {
+      list iflist = OspfMplsTE.iflist;
+
+      /* Dequeue listnode entry from the list. */
+      listnode_delete (iflist, lp);
+
+      /* Avoid misjudgement in the next lookup. */
+      if (listcount (iflist) == 0)
+        iflist->head = iflist->tail = NULL;
+
+      XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp);
+    }
+
+  /* Schedule Opaque-LSA refresh. *//* XXX */
+
+  rc = 0;
+/*out:*/
+  return rc;
+}
+
+static void
+ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state)
+{
+  struct te_link_subtlv_link_type old_type;
+  struct te_link_subtlv_link_id   old_id;
+  struct mpls_te_link *lp;
+
+  if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi));
+      goto out;
+    }
+  if (oi->area == NULL || oi->area->top == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?",
+IF_NAME (oi));
+      goto out;
+    }
+#ifdef notyet
+  if ((lp->area != NULL
+  &&   ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id))
+  || (lp->area != NULL && oi->area == NULL))
+    {
+      /* How should we consider this case? */
+      zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A");
+      ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
+    }
+#endif
+  /* Keep Area information in conbination with linkparams. */
+  lp->area = oi->area;
+
+  switch (oi->state)
+    {
+    case ISM_PointToPoint:
+    case ISM_DROther:
+    case ISM_Backup:
+    case ISM_DR:
+      old_type = lp->link_type;
+      old_id   = lp->link_id;
+
+      set_linkparams_link_type (oi, lp);
+      set_linkparams_link_id (oi, lp);
+
+      if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type)
+      ||   old_type.link_type.value     != lp->link_type.link_type.value)
+      ||  (ntohs (old_id.header.type)   != ntohs (lp->link_id.header.type)
+      ||   ntohl (old_id.value.s_addr)  != ntohl (lp->link_id.value.s_addr)))
+        {
+          if (lp->flags & LPFLG_LSA_ENGAGED)
+            ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+          else
+            ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+        }
+      break;
+    default:
+      lp->link_type.header.type = htons (0);
+      lp->link_id.header.type   = htons (0);
+
+      if (lp->flags & LPFLG_LSA_ENGAGED)
+        ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
+      break;
+    }
+
+out:
+  return;
+}
+
+static void
+ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state)
+{
+  /* So far, nothing to do here. */
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are OSPF protocol processing functions for MPLS-TE.
+ *------------------------------------------------------------------------*/
+
+static void
+build_tlv_header (struct stream *s, struct te_tlv_header *tlvh)
+{
+  stream_put (s, tlvh, sizeof (struct te_tlv_header));
+  return;
+}
+
+static void
+build_router_tlv (struct stream *s)
+{
+  struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->link_type.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->link_id.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr;
+  if (tlvh != NULL && ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr;
+  if (tlvh != NULL && ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->te_metric.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->max_bw.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->max_rsv_bw.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->unrsv_bw.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp)
+{
+  struct te_tlv_header *tlvh = &lp->rsc_clsclr.header;
+  if (ntohs (tlvh->type) != 0)
+    {
+      build_tlv_header (s, tlvh);
+      stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh));
+    }
+  return;
+}
+
+static void
+build_link_tlv (struct stream *s, struct mpls_te_link *lp)
+{
+  set_linkparams_link_header (lp);
+  build_tlv_header (s, &lp->link_header.header);
+
+  build_link_subtlv_link_type (s, lp);
+  build_link_subtlv_link_id (s, lp);
+  build_link_subtlv_lclif_ipaddr (s, lp);
+  build_link_subtlv_rmtif_ipaddr (s, lp);
+  build_link_subtlv_te_metric (s, lp);
+  build_link_subtlv_max_bw (s, lp);
+  build_link_subtlv_max_rsv_bw (s, lp);
+  build_link_subtlv_unrsv_bw (s, lp);
+  build_link_subtlv_rsc_clsclr (s, lp);
+  return;
+}
+
+static void
+ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp)
+{
+  /*
+   * The router address TLV is type 1, and ...
+   *                                      It must appear in exactly one
+   * Traffic Engineering LSA originated by a router.
+   */
+  build_router_tlv (s);
+
+  /*
+   * Only one Link TLV shall be carried in each LSA, allowing for fine
+   * granularity changes in topology.
+   */
+  build_link_tlv (s, lp);
+  return;
+}
+
+/* Create new opaque-LSA. */
+static struct ospf_lsa *
+ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp)
+{
+  struct stream *s;
+  struct lsa_header *lsah;
+  struct ospf_lsa *new = NULL;
+  u_char options, lsa_type;
+  struct in_addr lsa_id;
+  u_int32_t tmp;
+  u_int16_t length;
+
+  /* Create a stream for LSA. */
+  if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?");
+      goto out;
+    }
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  options  = LSA_OPTIONS_GET (area);
+#ifdef HAVE_NSSA
+  options |= LSA_NSSA_GET (area);
+#endif /* HAVE_NSSA */
+  options |= OSPF_OPTION_O; /* Don't forget this :-) */
+
+  lsa_type = OSPF_OPAQUE_AREA_LSA;
+  tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
+  lsa_id.s_addr = htonl (tmp);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id));
+
+  /* Set opaque-LSA header fields. */
+  lsa_header_set (s, options, lsa_type, lsa_id);
+
+  /* Set opaque-LSA body fields. */
+  ospf_mpls_te_lsa_body_set (s, lp);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Now, create an OSPF LSA instance. */
+  if ((new = ospf_lsa_new ()) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
+      stream_free (s);
+      goto out;
+    }
+  if ((new->data = ospf_lsa_data_new (length)) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?");
+      ospf_lsa_free (new);
+      new = NULL;
+      stream_free (s);
+      goto out;
+    }
+
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+out:
+  return new;
+}
+
+static int
+ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp)
+{
+  struct ospf_lsa *new;
+  int rc = -1;
+
+  /* Create new Opaque-LSA/MPLS-TE instance. */
+  if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?");
+      goto out;
+    }
+
+  /* Install this LSA into LSDB. */
+  if (ospf_lsa_install (NULL/*oi*/, new) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?");
+      ospf_lsa_free (new);
+      goto out;
+    }
+
+  /* Now this linkparameter entry has associated LSA. */
+  lp->flags |= LPFLG_LSA_ENGAGED;
+
+  /* Update new LSA origination count. */
+  area->top->lsa_originate_count++;
+
+  /* Flood new LSA through area. */
+  ospf_flood_through_area (area, NULL/*nbr*/, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      char area_id[INET_ADDRSTRLEN];
+      strcpy (area_id, inet_ntoa (area->area_id));
+      zlog_info ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  rc = 0;
+out:
+  return rc;
+}
+
+static int
+ospf_mpls_te_lsa_originate (void *arg)
+{
+  struct ospf_area *area = (struct ospf_area *) arg;
+  listnode node;
+  struct mpls_te_link *lp;
+  int rc = -1;
+
+  if (OspfMplsTE.status == disabled)
+    {
+      zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now.");
+      rc = 0; /* This is not an error case. */
+      goto out;
+    }
+
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    {
+      if ((lp = getdata (node)) == NULL)
+        continue;
+      if (lp->area == NULL)
+        continue;
+      if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id))
+        continue;
+
+      if (lp->flags & LPFLG_LSA_ENGAGED)
+        {
+          if (lp->flags & LPFLG_LSA_FORCED_REFRESH)
+            {
+              lp->flags &= ~LPFLG_LSA_FORCED_REFRESH;
+              ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+            }
+          continue;
+        }
+      if (! is_mandated_params_set (lp))
+        {
+          zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?");
+          continue;
+        }
+
+      /* Ok, let's try to originate an LSA for this area and Link. */
+      if (ospf_mpls_te_lsa_originate1 (area, lp) != 0)
+        goto out;
+    }
+
+  rc = 0;
+out:
+  return rc;
+}
+
+static void
+ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct mpls_te_link *lp;
+  struct ospf_area *area = lsa->area;
+  struct ospf_lsa *new = NULL;
+
+  if (OspfMplsTE.status == disabled)
+    {
+      /*
+       * This LSA must have flushed before due to MPLS-TE status change.
+       * It seems a slip among routers in the routing domain.
+       */
+      zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now.");
+      lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
+    }
+
+  /* At first, resolve lsa/lp relationship. */
+  if ((lp = lookup_linkparams_by_instance (lsa)) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?");
+      lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
+    }
+
+  /* If the lsa's age reached to MaxAge, start flushing procedure. */
+  if (IS_LSA_MAXAGE (lsa))
+    {
+      lp->flags &= ~LPFLG_LSA_ENGAGED;
+      ospf_opaque_lsa_flush_schedule (lsa);
+      goto out;
+    }
+
+  /* Create new Opaque-LSA/MPLS-TE instance. */
+  if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?");
+      goto out;
+    }
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  /* Install this LSA into LSDB. */
+  /* Given "lsa" will be freed in the next function. */
+  if (ospf_lsa_install (NULL/*oi*/, new) == NULL)
+    {
+      zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?");
+      ospf_lsa_free (new);
+      goto out;
+    }
+
+  /* Flood updated LSA through area. */
+  ospf_flood_through_area (area, NULL/*nbr*/, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE",
+                new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+out:
+  return;
+}
+
+static void
+ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp,
+                           enum sched_opcode opcode)
+{
+  struct ospf_lsa lsa;
+  struct lsa_header lsah;
+  u_int32_t tmp;
+
+  memset (&lsa, 0, sizeof (lsa));
+  memset (&lsah, 0, sizeof (lsah));
+
+  lsa.area = lp->area;
+  lsa.data = &lsah;
+  lsah.type = OSPF_OPAQUE_AREA_LSA;
+  tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance);
+  lsah.id.s_addr = htonl (tmp);
+
+  switch (opcode)
+    {
+    case REORIGINATE_PER_AREA:
+      ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area,
+          OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
+      break;
+    case REFRESH_THIS_LSA:
+      ospf_opaque_lsa_refresh_schedule (&lsa);
+      break;
+    case FLUSH_THIS_LSA:
+      lp->flags &= ~LPFLG_LSA_ENGAGED;
+      ospf_opaque_lsa_flush_schedule (&lsa);
+      break;
+    default:
+      zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode);
+      break;
+    }
+
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are vty session control functions.
+ *------------------------------------------------------------------------*/
+
+static u_int16_t
+show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh;
+
+  if (vty != NULL)
+    vty_out (vty, "  Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
+  else
+    zlog_info ("    Router-Address: %s", inet_ntoa (top->value));
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_tlv_link *top = (struct te_tlv_link *) tlvh;
+
+  if (vty != NULL)
+    vty_out (vty, "  Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE);
+  else
+    zlog_info ("    Link: %u octets of data", ntohs (top->header.length));
+
+  return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */
+}
+
+static u_int16_t
+show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_link_type *top;
+  const char *cp = "Unknown";
+
+  top = (struct te_link_subtlv_link_type *) tlvh;
+  switch (top->link_type.value)
+    {
+    case LINK_TYPE_SUBTLV_VALUE_PTP:
+      cp = "Point-to-point";
+      break;
+    case LINK_TYPE_SUBTLV_VALUE_MA:
+      cp = "Multiaccess";
+      break;
+    default:
+      break;
+    }
+
+  if (vty != NULL)
+    vty_out (vty, "  Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE);
+  else
+    zlog_info ("    Link-Type: %s (%u)", cp, top->link_type.value);
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_link_id *top;
+
+  top = (struct te_link_subtlv_link_id *) tlvh;
+  if (vty != NULL)
+    vty_out (vty, "  Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE);
+  else
+    zlog_info ("    Link-ID: %s", inet_ntoa (top->value));
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_lclif_ipaddr *top;
+  int i, n;
+
+  top = (struct te_link_subtlv_lclif_ipaddr *) tlvh;
+  n = ntohs (tlvh->length) / sizeof (top->value[0]);
+
+  if (vty != NULL)
+    vty_out (vty, "  Local Interface IP Address(es): %d%s", n, VTY_NEWLINE);
+  else
+    zlog_info ("    Local Interface IP Address(es): %d", n);
+
+  for (i = 0; i < n; i++)
+    {
+      if (vty != NULL)
+        vty_out (vty, "    #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
+      else
+        zlog_info ("      #%d: %s", i, inet_ntoa (top->value[i]));
+    }
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_rmtif_ipaddr *top;
+  int i, n;
+
+  top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh;
+  n = ntohs (tlvh->length) / sizeof (top->value[0]);
+  if (vty != NULL)
+    vty_out (vty, "  Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE);
+  else
+    zlog_info ("    Remote Interface IP Address(es): %d", n);
+
+  for (i = 0; i < n; i++)
+    {
+      if (vty != NULL)
+        vty_out (vty, "    #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE);
+      else
+        zlog_info ("      #%d: %s", i, inet_ntoa (top->value[i]));
+    }
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_te_metric *top;
+
+  top = (struct te_link_subtlv_te_metric *) tlvh;
+  if (vty != NULL)
+    vty_out (vty, "  Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
+  else
+    zlog_info ("    Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value));
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_max_bw *top;
+  float fval;
+
+  top = (struct te_link_subtlv_max_bw *) tlvh;
+  ntohf (&top->value, &fval);
+
+  if (vty != NULL)
+    vty_out (vty, "  Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+  else
+    zlog_info ("    Maximum Bandwidth: %g (Bytes/sec)", fval);
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_max_rsv_bw *top;
+  float fval;
+
+  top = (struct te_link_subtlv_max_rsv_bw *) tlvh;
+  ntohf (&top->value, &fval);
+
+  if (vty != NULL)
+    vty_out (vty, "  Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+  else
+    zlog_info ("    Maximum Reservable Bandwidth: %g (Bytes/sec)", fval);
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_unrsv_bw *top;
+  float fval;
+  int i;
+
+  top = (struct te_link_subtlv_unrsv_bw *) tlvh;
+  for (i = 0; i < 8; i++)
+    {
+      ntohf (&top->value[i], &fval);
+      if (vty != NULL)
+        vty_out (vty, "  Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE);
+      else
+        zlog_info ("    Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval);
+    }
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  struct te_link_subtlv_rsc_clsclr *top;
+
+  top = (struct te_link_subtlv_rsc_clsclr *) tlvh;
+  if (vty != NULL)
+    vty_out (vty, "  Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE);
+  else
+    zlog_info ("    Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value));
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh)
+{
+  if (vty != NULL)
+    vty_out (vty, "  Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE);
+  else
+    zlog_info ("    Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length));
+
+  return TLV_SIZE (tlvh);
+}
+
+static u_int16_t
+ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0,
+                               u_int16_t subtotal, u_int16_t total)
+{
+  struct te_tlv_header *tlvh, *next;
+  u_int16_t sum = subtotal;
+
+  for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
+    {
+      next = NULL;
+      switch (ntohs (tlvh->type))
+        {
+        case TE_LINK_SUBTLV_LINK_TYPE:
+          sum += show_vty_link_subtlv_link_type (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_LINK_ID:
+          sum += show_vty_link_subtlv_link_id (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_LCLIF_IPADDR:
+          sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_RMTIF_IPADDR:
+          sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_TE_METRIC:
+          sum += show_vty_link_subtlv_te_metric (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_MAX_BW:
+          sum += show_vty_link_subtlv_max_bw (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_MAX_RSV_BW:
+          sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_UNRSV_BW:
+          sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh);
+          break;
+        case TE_LINK_SUBTLV_RSC_CLSCLR:
+          sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh);
+          break;
+        default:
+          sum += show_vty_unknown_tlv (vty, tlvh);
+          break;
+        }
+    }
+  return sum;
+}
+
+static void
+ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa)
+{
+  struct lsa_header *lsah = (struct lsa_header *) lsa->data;
+  struct te_tlv_header *tlvh, *next;
+  u_int16_t sum, total;
+  u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh,
+                        u_int16_t subtotal, u_int16_t total) = NULL;
+
+  sum = 0;
+  total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE;
+
+  for (tlvh = TLV_HDR_TOP (lsah); sum < total;
+                       tlvh = (next ? next : TLV_HDR_NEXT (tlvh)))
+    {
+      if (subfunc != NULL)
+        {
+          sum = (* subfunc)(vty, tlvh, sum, total);
+         next = (struct te_tlv_header *)((char *) tlvh + sum);
+          subfunc = NULL;
+          continue;
+        }
+
+      next = NULL;
+      switch (ntohs (tlvh->type))
+        {
+        case TE_TLV_ROUTER_ADDR:
+          sum += show_vty_router_addr (vty, tlvh);
+          break;
+        case TE_TLV_LINK:
+          sum += show_vty_link_header (vty, tlvh);
+         subfunc = ospf_mpls_te_show_link_subtlv;
+         next = tlvh + 1;
+          break;
+        default:
+          sum += show_vty_unknown_tlv (vty, tlvh);
+          break;
+        }
+    }
+  return;
+}
+
+static void
+ospf_mpls_te_config_write_router (struct vty *vty)
+{
+  if (OspfMplsTE.status == enabled)
+    {
+      vty_out (vty, "  mpls-te%s", VTY_NEWLINE);
+      vty_out (vty, "  mpls-te router-address %s%s",
+               inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE);
+    }
+  return;
+}
+
+static void
+ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp)
+{
+  struct mpls_te_link *lp;
+
+  if ((OspfMplsTE.status == enabled)
+  &&  (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
+  &&  ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
+    {
+      float fval;
+      int i;
+
+      vty_out (vty, " mpls-te link metric %u%s",
+               (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE);
+
+      ntohf (&lp->max_bw.value, &fval);
+      if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
+        vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE);
+
+      ntohf (&lp->max_rsv_bw.value, &fval);
+      if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
+        vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE);
+
+      for (i = 0; i < 8; i++)
+        {
+          ntohf (&lp->unrsv_bw.value[i], &fval);
+          if (fval >= MPLS_TE_MINIMUM_BANDWIDTH)
+            vty_out (vty, " mpls-te link unrsv-bw %d %g%s",
+                     i, fval, VTY_NEWLINE);
+        }
+
+      vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s",
+               (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE);
+    }
+  return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are vty command functions.
+ *------------------------------------------------------------------------*/
+
+DEFUN (mpls_te,
+       mpls_te_cmd,
+       "mpls-te",
+       "Configure MPLS-TE parameters\n"
+       "Enable the MPLS-TE functionality\n")
+{
+  listnode node;
+  struct mpls_te_link *lp;
+
+  if (OspfMplsTE.status == enabled)
+    return CMD_SUCCESS;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("MPLS-TE: OFF -> ON");
+
+  OspfMplsTE.status = enabled;
+
+  /*
+   * Following code is intended to handle two cases;
+   *
+   * 1) MPLS-TE was disabled at startup time, but now become enabled.
+   * 2) MPLS-TE was once enabled then disabled, and now enabled again.
+   */
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    if ((lp = getdata (node)) != NULL)
+      initialize_linkparams (lp);
+
+  ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (mpls_te,
+       mpls_te_on_cmd,
+       "mpls-te on",
+       "Configure MPLS-TE parameters\n"
+       "Enable the MPLS-TE functionality\n")
+
+DEFUN (no_mpls_te,
+       no_mpls_te_cmd,
+       "no mpls-te",
+       NO_STR
+       "Configure MPLS-TE parameters\n"
+       "Disable the MPLS-TE functionality\n")
+{
+  listnode node;
+  struct mpls_te_link *lp;
+
+  if (OspfMplsTE.status == disabled)
+    return CMD_SUCCESS;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("MPLS-TE: ON -> OFF");
+
+  OspfMplsTE.status = disabled;
+
+  for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+    if ((lp = getdata (node)) != NULL)
+      if (lp->area != NULL)
+        if (lp->flags & LPFLG_LSA_ENGAGED)
+          ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_router_addr,
+       mpls_te_router_addr_cmd,
+       "mpls-te router-address A.B.C.D",
+       "MPLS-TE specific commands\n"
+       "Stable IP address of the advertising router\n"
+       "MPLS-TE router address in IPv4 address format\n")
+{
+  struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr;
+  struct in_addr value;
+
+  if (! inet_aton (argv[0], &value))
+    {
+      vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ntohs (ra->header.type) == 0
+  ||  ntohl (ra->value.s_addr) != ntohl (value.s_addr))
+    {
+      listnode node;
+      struct mpls_te_link *lp;
+      int need_to_reoriginate = 0;
+
+      set_mpls_te_router_addr (value);
+
+      if (OspfMplsTE.status == disabled)
+        goto out;
+
+      for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+        {
+          if ((lp = getdata (node)) == NULL)
+            continue;
+          if (lp->area == NULL)
+            continue;
+
+          if ((lp->flags & LPFLG_LSA_ENGAGED) == 0)
+            {
+              need_to_reoriginate = 1;
+              break;
+            }
+        }
+      for (node = listhead (OspfMplsTE.iflist); node; nextnode (node))
+        {
+          if ((lp = getdata (node)) == NULL)
+            continue;
+          if (lp->area == NULL)
+            continue;
+
+          if (need_to_reoriginate)
+            lp->flags |= LPFLG_LSA_FORCED_REFRESH;
+          else
+            ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+        }
+
+      if (need_to_reoriginate)
+        ospf_mpls_te_foreach_area (
+            ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA);
+    }
+out:
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_metric,
+       mpls_te_link_metric_cmd,
+       "mpls-te link metric <0-4294967295>",
+       "MPLS-TE specific commands\n"
+       "Configure MPLS-TE link parameters\n"
+       "Link metric for MPLS-TE purpose\n"
+       "Metric\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct mpls_te_link *lp;
+  u_int32_t value;
+
+  if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+    {
+      vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  value = strtoul (argv[0], NULL, 10);
+
+  if (ntohs (lp->te_metric.header.type) == 0
+  ||  ntohl (lp->te_metric.value) != value)
+    {
+      set_linkparams_te_metric (lp, value);
+
+      if (OspfMplsTE.status == enabled)
+        if (lp->area != NULL)
+          {
+            if (lp->flags & LPFLG_LSA_ENGAGED)
+              ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+            else
+              ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+          }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_maxbw,
+       mpls_te_link_maxbw_cmd,
+       "mpls-te link max-bw BANDWIDTH",
+       "MPLS-TE specific commands\n"
+       "Configure MPLS-TE link parameters\n"
+       "Maximum bandwidth that can be used\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct mpls_te_link *lp;
+  float f1, f2;
+
+  if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+    {
+      vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ntohf (&lp->max_bw.value, &f1);
+  if (sscanf (argv[0], "%g", &f2) != 1)
+    {
+      vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ntohs (lp->max_bw.header.type) == 0
+  ||  f1 != f2)
+    {
+      set_linkparams_max_bw (lp, &f2);
+
+      if (OspfMplsTE.status == enabled)
+        if (lp->area != NULL)
+          {
+            if (lp->flags & LPFLG_LSA_ENGAGED)
+              ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+            else
+              ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+          }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_max_rsv_bw,
+       mpls_te_link_max_rsv_bw_cmd,
+       "mpls-te link max-rsv-bw BANDWIDTH",
+       "MPLS-TE specific commands\n"
+       "Configure MPLS-TE link parameters\n"
+       "Maximum bandwidth that may be reserved\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct mpls_te_link *lp;
+  float f1, f2;
+
+  if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+    {
+      vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ntohf (&lp->max_rsv_bw.value, &f1);
+  if (sscanf (argv[0], "%g", &f2) != 1)
+    {
+      vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ntohs (lp->max_rsv_bw.header.type) == 0
+  ||  f1 != f2)
+    {
+      set_linkparams_max_rsv_bw (lp, &f2);
+
+      if (OspfMplsTE.status == enabled)
+        if (lp->area != NULL)
+          {
+            if (lp->flags & LPFLG_LSA_ENGAGED)
+              ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+            else
+              ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+          }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_unrsv_bw,
+       mpls_te_link_unrsv_bw_cmd,
+       "mpls-te link unrsv-bw <0-7> BANDWIDTH",
+       "MPLS-TE specific commands\n"
+       "Configure MPLS-TE link parameters\n"
+       "Unreserved bandwidth at each priority level\n"
+       "Priority\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct mpls_te_link *lp;
+  int priority;
+  float f1, f2;
+
+  if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+    {
+      vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* We don't have to consider about range check here. */
+  if (sscanf (argv[0], "%d", &priority) != 1)
+    {
+      vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ntohf (&lp->unrsv_bw.value [priority], &f1);
+  if (sscanf (argv[1], "%g", &f2) != 1)
+    {
+      vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ntohs (lp->unrsv_bw.header.type) == 0
+  ||  f1 != f2)
+    {
+      set_linkparams_unrsv_bw (lp, priority, &f2);
+
+      if (OspfMplsTE.status == enabled)
+        if (lp->area != NULL)
+          {
+            if (lp->flags & LPFLG_LSA_ENGAGED)
+              ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+            else
+              ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+          }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_te_link_rsc_clsclr,
+       mpls_te_link_rsc_clsclr_cmd,
+       "mpls-te link rsc-clsclr BITPATTERN",
+       "MPLS-TE specific commands\n"
+       "Configure MPLS-TE link parameters\n"
+       "Administrative group membership\n"
+       "32-bit Hexadecimal value (ex. 0xa1)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct mpls_te_link *lp;
+  unsigned long value;
+
+  if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL)
+    {
+      vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (sscanf (argv[0], "0x%lx", &value) != 1)
+    {
+      vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", strerror (errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ntohs (lp->rsc_clsclr.header.type) == 0
+  ||  ntohl (lp->rsc_clsclr.value) != value)
+    {
+      set_linkparams_rsc_clsclr (lp, value);
+
+      if (OspfMplsTE.status == enabled)
+        if (lp->area != NULL)
+          {
+            if (lp->flags & LPFLG_LSA_ENGAGED)
+              ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA);
+            else
+              ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA);
+          }
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_mpls_te_router,
+       show_mpls_te_router_cmd,
+       "show mpls-te router",
+       SHOW_STR
+       "MPLS-TE information\n"
+       "Router information\n")
+{
+  if (OspfMplsTE.status == enabled)
+    {
+      vty_out (vty, "--- MPLS-TE router parameters ---%s",
+               VTY_NEWLINE);
+
+      if (ntohs (OspfMplsTE.router_addr.header.type) != 0)
+        show_vty_router_addr (vty, &OspfMplsTE.router_addr.header);
+      else if (vty != NULL)
+        vty_out (vty, "  N/A%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+static void
+show_mpls_te_link_sub (struct vty *vty, struct interface *ifp)
+{
+  struct mpls_te_link *lp;
+  struct te_tlv_header *tlvh;
+
+  if ((OspfMplsTE.status == enabled)
+  &&  (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0)
+  &&  ((lp = lookup_linkparams_by_ifp (ifp)) != NULL))
+    {
+      vty_out (vty, "-- MPLS-TE link parameters for %s --%s",
+               ifp->name, VTY_NEWLINE);
+
+      show_vty_link_subtlv_link_type (vty, &lp->link_type.header);
+      show_vty_link_subtlv_link_id (vty, &lp->link_id.header);
+
+      if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL)
+        show_vty_link_subtlv_lclif_ipaddr (vty, tlvh);
+      if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL)
+        show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh);
+
+      show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header);
+
+      show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header);
+      show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header);
+      show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header);
+      show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header);
+    }
+  else
+    {
+      vty_out (vty, "  %s: MPLS-TE is disabled on this interface%s",
+               ifp->name, VTY_NEWLINE);
+    }
+
+  return;
+}
+
+DEFUN (show_mpls_te_link,
+       show_mpls_te_link_cmd,
+       "show mpls-te interface [INTERFACE]",
+       SHOW_STR
+       "MPLS-TE information\n"
+       "Interface information\n"
+       "Interface name\n")
+{
+  struct interface *ifp;
+  listnode node;
+
+  /* Show All Interfaces. */
+  if (argc == 0)
+    for (node = listhead (iflist); node; nextnode (node))
+      show_mpls_te_link_sub (vty, node->data);
+  /* Interface name is specified. */
+  else
+    {
+      if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+        vty_out (vty, "No such interface name%s", VTY_NEWLINE);
+      else
+        show_mpls_te_link_sub (vty, ifp);
+    }
+
+  return CMD_SUCCESS;
+}
+
+static void
+ospf_mpls_te_register_vty (void)
+{
+  install_element (VIEW_NODE, &show_mpls_te_router_cmd);
+  install_element (VIEW_NODE, &show_mpls_te_link_cmd);
+  install_element (ENABLE_NODE, &show_mpls_te_router_cmd);
+  install_element (ENABLE_NODE, &show_mpls_te_link_cmd);
+
+  install_element (OSPF_NODE, &mpls_te_cmd);
+  install_element (OSPF_NODE, &no_mpls_te_cmd);
+  install_element (OSPF_NODE, &mpls_te_on_cmd);
+  install_element (OSPF_NODE, &mpls_te_router_addr_cmd);
+
+  install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd);
+  install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd);
+  install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd);
+  install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd);
+  install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd);
+
+  return;
+}
+
+#endif /* HAVE_OSPF_TE */
diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h
new file mode 100644 (file)
index 0000000..8a7a98c
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt
+ * Copyright (C) 2001 KDD R&D Laboratories, Inc.
+ * http://www.kddlabs.co.jp/
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPF_MPLS_TE_H
+#define _ZEBRA_OSPF_MPLS_TE_H
+
+/*
+ * Opaque LSA's link state ID for Traffic Engineering is
+ * structured as follows.
+ *
+ *        24       16        8        0
+ * +--------+--------+--------+--------+
+ * |    1   |  MBZ   |........|........|
+ * +--------+--------+--------+--------+
+ * |<-Type->|<Resv'd>|<-- Instance --->|
+ *
+ *
+ * Type:      IANA has assigned '1' for Traffic Engineering.
+ * MBZ:       Reserved, must be set to zero.
+ * Instance:  User may select an arbitrary 16-bit value.
+ *
+ */
+
+#define        LEGAL_TE_INSTANCE_RANGE(i)      (0 <= (i) && (i) <= 0xffff)
+
+/*
+ *        24       16        8        0
+ * +--------+--------+--------+--------+ ---
+ * |   LS age        |Options |   10   |  A
+ * +--------+--------+--------+--------+  |
+ * |    1   |   0    |    Instance     |  |
+ * +--------+--------+--------+--------+  |
+ * |        Advertising router         |  |  Standard (Opaque) LSA header;
+ * +--------+--------+--------+--------+  |  Only type-10 is used.
+ * |        LS sequence number         |  |
+ * +--------+--------+--------+--------+  |
+ * |   LS checksum   |     Length      |  V
+ * +--------+--------+--------+--------+ ---
+ * |      Type       |     Length      |  A
+ * +--------+--------+--------+--------+  |  TLV part for TE; Values might be
+ * |              Values ...           |  V  structured as a set of sub-TLVs.
+ * +--------+--------+--------+--------+ ---
+ */
+
+/*
+ * Following section defines TLV (tag, length, value) structures,
+ * used for Traffic Engineering.
+ */
+struct te_tlv_header
+{
+  u_int16_t    type;                   /* TE_TLV_XXX (see below) */
+  u_int16_t    length;                 /* Value portion only, in octets */
+};
+
+#define TLV_HDR_SIZE \
+       sizeof (struct te_tlv_header)
+
+#define TLV_BODY_SIZE(tlvh) \
+       ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))
+
+#define TLV_SIZE(tlvh) \
+       (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
+
+#define TLV_HDR_TOP(lsah) \
+       (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE)
+
+#define TLV_HDR_NEXT(tlvh) \
+       (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))
+
+/*
+ * Following section defines TLV body parts.
+ */
+/* Router Address TLV *//* Mandatory */
+#define        TE_TLV_ROUTER_ADDR              1
+struct te_tlv_router_addr
+{
+  struct te_tlv_header header;         /* Value length is 4 octets. */
+  struct in_addr       value;
+};
+
+/* Link TLV */
+#define        TE_TLV_LINK                     2
+struct te_tlv_link
+{
+  struct te_tlv_header header;
+  /* A set of link-sub-TLVs will follow. */
+};
+
+/* Link Type Sub-TLV *//* Mandatory */
+#define        TE_LINK_SUBTLV_LINK_TYPE                1
+struct te_link_subtlv_link_type
+{
+  struct te_tlv_header header;         /* Value length is 1 octet. */
+  struct {
+#define        LINK_TYPE_SUBTLV_VALUE_PTP      1
+#define        LINK_TYPE_SUBTLV_VALUE_MA       2
+      u_char   value;
+      u_char   padding[3];
+  } link_type;
+};
+
+/* Link Sub-TLV: Link ID *//* Mandatory */
+#define        TE_LINK_SUBTLV_LINK_ID                  2
+struct te_link_subtlv_link_id
+{
+  struct te_tlv_header header;         /* Value length is 4 octets. */
+  struct in_addr       value;          /* Same as router-lsa's link-id. */
+};
+
+/* Link Sub-TLV: Local Interface IP Address *//* Optional */
+#define        TE_LINK_SUBTLV_LCLIF_IPADDR             3
+struct te_link_subtlv_lclif_ipaddr
+{
+  struct te_tlv_header header;         /* Value length is 4 x N octets. */
+  struct in_addr       value[1];       /* Local IP address(es). */
+};
+
+/* Link Sub-TLV: Remote Interface IP Address *//* Optional */
+#define        TE_LINK_SUBTLV_RMTIF_IPADDR             4
+struct te_link_subtlv_rmtif_ipaddr
+{
+  struct te_tlv_header header;         /* Value length is 4 x N octets. */
+  struct in_addr       value[1];       /* Neighbor's IP address(es). */
+};
+
+/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */
+#define        TE_LINK_SUBTLV_TE_METRIC                5
+struct te_link_subtlv_te_metric
+{
+  struct te_tlv_header header;         /* Value length is 4 octets. */
+  u_int32_t            value;          /* Link metric for TE purpose. */
+};
+
+/* Link Sub-TLV: Maximum Bandwidth *//* Optional */
+#define        TE_LINK_SUBTLV_MAX_BW                   6
+struct te_link_subtlv_max_bw
+{
+  struct te_tlv_header header;         /* Value length is 4 octets. */
+  float                        value;          /* bytes/sec */
+};
+
+/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */
+#define        TE_LINK_SUBTLV_MAX_RSV_BW               7
+struct te_link_subtlv_max_rsv_bw
+{
+  struct te_tlv_header header;         /* Value length is 4 octets. */
+  float                        value;          /* bytes/sec */
+};
+
+/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */
+#define        TE_LINK_SUBTLV_UNRSV_BW                 8
+struct te_link_subtlv_unrsv_bw
+{
+  struct te_tlv_header header;         /* Value length is 32 octets. */
+  float                        value[8];       /* One for each priority level. */
+};
+
+/* Link Sub-TLV: Resource Class/Color *//* Optional */
+#define        TE_LINK_SUBTLV_RSC_CLSCLR               9
+struct te_link_subtlv_rsc_clsclr
+{
+  struct te_tlv_header header;         /* Value length is 4 octets. */
+  u_int32_t            value;          /* Admin. group membership. */
+};
+
+/* Here are "non-official" architechtual constants. */
+#define MPLS_TE_MINIMUM_BANDWIDTH      1.0     /* Reasonable? *//* XXX */
+
+/* Prototypes. */
+extern int ospf_mpls_te_init (void);
+extern void ospf_mpls_te_term (void);
+
+#endif /* _ZEBRA_OSPF_MPLS_TE_H */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
new file mode 100644 (file)
index 0000000..73215fa
--- /dev/null
@@ -0,0 +1,7571 @@
+/* OSPF VTY interface.
+ * Copyright (C) 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+/*#include "ospfd/ospf_routemap.h" */
+#include "ospfd/ospf_vty.h"
+#include "ospfd/ospf_dump.h"
+
+\f
+static char *ospf_network_type_str[] =
+{
+  "Null",
+  "POINTOPOINT",
+  "BROADCAST",
+  "NBMA",
+  "POINTOMULTIPOINT",
+  "VIRTUALLINK",
+  "LOOPBACK"
+};
+
+\f
+/* Utility functions. */
+int
+ospf_str2area_id (char *str, struct in_addr *area_id, int *format)
+{
+  char *endptr = NULL;
+  unsigned long ret;
+
+  /* match "A.B.C.D". */
+  if (strchr (str, '.') != NULL)
+    {
+      ret = inet_aton (str, area_id);
+      if (!ret)
+        return -1;
+      *format = OSPF_AREA_ID_FORMAT_ADDRESS;
+    }
+  /* match "<0-4294967295>". */
+  else
+    {
+      ret = strtoul (str, &endptr, 10);
+      if (*endptr != '\0' || (ret == ULONG_MAX && errno == ERANGE))
+        return -1;
+
+      area_id->s_addr = htonl (ret);
+      *format = OSPF_AREA_ID_FORMAT_DECIMAL;
+    }
+
+  return 0;
+}
+
+\f
+int
+str2distribute_source (char *str, int *source)
+{
+  /* Sanity check. */
+  if (str == NULL)
+    return 0;
+
+  if (strncmp (str, "k", 1) == 0)
+    *source = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (str, "c", 1) == 0)
+    *source = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (str, "s", 1) == 0)
+    *source = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (str, "r", 1) == 0)
+    *source = ZEBRA_ROUTE_RIP;
+  else if (strncmp (str, "b", 1) == 0)
+    *source = ZEBRA_ROUTE_BGP;
+  else
+    return 0;
+
+  return 1;
+}
+
+int
+str2metric (char *str, int *metric)
+{
+  /* Sanity check. */
+  if (str == NULL)
+    return 0;
+
+  *metric = strtol (str, NULL, 10);
+  if (*metric < 0 && *metric > 16777214)
+    {
+      /* vty_out (vty, "OSPF metric value is invalid%s", VTY_NEWLINE); */
+      return 0;
+    }
+
+  return 1;
+}
+
+int
+str2metric_type (char *str, int *metric_type)
+{
+  /* Sanity check. */
+  if (str == NULL)
+    return 0;
+
+  if (strncmp (str, "1", 1) == 0)
+    *metric_type = EXTERNAL_METRIC_TYPE_1;
+  else if (strncmp (str, "2", 1) == 0)
+    *metric_type = EXTERNAL_METRIC_TYPE_2;
+  else
+    return 0;
+
+  return 1;
+}
+
+int
+ospf_oi_count (struct interface *ifp)
+{
+  struct route_node *rn;
+  int i = 0;
+
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    if (rn->info)
+      i++;
+
+  return i;
+}
+
+\f
+DEFUN (router_ospf,
+       router_ospf_cmd,
+       "router ospf",
+       "Enable a routing process\n"
+       "Start OSPF configuration\n")
+{
+  vty->node = OSPF_NODE;
+  vty->index = ospf_get ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_ospf,
+       no_router_ospf_cmd,
+       "no router ospf",
+       NO_STR
+       "Enable a routing process\n"
+       "Start OSPF configuration\n")
+{
+  if (ospf_top == NULL)
+    {
+      vty_out (vty, "There isn't active ospf instance.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf_finish (ospf_top);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_router_id,
+       ospf_router_id_cmd,
+       "ospf router-id A.B.C.D",
+       "OSPF specific commands\n"
+       "router-id for the OSPF process\n"
+       "OSPF router-id in IP address format\n")
+{
+  int ret;
+  struct in_addr router_id;
+
+  ret = inet_aton (argv[0], &router_id);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify Router ID by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* ospf_top->router_id = router_id; */
+  ospf_top->router_id_static = router_id;
+
+  if (ospf_top->t_router_id_update == NULL)
+    ospf_top->t_router_id_update =
+      thread_add_timer (master, ospf_router_id_update_timer, NULL,
+                       OSPF_ROUTER_ID_UPDATE_DELAY);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ospf_router_id,
+       router_id_cmd,
+       "router-id A.B.C.D",
+       "router-id for the OSPF process\n"
+       "OSPF router-id in IP address format\n")
+
+DEFUN (no_ospf_router_id,
+       no_ospf_router_id_cmd,
+       "no ospf router-id",
+       NO_STR
+       "OSPF specific commands\n"
+       "router-id for the OSPF process\n")
+{
+  ospf_top->router_id_static.s_addr = 0;
+
+  ospf_router_id_update ();
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ospf_router_id,
+       no_router_id_cmd,
+       "no router-id",
+       NO_STR
+       "router-id for the OSPF process\n")
+
+DEFUN (passive_interface,
+       passive_interface_addr_cmd,
+       "passive-interface IFNAME A.B.C.D",
+       "Suppress routing updates on an interface\n"
+       "Interface's name\n")
+{
+ struct interface *ifp;
+ struct in_addr addr;
+ int ret;
+ struct ospf_if_params *params;
+
+ ifp = if_lookup_by_name (argv[0]);
+ if (ifp == NULL)
+   {
+     vty_out (vty, "Please specify an existing interface%s", VTY_NEWLINE);
+     return CMD_WARNING;
+   }
+
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  SET_IF_PARAM (params, passive_interface);
+  params->passive_interface = OSPF_IF_PASSIVE;
+ return CMD_SUCCESS;
+}
+
+ALIAS (passive_interface,
+       passive_interface_cmd,
+       "passive-interface IFNAME",
+       "Suppress routing updates on an interface\n"
+       "Interface's name\n")
+
+DEFUN (no_passive_interface,
+       no_passive_interface_addr_cmd,
+       "no passive-interface IFNAME A.B.C.D",
+       NO_STR
+       "Allow routing updates on an interface\n"
+       "Interface's name\n")
+{
+  struct interface *ifp;
+  struct in_addr addr;
+  struct ospf_if_params *params;
+  int ret;
+    
+  ifp = if_lookup_by_name (argv[0]);
+  
+  if (ifp == NULL)
+    {
+      vty_out (vty, "Please specify an existing interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, passive_interface);
+  params->passive_interface = OSPF_IF_ACTIVE;
+  
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_passive_interface,
+       no_passive_interface_cmd,
+       "no passive-interface IFNAME",
+       NO_STR
+       "Allow routing updates on an interface\n"
+       "Interface's name\n")
+
+DEFUN (network_area,
+       network_area_cmd,
+       "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)",
+       "Enable routing on an IP network\n"
+       "OSPF network prefix\n"
+       "Set the OSPF area ID\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n")
+{
+  struct ospf *ospf= vty->index;
+  struct prefix_ipv4 p;
+  struct in_addr area_id;
+  int ret, format;
+
+  /* Get network prefix and Area ID. */
+  VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]);
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]);
+
+  ret = ospf_network_set (ospf, &p, area_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_network_area,
+       no_network_area_cmd,
+       "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)",
+       NO_STR
+       "Enable routing on an IP network\n"
+       "OSPF network prefix\n"
+       "Set the OSPF area ID\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n")
+{
+  struct ospf *ospf = (struct ospf *) vty->index;
+  struct prefix_ipv4 p;
+  struct in_addr area_id;
+  int ret, format;
+
+  /* Get network prefix and Area ID. */
+  VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]);
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]);
+
+  ret = ospf_network_unset (ospf, &p, area_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "Can't find specified network area configuration.%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (area_range,
+       area_range_cmd,
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n")
+{
+  struct ospf *ospf = vty->index;
+  struct prefix_ipv4 p;
+  struct in_addr area_id;
+  int format;
+  u_int32_t cost;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+  VTY_GET_IPV4_PREFIX ("area range", p, argv[1]);
+
+  ospf_area_range_set (ospf, area_id, &p, OSPF_AREA_RANGE_ADVERTISE);
+  if (argc > 2)
+    {
+      VTY_GET_UINT32 ("range cost", cost, argv[2]);
+      ospf_area_range_cost_set (ospf, area_id, &p, cost);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (area_range,
+       area_range_advertise_cmd,
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "OSPF area range for route advertise (default)\n"
+       "Area range prefix\n"
+       "Advertise this range (default)\n")
+
+ALIAS (area_range,
+       area_range_cost_cmd,
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+ALIAS (area_range,
+       area_range_advertise_cost_cmd,
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "Advertise this range (default)\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+DEFUN (area_range_not_advertise,
+       area_range_not_advertise_cmd,
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "DoNotAdvertise this range\n")
+{
+  struct ospf *ospf = vty->index;
+  struct prefix_ipv4 p;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+  VTY_GET_IPV4_PREFIX ("area range", p, argv[1]);
+
+  ospf_area_range_set (ospf, area_id, &p, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_range,
+       no_area_range_cmd,
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n")
+{
+  struct ospf *ospf = vty->index;
+  struct prefix_ipv4 p;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+  VTY_GET_IPV4_PREFIX ("area range", p, argv[1]);
+
+  ospf_area_range_unset (ospf, area_id, &p);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_area_range,
+       no_area_range_advertise_cmd,
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M (advertise|not-advertise)",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "Advertise this range (default)\n"
+       "DoNotAdvertise this range\n")
+
+ALIAS (no_area_range,
+       no_area_range_cost_cmd,
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+ALIAS (no_area_range,
+       no_area_range_advertise_cost_cmd,
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "Advertise this range (default)\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+\f
+DEFUN (area_range_substitute,
+       area_range_substitute_cmd,
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "Announce area range as another prefix\n"
+       "Network prefix to be announced instead of range\n")
+{
+  struct ospf *ospf = vty->index;
+  struct prefix_ipv4 p, s;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+  VTY_GET_IPV4_PREFIX ("area range", p, argv[1]);
+  VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]);
+
+  ospf_area_range_substitute_set (ospf, area_id, &p, &s);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_range_substitute,
+       no_area_range_substitute_cmd,
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Summarize routes matching address/mask (border routers only)\n"
+       "Area range prefix\n"
+       "Announce area range as another prefix\n"
+       "Network prefix to be announced instead of range\n")
+{
+  struct ospf *ospf = vty->index;
+  struct prefix_ipv4 p, s;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+  VTY_GET_IPV4_PREFIX ("area range", p, argv[1]);
+  VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]);
+
+  ospf_area_range_substitute_unset (ospf, area_id, &p);
+
+  return CMD_SUCCESS;
+}
+
+\f
+/* Command Handler Logic in VLink stuff is delicate!!
+
+       ALTER AT YOUR OWN RISK!!!!
+
+       Various dummy values are used to represent 'NoChange' state for
+       VLink configuration NOT being changed by a VLink command, and
+       special syntax is used within the command strings so that the
+       typed in command verbs can be seen in the configuration command
+       bacckend handler.  This is to drastically reduce the verbeage
+       required to coe up with a reasonably compatible Cisco VLink command
+
+       - Matthew Grant <grantma@anathoth.gen.nz> 
+       Wed, 21 Feb 2001 15:13:52 +1300
+ */
+
+
+/* Configuration data for virtual links 
+ */ 
+struct ospf_vl_config_data {
+  struct vty *vty;             /* vty stuff */
+  struct in_addr area_id;      /* area ID from command line */
+  int format;                  /* command line area ID format */
+  struct in_addr vl_peer;      /* command line vl_peer */
+  int auth_type;               /* Authehntication type, if given */
+  char *auth_key;              /* simple password if present */
+  int crypto_key_id;           /* Cryptographic key ID */
+  char *md5_key;               /* MD5 authentication key */
+  int hello_interval;          /* Obvious what these are... */
+  int retransmit_interval; 
+  int transmit_delay;
+  int dead_interval;
+};
+
+void
+ospf_vl_config_data_init (struct ospf_vl_config_data *vl_config, 
+                         struct vty *vty)
+{
+  memset (vl_config, 0, sizeof (struct ospf_vl_config_data));
+  vl_config->auth_type = OSPF_AUTH_CMD_NOTSEEN;
+  vl_config->vty = vty;
+}
+
+struct ospf_vl_data *
+ospf_find_vl_data (struct ospf_vl_config_data *vl_config)
+{
+  struct ospf_area *area;
+  struct ospf_vl_data *vl_data;
+  struct vty *vty;
+  struct in_addr area_id;
+
+  vty = vl_config->vty;
+  area_id = vl_config->area_id;
+
+  if (area_id.s_addr == OSPF_AREA_BACKBONE)
+    {
+      vty_out (vty, 
+              "Configuring VLs over the backbone is not allowed%s",
+               VTY_NEWLINE);
+      return NULL;
+    }
+  area = ospf_area_get (area_id, vl_config->format);
+
+  if (area->external_routing != OSPF_AREA_DEFAULT)
+    {
+      if (vl_config->format == OSPF_AREA_ID_FORMAT_ADDRESS)
+       vty_out (vty, "Area %s is %s%s",
+                inet_ntoa (area_id),
+#ifdef HAVE_NSSA
+                area->external_routing == OSPF_AREA_NSSA?"nssa":"stub",
+#else
+                "stub",
+#endif /* HAVE_NSSA */          
+                VTY_NEWLINE);
+      else
+       vty_out (vty, "Area %ld is %s%s",
+                (u_long)ntohl (area_id.s_addr),
+#ifdef HAVE_NSSA
+                area->external_routing == OSPF_AREA_NSSA?"nssa":"stub",
+#else
+                "stub",
+#endif /* HAVE_NSSA */          
+                VTY_NEWLINE);  
+      return NULL;
+    }
+  
+  if ((vl_data = ospf_vl_lookup (area, vl_config->vl_peer)) == NULL)
+    {
+      vl_data = ospf_vl_data_new (area, vl_config->vl_peer);
+      if (vl_data->vl_oi == NULL)
+       {
+         vl_data->vl_oi = ospf_vl_new (vl_data);
+         ospf_vl_add (vl_data);
+         ospf_spf_calculate_schedule ();
+       }
+    }
+  return vl_data;
+}
+
+
+int
+ospf_vl_set_security (struct ospf_vl_data *vl_data,
+                     struct ospf_vl_config_data *vl_config)
+{
+  struct crypt_key *ck;
+  struct vty *vty;
+  struct interface *ifp = vl_data->vl_oi->ifp;
+
+  vty = vl_config->vty;
+
+  if (vl_config->auth_type != OSPF_AUTH_CMD_NOTSEEN)
+    {
+      SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
+      IF_DEF_PARAMS (ifp)->auth_type = vl_config->auth_type;
+    }
+
+  if (vl_config->auth_key)
+    {
+      memset(IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE+1);
+      strncpy (IF_DEF_PARAMS (ifp)->auth_simple, vl_config->auth_key, 
+              OSPF_AUTH_SIMPLE_SIZE);
+    }
+  else if (vl_config->md5_key)
+    {
+      if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id) 
+         != NULL)
+       {
+         vty_out (vty, "OSPF: Key %d already exists%s",
+                  vl_config->crypto_key_id, VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      ck = ospf_crypt_key_new ();
+      ck->key_id = vl_config->crypto_key_id;
+      memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1);
+      strncpy (ck->auth_key, vl_config->md5_key, OSPF_AUTH_MD5_SIZE);
+      
+      ospf_crypt_key_add (IF_DEF_PARAMS (ifp)->auth_crypt, ck);
+    }
+  else if (vl_config->crypto_key_id != 0)
+    {
+      /* Delete a key */
+
+      if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, 
+                                vl_config->crypto_key_id) == NULL)
+       {
+         vty_out (vty, "OSPF: Key %d does not exist%s", 
+                  vl_config->crypto_key_id, VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      
+      ospf_crypt_key_delete (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id);
+
+    }
+  
+  return CMD_SUCCESS;
+}
+
+
+
+int
+ospf_vl_set_timers (struct ospf_vl_data *vl_data,
+                   struct ospf_vl_config_data *vl_config)
+{
+  struct interface *ifp = ifp = vl_data->vl_oi->ifp;
+  /* Virtual Link data initialised to defaults, so only set
+     if a value given */
+  if (vl_config->hello_interval)
+    {
+      SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
+      IF_DEF_PARAMS (ifp)->v_hello = vl_config->hello_interval;
+    }
+
+  if (vl_config->dead_interval)
+    {
+      SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
+      IF_DEF_PARAMS (ifp)->v_wait = vl_config->dead_interval;
+    }
+
+  if (vl_config->retransmit_interval)
+    {
+      SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval);
+      IF_DEF_PARAMS (ifp)->retransmit_interval = vl_config->retransmit_interval;
+    }
+  
+  if (vl_config->transmit_delay)
+    {
+      SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay);
+      IF_DEF_PARAMS (ifp)->transmit_delay = vl_config->transmit_delay;
+    }
+  
+  return CMD_SUCCESS;
+}
+
+
+
+/* The business end of all of the above */
+int
+ospf_vl_set (struct ospf_vl_config_data *vl_config)
+{
+  struct ospf_vl_data *vl_data;
+  int ret;
+
+  vl_data = ospf_find_vl_data (vl_config);
+  if (!vl_data)
+    return CMD_WARNING;
+  
+  /* Process this one first as it can have a fatal result, which can
+     only logically occur if the virtual link exists already
+     Thus a command error does not result in a change to the
+     running configuration such as unexpectedly altered timer 
+     values etc.*/
+  ret = ospf_vl_set_security (vl_data, vl_config);
+  if (ret != CMD_SUCCESS)
+    return ret;
+
+  /* Set any time based parameters, these area already range checked */
+
+  ret = ospf_vl_set_timers (vl_data, vl_config);
+  if (ret != CMD_SUCCESS)
+    return ret;
+
+  return CMD_SUCCESS;
+
+}
+
+/* This stuff exists to make specifying all the alias commands A LOT simpler
+ */
+#define VLINK_HELPSTR_IPADDR \
+       "OSPF area parameters\n" \
+       "OSPF area ID in IP address format\n" \
+       "OSPF area ID as a decimal value\n" \
+       "Configure a virtual link\n" \
+       "Router ID of the remote ABR\n"
+
+#define VLINK_HELPSTR_AUTHTYPE_SIMPLE \
+       "Enable authentication on this virtual link\n" \
+       "dummy string \n" 
+
+#define VLINK_HELPSTR_AUTHTYPE_ALL \
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE \
+       "Use null authentication\n" \
+       "Use message-digest authentication\n"
+
+#define VLINK_HELPSTR_TIME_PARAM_NOSECS \
+       "Time between HELLO packets\n" \
+       "Time between retransmitting lost link state advertisements\n" \
+       "Link state transmit delay\n" \
+       "Interval after which a neighbor is declared dead\n"
+
+#define VLINK_HELPSTR_TIME_PARAM \
+       VLINK_HELPSTR_TIME_PARAM_NOSECS \
+       "Seconds\n"
+
+#define VLINK_HELPSTR_AUTH_SIMPLE \
+       "Authentication password (key)\n" \
+       "The OSPF password (key)"
+
+#define VLINK_HELPSTR_AUTH_MD5 \
+       "Message digest authentication password (key)\n" \
+       "dummy string \n" \
+       "Key ID\n" \
+       "Use MD5 algorithm\n" \
+       "The OSPF password (key)"
+
+DEFUN (area_vlink,
+       area_vlink_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D",
+       VLINK_HELPSTR_IPADDR)
+{
+  struct ospf_vl_config_data vl_config;
+  char auth_key[OSPF_AUTH_SIMPLE_SIZE+1];
+  char md5_key[OSPF_AUTH_MD5_SIZE+1]; 
+  int i;
+  int ret;
+  
+  ospf_vl_config_data_init(&vl_config, vty);
+
+  /* Read off first 2 parameters and check them */
+  ret = ospf_str2area_id (argv[0], &vl_config.area_id, &vl_config.format);
+  if (ret < 0)
+    {
+      vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (argv[1], &vl_config.vl_peer);
+  if (! ret)
+    {
+      vty_out (vty, "Please specify valid Router ID as a.b.c.d%s",
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc <=2)
+    {
+      /* Thats all folks! - BUGS B. strikes again!!!*/
+
+      return  ospf_vl_set (&vl_config);
+    }
+
+  /* Deal with other parameters */
+  for (i=2; i < argc; i++)
+    {
+
+      /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */
+
+      switch (argv[i][0])
+       {
+
+       case 'a':
+         if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0)
+           {
+             /* authentication-key - this option can occur anywhere on 
+                                     command line.  At start of command line
+                                     must check for authentication option. */
+             memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1);
+             strncpy (auth_key, argv[i+1], OSPF_AUTH_SIMPLE_SIZE);
+             vl_config.auth_key = auth_key;
+             i++;
+           }
+         else if (strncmp (argv[i], "authentication", 14) == 0)
+           {
+             /* authentication  - this option can only occur at start
+                                  of command line */
+             vl_config.auth_type = OSPF_AUTH_SIMPLE;
+             if ((i+1) < argc)
+               {
+                 if (strncmp (argv[i+1], "n", 1) == 0)
+                   {
+                     /* "authentication null" */
+                     vl_config.auth_type = OSPF_AUTH_NULL;
+                     i++;
+                   }
+                 else if (strncmp (argv[i+1], "m", 1) == 0
+                          && strcmp (argv[i+1], "message-digest-") != 0)
+                   {
+                     /* "authentication message-digest" */ 
+                     vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+                     i++;
+                   }
+               }
+           }
+         break;
+
+       case 'm':
+         /* message-digest-key */
+         i++;
+         vl_config.crypto_key_id = strtol (argv[i], NULL, 10);
+         if (vl_config.crypto_key_id < 0)
+           return CMD_WARNING;
+         i++;
+         memset(md5_key, 0, OSPF_AUTH_MD5_SIZE+1);
+         strncpy (md5_key, argv[i], OSPF_AUTH_MD5_SIZE);
+         vl_config.md5_key = md5_key; 
+         break;
+
+       case 'h':
+         /* Hello interval */
+         i++;
+         vl_config.hello_interval = strtol (argv[i], NULL, 10);
+         if (vl_config.hello_interval < 0) 
+           return CMD_WARNING;
+         break;
+
+       case 'r':
+         /* Retransmit Interval */
+         i++;
+         vl_config.retransmit_interval = strtol (argv[i], NULL, 10);
+         if (vl_config.retransmit_interval < 0)
+           return CMD_WARNING;
+         break;
+
+       case 't':
+         /* Transmit Delay */
+         i++;
+         vl_config.transmit_delay = strtol (argv[i], NULL, 10);
+         if (vl_config.transmit_delay < 0)
+           return CMD_WARNING;
+         break;
+
+       case 'd':
+         /* Dead Interval */
+         i++;
+         vl_config.dead_interval = strtol (argv[i], NULL, 10);
+         if (vl_config.dead_interval < 0)
+           return CMD_WARNING;
+         break;
+       }
+    }
+
+
+  /* Action configuration */
+
+  return ospf_vl_set (&vl_config);
+
+}
+
+DEFUN (no_area_vlink,
+       no_area_vlink_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D",
+       NO_STR
+       VLINK_HELPSTR_IPADDR)
+{
+  struct ospf_area *area;
+  struct ospf_vl_config_data vl_config;
+  struct ospf_vl_data *vl_data = NULL;
+  char auth_key[OSPF_AUTH_SIMPLE_SIZE+1];
+  int i;
+  int ret, format;
+
+  ospf_vl_config_data_init(&vl_config, vty);
+
+  ret = ospf_str2area_id (argv[0], &vl_config.area_id, &format);
+  if (ret < 0)
+    {
+      vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  area = ospf_area_lookup_by_area_id (vl_config.area_id);
+  if (!area)
+    {
+      vty_out (vty, "Area does not exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (argv[1], &vl_config.vl_peer);
+  if (! ret)
+    {
+      vty_out (vty, "Please specify valid Router ID as a.b.c.d%s",
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc <=2)
+    {
+      /* Basic VLink no command */
+      /* Thats all folks! - BUGS B. strikes again!!!*/
+      if ((vl_data = ospf_vl_lookup (area, vl_config.vl_peer)))
+       ospf_vl_delete (vl_data);
+
+      ospf_area_check_free (vl_config.area_id);
+      
+      return CMD_SUCCESS;
+    }
+
+  /* If we are down here, we are reseting parameters */
+
+  /* Deal with other parameters */
+  for (i=2; i < argc; i++)
+    {
+
+      /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */
+
+      switch (argv[i][0])
+       {
+
+       case 'a':
+         if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0)
+           {
+             /* authentication-key - this option can occur anywhere on 
+                                     command line.  At start of command line
+                                     must check for authentication option. */
+             memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1);
+             vl_config.auth_key = auth_key;
+           }
+         else if (strncmp (argv[i], "authentication", 14) == 0)
+           {
+             /* authentication  - this option can only occur at start
+                                  of command line */
+             vl_config.auth_type = OSPF_AUTH_NOTSET;
+           }
+         break;
+
+       case 'm':
+         /* message-digest-key */
+         /* Delete one key */
+         i++;
+         vl_config.crypto_key_id = strtol (argv[i], NULL, 10);
+         if (vl_config.crypto_key_id < 0)
+           return CMD_WARNING;
+         vl_config.md5_key = NULL; 
+         break;
+
+       case 'h':
+         /* Hello interval */
+         vl_config.hello_interval = OSPF_HELLO_INTERVAL_DEFAULT;
+         break;
+
+       case 'r':
+         /* Retransmit Interval */
+         vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT;
+         break;
+
+       case 't':
+         /* Transmit Delay */
+         vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT;
+         break;
+
+       case 'd':
+         /* Dead Interval */
+         i++;
+         vl_config.dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
+         break;
+       }
+    }
+
+
+  /* Action configuration */
+
+  return ospf_vl_set (&vl_config);
+}
+
+ALIAS (area_vlink,
+       area_vlink_param1_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_param1_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+       area_vlink_param2_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_param2_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+       area_vlink_param3_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_param3_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+       area_vlink_param4_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_param4_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM
+       VLINK_HELPSTR_TIME_PARAM)
+
+ALIAS (area_vlink,
+       area_vlink_authtype_args_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) (message-digest|null)",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_ALL)
+
+ALIAS (area_vlink,
+       area_vlink_authtype_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|)",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_authtype_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE)
+
+ALIAS (area_vlink,
+       area_vlink_md5_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(message-digest-key|) <1-255> md5 KEY",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_md5_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(message-digest-key|) <1-255>",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (area_vlink,
+       area_vlink_authkey_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication-key|) AUTH_KEY",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_authkey_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication-key|)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (area_vlink,
+       area_vlink_authtype_args_authkey_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) (message-digest|null) "
+       "(authentication-key|) AUTH_KEY",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_ALL
+       VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (area_vlink,
+       area_vlink_authtype_authkey_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(authentication-key|) AUTH_KEY",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE
+       VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_authtype_authkey_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(authentication-key|)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE
+       VLINK_HELPSTR_AUTH_SIMPLE)
+
+ALIAS (area_vlink,
+       area_vlink_authtype_args_md5_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) (message-digest|null) "
+       "(message-digest-key|) <1-255> md5 KEY",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_ALL
+       VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (area_vlink,
+       area_vlink_authtype_md5_cmd,
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(message-digest-key|) <1-255> md5 KEY",
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE
+       VLINK_HELPSTR_AUTH_MD5)
+
+ALIAS (no_area_vlink,
+       no_area_vlink_authtype_md5_cmd,
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(message-digest-key|)",
+       NO_STR
+       VLINK_HELPSTR_IPADDR
+       VLINK_HELPSTR_AUTHTYPE_SIMPLE
+       VLINK_HELPSTR_AUTH_MD5)
+
+\f
+DEFUN (area_shortcut,
+       area_shortcut_cmd,
+       "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure the area's shortcutting mode\n"
+       "Set default shortcutting behavior\n"
+       "Enable shortcutting through the area\n"
+       "Disable shortcutting through the area\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int mode;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]);
+
+  area = ospf_area_get (area_id, format);
+
+  if (strncmp (argv[1], "de", 2) == 0)
+    mode = OSPF_SHORTCUT_DEFAULT;
+  else if (strncmp (argv[1], "di", 2) == 0)
+    mode = OSPF_SHORTCUT_DISABLE;
+  else if (strncmp (argv[1], "e", 1) == 0)
+    mode = OSPF_SHORTCUT_ENABLE;
+  else
+    return CMD_WARNING;
+
+  ospf_area_shortcut_set (area, mode);
+
+  if (ospf_top->abr_type != OSPF_ABR_SHORTCUT)
+    vty_out (vty, "Shortcut area setting will take effect "
+            "only when the router is configured as Shortcut ABR%s",
+            VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_shortcut,
+       no_area_shortcut_cmd,
+       "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Deconfigure the area's shortcutting mode\n"
+       "Deconfigure enabled shortcutting through the area\n"
+       "Deconfigure disabled shortcutting through the area\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]);
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (!area)
+    return CMD_SUCCESS;
+
+  ospf_area_shortcut_unset (area);
+
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (area_stub,
+       area_stub_cmd,
+       "area (A.B.C.D|<0-4294967295>) stub",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int ret, format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]);
+
+  ret = ospf_area_stub_set (ospf, area_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "First deconfigure all virtual link through this area%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf_area_no_summary_unset (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (area_stub_no_summary,
+       area_stub_no_summary_cmd,
+       "area (A.B.C.D|<0-4294967295>) stub no-summary",
+       "OSPF stub parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n"
+       "Do not inject inter-area routes into stub\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int ret, format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]);
+
+  ret = ospf_area_stub_set (ospf, area_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf_area_no_summary_set (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_stub,
+       no_area_stub_cmd,
+       "no area (A.B.C.D|<0-4294967295>) stub",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]);
+
+  ospf_area_stub_unset (ospf, area_id);
+  ospf_area_no_summary_unset (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_stub_no_summary,
+       no_area_stub_no_summary_cmd,
+       "no area (A.B.C.D|<0-4294967295>) stub no-summary",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n"
+       "Do not inject inter-area routes into area\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]);
+  ospf_area_no_summary_unset (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_NSSA
+DEFUN (area_nssa,
+       area_nssa_cmd,
+       "area (A.B.C.D|<0-4294967295>) nssa",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as nssa\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int ret, format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]);
+
+  ret = ospf_area_nssa_set (ospf, area_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc > 1)
+    {
+      if (strncmp (argv[1], "translate-c", 11) == 0)
+       ospf_area_nssa_translator_role_set (ospf, area_id,
+                                           OSPF_NSSA_ROLE_CANDIDATE);
+      else if (strncmp (argv[1], "translate-n", 11) == 0)
+       ospf_area_nssa_translator_role_set (ospf, area_id,
+                                           OSPF_NSSA_ROLE_NEVER);
+      else if (strncmp (argv[1], "translate-a", 11) == 0)
+       ospf_area_nssa_translator_role_set (ospf, area_id,
+                                           OSPF_NSSA_ROLE_ALWAYS);
+    }
+
+  if (argc > 2)
+    ospf_area_no_summary_set (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (area_nssa,
+       area_nssa_translate_no_summary_cmd,
+       "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always) (no-summary|)",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as nssa\n"
+       "Configure NSSA-ABR for translate election (default)\n"
+       "Configure NSSA-ABR to never translate\n"
+       "Configure NSSA-ABR to always translate\n"
+       "Do not inject inter-area routes into nssa\n"
+       "dummy\n")
+
+ALIAS (area_nssa,
+       area_nssa_translate_cmd,
+       "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always)",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as nssa\n"
+       "Configure NSSA-ABR for translate election (default)\n"
+       "Configure NSSA-ABR to never translate\n"
+       "Configure NSSA-ABR to always translate\n")
+
+DEFUN (area_nssa_no_summary,
+       area_nssa_no_summary_cmd,
+       "area (A.B.C.D|<0-4294967295>) nssa no-summary",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as nssa\n"
+       "Do not inject inter-area routes into nssa\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int ret, format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]);
+
+  ret = ospf_area_nssa_set (ospf, area_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf_area_no_summary_set (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_nssa,
+       no_area_nssa_cmd,
+       "no area (A.B.C.D|<0-4294967295>) nssa",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as nssa\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]);
+
+  ospf_area_nssa_unset (ospf, area_id);
+  ospf_area_no_summary_unset (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_nssa_no_summary,
+       no_area_nssa_no_summary_cmd,
+       "no area (A.B.C.D|<0-4294967295>) nssa no-summary",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as nssa\n"
+       "Do not inject inter-area routes into nssa\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]);
+  ospf_area_no_summary_unset (ospf, area_id);
+
+  return CMD_SUCCESS;
+}
+
+#endif /* HAVE_NSSA */
+
+DEFUN (area_default_cost,
+       area_default_cost_cmd,
+       "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the summary-default cost of a NSSA or stub area\n"
+       "Stub's advertised default summary cost\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  u_int32_t cost;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]);
+  VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215);
+
+  area = ospf_area_get (area_id, format);
+
+  if (area->external_routing == OSPF_AREA_DEFAULT)
+    {
+      vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  area->default_cost = cost;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_default_cost,
+       no_area_default_cost_cmd,
+       "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the summary-default cost of a NSSA or stub area\n"
+       "Stub's advertised default summary cost\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  u_int32_t cost;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]);
+  VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215);
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return CMD_SUCCESS;
+
+  if (area->external_routing == OSPF_AREA_DEFAULT)
+    {
+      vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  area->default_cost = 1;
+
+  ospf_area_check_free (area_id);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (area_export_list,
+       area_export_list_cmd,
+       "area (A.B.C.D|<0-4294967295>) export-list NAME",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the filter for networks announced to other areas\n"
+       "Name of the access-list\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("export-list", area_id, format, argv[0]);
+
+  area = ospf_area_get (area_id, format);
+  ospf_area_export_list_set (area, argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_export_list,
+       no_area_export_list_cmd,
+       "no area (A.B.C.D|<0-4294967295>) export-list NAME",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Unset the filter for networks announced to other areas\n"
+       "Name of the access-list\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("export-list", area_id, format, argv[0]);
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return CMD_SUCCESS;
+
+  ospf_area_export_list_unset (area);
+
+  return CMD_SUCCESS;
+}
+
+
+DEFUN (area_import_list,
+       area_import_list_cmd,
+       "area (A.B.C.D|<0-4294967295>) import-list NAME",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the filter for networks from other areas announced to the specified one\n"
+       "Name of the access-list\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("import-list", area_id, format, argv[0]);
+
+  area = ospf_area_get (area_id, format);
+  ospf_area_import_list_set (area, argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_import_list,
+       no_area_import_list_cmd,
+       "no area (A.B.C.D|<0-4294967295>) import-list NAME",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Unset the filter for networks announced to other areas\n"
+       "Name of the access-list\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID_NO_BB ("import-list", area_id, format, argv[0]);
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return CMD_SUCCESS;
+
+  ospf_area_import_list_unset (area);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (area_filter_list,
+       area_filter_list_cmd,
+       "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Filter networks between OSPF areas\n"
+       "Filter prefixes between OSPF areas\n"
+       "Name of an IP prefix-list\n"
+       "Filter networks sent to this area\n"
+       "Filter networks sent from this area\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  struct prefix_list *plist;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+
+  area = ospf_area_get (area_id, format);
+  plist = prefix_list_lookup (AFI_IP, argv[1]);
+  if (strncmp (argv[2], "in", 2) == 0)
+    {
+      PREFIX_LIST_IN (area) = plist;
+      if (PREFIX_NAME_IN (area))
+       free (PREFIX_NAME_IN (area));
+
+      PREFIX_NAME_IN (area) = strdup (argv[1]);
+      ospf_schedule_abr_task ();
+    }
+  else
+    {
+      PREFIX_LIST_OUT (area) = plist;
+      if (PREFIX_NAME_OUT (area))
+       free (PREFIX_NAME_OUT (area));
+
+      PREFIX_NAME_OUT (area) = strdup (argv[1]);
+      ospf_schedule_abr_task ();
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_filter_list,
+       no_area_filter_list_cmd,
+       "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Filter networks between OSPF areas\n"
+       "Filter prefixes between OSPF areas\n"
+       "Name of an IP prefix-list\n"
+       "Filter networks sent to this area\n"
+       "Filter networks sent from this area\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  struct prefix_list *plist;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  plist = prefix_list_lookup (AFI_IP, argv[1]);
+  if (strncmp (argv[2], "in", 2) == 0)
+    {
+      if (PREFIX_NAME_IN (area))
+       if (strcmp (PREFIX_NAME_IN (area), argv[1]) != 0)
+         return CMD_SUCCESS;
+
+      PREFIX_LIST_IN (area) = NULL;
+      if (PREFIX_NAME_IN (area))
+       free (PREFIX_NAME_IN (area));
+
+      PREFIX_NAME_IN (area) = NULL;
+
+      ospf_schedule_abr_task ();
+    }
+  else
+    {
+      if (PREFIX_NAME_OUT (area))
+       if (strcmp (PREFIX_NAME_OUT (area), argv[1]) != 0)
+         return CMD_SUCCESS;
+
+      PREFIX_LIST_OUT (area) = NULL;
+      if (PREFIX_NAME_OUT (area))
+       free (PREFIX_NAME_OUT (area));
+
+      PREFIX_NAME_OUT (area) = NULL;
+
+      ospf_schedule_abr_task ();
+    }
+
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (area_authentication_message_digest,
+       area_authentication_message_digest_cmd,
+       "area (A.B.C.D|<0-4294967295>) authentication message-digest",
+       "OSPF area parameters\n"
+       "Enable authentication\n"
+       "Use message-digest authentication\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+
+  area = ospf_area_get (area_id, format);
+  area->auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (area_authentication,
+       area_authentication_cmd,
+       "area (A.B.C.D|<0-4294967295>) authentication",
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Enable authentication\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+
+  area = ospf_area_get (area_id, format);
+  area->auth_type = OSPF_AUTH_SIMPLE;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_area_authentication,
+       no_area_authentication_cmd,
+       "no area (A.B.C.D|<0-4294967295>) authentication",
+       NO_STR
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Enable authentication\n")
+{
+  struct ospf_area *area;
+  struct in_addr area_id;
+  int format;
+
+  VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return CMD_SUCCESS;
+
+  area->auth_type = OSPF_AUTH_NULL;
+
+  ospf_area_check_free (area_id);
+  
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (ospf_abr_type,
+       ospf_abr_type_cmd,
+       "ospf abr-type (cisco|ibm|shortcut|standard)",
+       "OSPF specific commands\n"
+       "Set OSPF ABR type\n"
+       "Alternative ABR, cisco implementation\n"
+       "Alternative ABR, IBM implementation\n"
+       "Shortcut ABR\n"
+       "Standard behavior (RFC2328)\n")
+{
+  u_char abr_type = OSPF_ABR_UNKNOWN;
+
+  if (strncmp (argv[0], "c", 1) == 0)
+    abr_type = OSPF_ABR_CISCO;
+  else if (strncmp (argv[0], "i", 1) == 0)
+    abr_type = OSPF_ABR_IBM;
+  else if (strncmp (argv[0], "sh", 2) == 0)
+    abr_type = OSPF_ABR_SHORTCUT;
+  else if (strncmp (argv[0], "st", 2) == 0)
+    abr_type = OSPF_ABR_STAND;
+  else
+    return CMD_WARNING;
+
+  /* If ABR type value is changed, schedule ABR task. */
+  if (ospf_top->abr_type != abr_type)
+    {
+      ospf_top->abr_type = abr_type;
+      ospf_schedule_abr_task ();
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_abr_type,
+       no_ospf_abr_type_cmd,
+       "no ospf abr-type (cisco|ibm|shortcut)",
+       NO_STR
+       "OSPF specific commands\n"
+       "Set OSPF ABR type\n"
+       "Alternative ABR, cisco implementation\n"
+       "Alternative ABR, IBM implementation\n"
+       "Shortcut ABR\n")
+{
+  u_char abr_type = OSPF_ABR_UNKNOWN;
+
+  if (strncmp (argv[0], "c", 1) == 0)
+    abr_type = OSPF_ABR_CISCO;
+  else if (strncmp (argv[0], "i", 1) == 0)
+    abr_type = OSPF_ABR_IBM;
+  else if (strncmp (argv[0], "s", 1) == 0)
+    abr_type = OSPF_ABR_SHORTCUT;
+  else
+    return CMD_WARNING;
+
+  /* If ABR type value is changed, schedule ABR task. */
+  if (ospf_top->abr_type == abr_type)
+    {
+      ospf_top->abr_type = OSPF_ABR_STAND;
+      ospf_schedule_abr_task ();
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_compatible_rfc1583,
+       ospf_compatible_rfc1583_cmd,
+       "compatible rfc1583",
+       "OSPF compatibility list\n"
+       "compatible with RFC 1583\n")
+{
+  struct ospf *ospf = vty->index;
+
+  if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
+    {
+      SET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE);
+      ospf_spf_calculate_schedule ();
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_compatible_rfc1583,
+       no_ospf_compatible_rfc1583_cmd,
+       "no compatible rfc1583",
+       NO_STR
+       "OSPF compatibility list\n"
+       "compatible with RFC 1583\n")
+{
+  struct ospf *ospf = vty->index;
+
+  if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
+    {
+      UNSET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE);
+      ospf_spf_calculate_schedule ();
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (ospf_compatible_rfc1583,
+       ospf_rfc1583_flag_cmd,
+       "ospf rfc1583compatibility",
+       "OSPF specific commands\n"
+       "Enable the RFC1583Compatibility flag\n")
+
+ALIAS (no_ospf_compatible_rfc1583,
+       no_ospf_rfc1583_flag_cmd,
+       "no ospf rfc1583compatibility",
+       NO_STR
+       "OSPF specific commands\n"
+       "Disable the RFC1583Compatibility flag\n")
+
+DEFUN (timers_spf,
+       timers_spf_cmd,
+       "timers spf <0-4294967295> <0-4294967295>",
+       "Adjust routing timers\n"
+       "OSPF SPF timers\n"
+       "Delay between receiving a change to SPF calculation\n"
+       "Hold time between consecutive SPF calculations\n")
+{
+  struct ospf *ospf = vty->index;
+  u_int32_t delay, hold;
+
+  VTY_GET_UINT32 ("SPF delay timer", delay, argv[0]);
+  VTY_GET_UINT32 ("SPF hold timer", hold, argv[1]);
+
+  ospf_timers_spf_set (ospf, delay, hold);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_timers_spf,
+       no_timers_spf_cmd,
+       "no timers spf",
+       NO_STR
+       "Adjust routing timers\n"
+       "OSPF SPF timers\n")
+{
+  ospf_top->spf_delay = OSPF_SPF_DELAY_DEFAULT;
+  ospf_top->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT;
+
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (neighbor,
+       neighbor_cmd,
+       "neighbor A.B.C.D",
+       NEIGHBOR_STR
+       "Neighbor IP address\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr nbr_addr;
+  int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
+  int interval = OSPF_POLL_INTERVAL_DEFAULT;
+
+  VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]);
+
+  if (argc > 1)
+    VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[1], 0, 255);
+
+  if (argc > 2)
+    VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[2], 1, 65535);
+
+  ospf_nbr_nbma_set (ospf, nbr_addr);
+  if (argc > 1)
+    ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority);
+  if (argc > 2)
+    ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, priority);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (neighbor,
+       neighbor_priority_poll_interval_cmd,
+       "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>",
+       NEIGHBOR_STR
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Priority\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+ALIAS (neighbor,
+       neighbor_priority_cmd,
+       "neighbor A.B.C.D priority <0-255>",
+       NEIGHBOR_STR
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Seconds\n")
+
+DEFUN (neighbor_poll_interval,
+       neighbor_poll_interval_cmd,
+       "neighbor A.B.C.D poll-interval <1-65535>",
+       NEIGHBOR_STR
+       "Neighbor IP address\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr nbr_addr;
+  int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
+  int interval = OSPF_POLL_INTERVAL_DEFAULT;
+
+  VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]);
+
+  if (argc > 1)
+    VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[1], 1, 65535);
+
+  if (argc > 2)
+    VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[2], 0, 255);
+
+  ospf_nbr_nbma_set (ospf, nbr_addr);
+  if (argc > 1)
+    ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, interval);
+  if (argc > 2)
+    ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (neighbor_poll_interval,
+       neighbor_poll_interval_priority_cmd,
+       "neighbor A.B.C.D poll-interval <1-65535> priority <0-255>",
+       NEIGHBOR_STR
+       "Neighbor address\n"
+       "OSPF dead-router polling interval\n"
+       "Seconds\n"
+       "OSPF priority of non-broadcast neighbor\n"
+       "Priority\n")
+
+DEFUN (no_neighbor,
+       no_neighbor_cmd,
+       "no neighbor A.B.C.D",
+       NO_STR
+       NEIGHBOR_STR
+       "Neighbor IP address\n")
+{
+  struct ospf *ospf = vty->index;
+  struct in_addr nbr_addr;
+  int ret;
+
+  VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]);
+
+  ret = ospf_nbr_nbma_unset (ospf, nbr_addr);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_neighbor,
+       no_neighbor_priority_cmd,
+       "no neighbor A.B.C.D priority <0-255>",
+       NO_STR
+       NEIGHBOR_STR
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Priority\n")
+
+ALIAS (no_neighbor,
+       no_neighbor_poll_interval_cmd,
+       "no neighbor A.B.C.D poll-interval <1-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       "Neighbor IP address\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+ALIAS (no_neighbor,
+       no_neighbor_priority_pollinterval_cmd,
+       "no neighbor A.B.C.D priority <0-255> poll-interval <1-65535>",
+       NO_STR
+       NEIGHBOR_STR
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Priority\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+\f
+DEFUN (refresh_timer, refresh_timer_cmd,
+       "refresh timer <10-1800>",
+       "Adjust refresh parameters\n"
+       "Set refresh timer\n"
+       "Timer value in seconds\n")
+{
+  struct ospf *ospf = vty->index;
+  int interval;
+  
+  VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800);
+  interval = (interval / 10) * 10;
+
+  ospf_timers_refresh_set (ospf, interval);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_refresh_timer, no_refresh_timer_val_cmd,
+       "no refresh timer <10-1800>",
+       "Adjust refresh parameters\n"
+       "Unset refresh timer\n"
+       "Timer value in seconds\n")
+{
+  struct ospf *ospf = vty->index;
+  int interval;
+
+  if (argc == 1)
+    {
+      VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800);
+  
+      if (ospf->lsa_refresh_interval != interval ||
+         interval == OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
+       return CMD_SUCCESS;
+    }
+
+  ospf_timers_refresh_unset (ospf);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_refresh_timer,
+       no_refresh_timer_cmd,
+       "no refresh timer",
+       "Adjust refresh parameters\n"
+       "Unset refresh timer\n")
+
+DEFUN (auto_cost_reference_bandwidth,
+       auto_cost_reference_bandwidth_cmd,
+       "auto-cost reference-bandwidth <1-4294967>",
+       "Calculate OSPF interface cost according to bandwidth\n"
+       "Use reference bandwidth method to assign OSPF cost\n"
+       "The reference bandwidth in terms of Mbits per second\n")
+{
+  u_int32_t refbw;
+  listnode node;
+
+  refbw = strtol (argv[0], NULL, 10);
+  if (refbw < 1 || refbw > 4294967)
+    {
+      vty_out (vty, "reference-bandwidth value is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* If reference bandwidth is changed. */
+  if ((refbw * 1000) == ospf_top->ref_bandwidth)
+    return CMD_SUCCESS;
+  
+  ospf_top->ref_bandwidth = refbw * 1000;
+  vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE);
+  vty_out (vty, "        Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE);
+      
+  for (node = listhead (ospf_top->iflist); node; nextnode (node))
+      ospf_if_recalculate_output_cost (getdata (node));
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_auto_cost_reference_bandwidth,
+       no_auto_cost_reference_bandwidth_cmd,
+       "no auto-cost reference-bandwidth",
+       NO_STR
+       "Calculate OSPF interface cost according to bandwidth\n"
+       "Use reference bandwidth method to assign OSPF cost\n")
+{
+  listnode node;
+
+  if (ospf_top->ref_bandwidth == OSPF_DEFAULT_REF_BANDWIDTH)
+    return CMD_SUCCESS;
+  
+  ospf_top->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH;
+  vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE);
+  vty_out (vty, "        Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE);
+
+  
+    for (node = listhead (ospf_top->iflist); node; nextnode (node))
+      ospf_if_recalculate_output_cost (getdata (node));
+      
+  return CMD_SUCCESS;
+}
+
+\f
+DEFUN (clear_ip_ospf_neighbor,
+       clear_ip_ospf_neighbor_cmd,
+       "clear ip ospf neighbor A.B.C.D",
+       "Reset functions\n"
+       "IP\n"
+       "Clear OSPF\n"
+       "Neighbor list\n"
+       "Neighbor ID\n")
+{
+  listnode node;
+  struct ospf_neighbor *nbr;
+  struct in_addr router_id;
+  int ret;
+
+  ret = inet_aton (argv[0], &router_id);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify Neighbor ID by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+
+      nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id);
+
+      if (nbr)
+       {
+         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
+         vty_out (vty, "clear neighbor %s%s", argv[0], VTY_NEWLINE);
+         break;
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+char *ospf_abr_type_descr_str[] = 
+{
+  "Unknown",
+  "Standard (RFC2328)",
+  "Alternative IBM",
+  "Alternative Cisco",
+  "Alternative Shortcut"
+};
+
+char *ospf_shortcut_mode_descr_str[] = 
+{
+  "Default",
+  "Enabled",
+  "Disabled"
+};
+
+
+\f
+void
+show_ip_ospf_area (struct vty *vty, struct ospf_area *area)
+{
+  /* Show Area ID. */
+  vty_out (vty, " Area ID: %s", inet_ntoa (area->area_id));
+
+  /* Show Area type/mode. */
+  if (OSPF_IS_AREA_BACKBONE (area))
+    vty_out (vty, " (Backbone)%s", VTY_NEWLINE);
+  else
+    {
+      if (area->external_routing == OSPF_AREA_STUB)
+       vty_out (vty, " (Stub%s%s)",
+                area->no_summary ? ", no summary" : "",
+                area->shortcut_configured ? "; " : "");
+
+#ifdef HAVE_NSSA
+
+      else
+      if (area->external_routing == OSPF_AREA_NSSA)
+       vty_out (vty, " (NSSA%s%s)",
+                area->no_summary ? ", no summary" : "",
+                area->shortcut_configured ? "; " : "");
+#endif /* HAVE_NSSA */
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "   Shortcutting mode: %s",
+              ospf_shortcut_mode_descr_str[area->shortcut_configured]);
+      vty_out (vty, ", S-bit consensus: %s%s",
+              area->shortcut_capability ? "ok" : "no", VTY_NEWLINE);
+    }
+
+  /* Show number of interfaces. */
+  vty_out (vty, "   Number of interfaces in this area: Total: %d, "
+          "Active: %d%s", listcount (area->oiflist),
+          area->act_ints, VTY_NEWLINE);
+
+#ifdef HAVE_NSSA
+  if (area->external_routing == OSPF_AREA_NSSA)
+    {
+      vty_out (vty, "   It is an NSSA configuration. %s   Elected NSSA/ABR performs type-7/type-5 LSA translation. %s", VTY_NEWLINE, VTY_NEWLINE);
+      if (! OSPF_IS_ABR)
+       vty_out (vty, "   It is not ABR, therefore not Translator. %s",
+                VTY_NEWLINE);
+      else
+       {
+         if (area->NSSATranslator)
+           vty_out (vty, "   We are an ABR and the NSSA Elected Translator. %s", VTY_NEWLINE);
+         else
+           vty_out (vty, "   We are an ABR, but not the NSSA Elected Translator. %s", VTY_NEWLINE);
+       }
+    }
+#endif /* HAVE_NSSA */
+
+  /* Show number of fully adjacent neighbors. */
+  vty_out (vty, "   Number of fully adjacent neighbors in this area:"
+          " %d%s", area->full_nbrs, VTY_NEWLINE);
+
+  /* Show authentication type. */
+  vty_out (vty, "   Area has ");
+  if (area->auth_type == OSPF_AUTH_NULL)
+    vty_out (vty, "no authentication%s", VTY_NEWLINE);
+  else if (area->auth_type == OSPF_AUTH_SIMPLE)
+    vty_out (vty, "simple password authentication%s", VTY_NEWLINE);
+  else if (area->auth_type == OSPF_AUTH_CRYPTOGRAPHIC)
+    vty_out (vty, "message digest authentication%s", VTY_NEWLINE);
+
+  if (!OSPF_IS_AREA_BACKBONE (area))
+    vty_out (vty, "   Number of full virtual adjacencies going through"
+            " this area: %d%s", area->full_vls, VTY_NEWLINE);
+
+  /* Show SPF calculation times. */
+  vty_out (vty, "   SPF algorithm executed %d times%s",
+          area->spf_calculation, VTY_NEWLINE);
+
+  /* Show number of LSA. */
+  vty_out (vty, "   Number of LSA %ld%s", area->lsdb->total, VTY_NEWLINE);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+DEFUN (show_ip_ospf,
+       show_ip_ospf_cmd,
+       "show ip ospf",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n")
+{
+  listnode node;
+  struct ospf_area * area;
+
+  /* Check OSPF is enable. */
+  if (ospf_top == NULL)
+    {
+      vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* Show Router ID. */
+  vty_out (vty, " OSPF Routing Process, Router ID: %s%s",
+           inet_ntoa (ospf_top->router_id),
+           VTY_NEWLINE);
+
+  /* Show capability. */
+  vty_out (vty, " Supports only single TOS (TOS0) routes%s", VTY_NEWLINE);
+  vty_out (vty, " This implementation conforms to RFC2328%s", VTY_NEWLINE);
+  vty_out (vty, " RFC1583Compatibility flag is %s%s",
+          CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE) ?
+          "enabled" : "disabled", VTY_NEWLINE);
+#ifdef HAVE_OPAQUE_LSA
+  vty_out (vty, " OpaqueCapability flag is %s%s%s",
+          CHECK_FLAG (ospf_top->config, OSPF_OPAQUE_CAPABLE) ?
+           "enabled" : "disabled",
+           IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf_top->opaque) ?
+           " (origination blocked)" : "",
+           VTY_NEWLINE);
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Show SPF timers. */
+  vty_out (vty, " SPF schedule delay %d secs, Hold time between two SPFs %d secs%s",
+          ospf_top->spf_delay, ospf_top->spf_holdtime, VTY_NEWLINE);
+
+  /* Show refresh parameters. */
+  vty_out (vty, " Refresh timer %d secs%s",
+          ospf_top->lsa_refresh_interval, VTY_NEWLINE);
+          
+  /* Show ABR/ASBR flags. */
+  if (CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ABR))
+    vty_out (vty, " This router is an ABR, ABR type is: %s%s",
+             ospf_abr_type_descr_str[ospf_top->abr_type], VTY_NEWLINE);
+
+  if (CHECK_FLAG (ospf_top->flags, OSPF_FLAG_ASBR))
+    vty_out (vty, " This router is an ASBR "
+             "(injecting external routing information)%s", VTY_NEWLINE);
+
+  /* Show Number of AS-external-LSAs. */
+  vty_out (vty, " Number of external LSA %ld%s",
+          ospf_lsdb_count_all (ospf_top->lsdb), VTY_NEWLINE);
+
+  /* Show number of areas attached. */
+  vty_out (vty, " Number of areas attached to this router: %d%s%s",
+           listcount (ospf_top->areas), VTY_NEWLINE, VTY_NEWLINE);
+
+  /* Show each area status. */
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    if ((area = getdata (node)) != NULL)
+      show_ip_ospf_area (vty, area);
+
+  return CMD_SUCCESS;
+}
+
+\f
+void
+show_ip_ospf_interface_sub (struct vty *vty, struct interface *ifp)
+{
+  struct ospf_neighbor *nbr;
+  int oi_count;
+  struct route_node *rn;
+  char buf[9];
+
+  oi_count = ospf_oi_count (ifp);
+  
+  /* Is interface up? */
+  if (if_is_up (ifp))
+    vty_out (vty, "%s is up, line protocol is up%s", ifp->name, VTY_NEWLINE);
+  else
+    {
+      vty_out (vty, "%s is down, line protocol is down%s", ifp->name,
+              VTY_NEWLINE);
+
+      
+      if (oi_count == 0)
+       vty_out (vty, "  OSPF not enabled on this interface%s", VTY_NEWLINE);
+      else
+       vty_out (vty, "  OSPF is enabled, but not running on this interface%s",
+                VTY_NEWLINE);
+      return;
+    }
+
+  /* Is interface OSPF enabled? */
+  if (oi_count == 0)
+    {
+      vty_out (vty, "  OSPF not enabled on this interface%s", VTY_NEWLINE);
+      return;
+    }
+  
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      struct ospf_interface *oi = rn->info;
+      
+      if (oi == NULL)
+       continue;
+      
+      /* Show OSPF interface information. */
+      vty_out (vty, "  Internet Address %s/%d,",
+              inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
+
+      vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area),
+              VTY_NEWLINE);
+
+      vty_out (vty, "  Router ID %s, Network Type %s, Cost: %d%s",
+              inet_ntoa (ospf_top->router_id), ospf_network_type_str[oi->type],
+              oi->output_cost, VTY_NEWLINE);
+
+      vty_out (vty, "  Transmit Delay is %d sec, State %s, Priority %d%s",
+              OSPF_IF_PARAM (oi,transmit_delay), LOOKUP (ospf_ism_state_msg, oi->state),
+              PRIORITY (oi), VTY_NEWLINE);
+
+  /* Show DR information. */
+      if (DR (oi).s_addr == 0)
+       vty_out (vty, "  No designated router on this network%s", VTY_NEWLINE);
+      else
+       {
+         nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi));
+         if (nbr == NULL)
+           vty_out (vty, "  No designated router on this network%s", VTY_NEWLINE);
+         else
+           {
+             vty_out (vty, "  Designated Router (ID) %s,",
+                      inet_ntoa (nbr->router_id));
+             vty_out (vty, " Interface Address %s%s",
+                      inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
+           }
+       }
+
+      /* Show BDR information. */
+      if (BDR (oi).s_addr == 0)
+       vty_out (vty, "  No backup designated router on this network%s",
+                VTY_NEWLINE);
+      else
+       {
+         nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &BDR (oi));
+         if (nbr == NULL)
+           vty_out (vty, "  No backup designated router on this network%s",
+                    VTY_NEWLINE);
+         else
+           {
+             vty_out (vty, "  Backup Designated Router (ID) %s,",
+                      inet_ntoa (nbr->router_id));
+             vty_out (vty, " Interface Address %s%s",
+                      inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
+           }
+       }
+      vty_out (vty, "  Timer intervals configured,");
+      vty_out (vty, " Hello %d, Dead %d, Wait %d, Retransmit %d%s",
+              OSPF_IF_PARAM (oi, v_hello), OSPF_IF_PARAM (oi, v_wait),
+              OSPF_IF_PARAM (oi, v_wait),
+              OSPF_IF_PARAM (oi, retransmit_interval),
+              VTY_NEWLINE);
+      
+      if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_ACTIVE)
+       vty_out (vty, "    Hello due in %s%s",
+                ospf_timer_dump (oi->t_hello, buf, 9), VTY_NEWLINE);
+      else /* OSPF_IF_PASSIVE is set */
+       vty_out (vty, "    No Hellos (Passive interface)%s", VTY_NEWLINE);
+      
+      vty_out (vty, "  Neighbor Count is %d, Adjacent neighbor count is %d%s",
+              ospf_nbr_count (oi->nbrs, 0), ospf_nbr_count (oi->nbrs, NSM_Full),
+              VTY_NEWLINE);
+    }
+}
+
+DEFUN (show_ip_ospf_interface,
+       show_ip_ospf_interface_cmd,
+       "show ip ospf interface [INTERFACE]",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Interface information\n"
+       "Interface name\n")
+{
+  struct interface *ifp;
+  listnode node;
+
+  /* Show All Interfaces. */
+  if (argc == 0)
+    for (node = listhead (iflist); node; nextnode (node))
+      show_ip_ospf_interface_sub (vty, node->data);
+  /* Interface name is specified. */
+  else
+    {
+      if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+        vty_out (vty, "No such interface name%s", VTY_NEWLINE);
+      else
+        show_ip_ospf_interface_sub (vty, ifp);
+    }
+
+  return CMD_SUCCESS;
+}
+
+void
+show_ip_ospf_neighbor_sub (struct vty *vty, struct ospf_interface *oi)
+{
+  struct route_node *rn;
+  struct ospf_neighbor *nbr;
+  char msgbuf[16];
+  char timebuf[9];
+
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info))
+      /* Do not show myself. */
+      if (nbr != oi->nbr_self)
+       /* Down state is not shown. */
+       if (nbr->state != NSM_Down)
+         {
+           ospf_nbr_state_message (nbr, msgbuf, 16);
+
+           if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0)
+           vty_out (vty, "%-15s %3d   %-15s %8s    ",
+                    "-", nbr->priority,
+                    msgbuf, ospf_timer_dump (nbr->t_inactivity, timebuf, 9));
+           else
+           vty_out (vty, "%-15s %3d   %-15s %8s    ",
+                    inet_ntoa (nbr->router_id), nbr->priority,
+                    msgbuf, ospf_timer_dump (nbr->t_inactivity, timebuf, 9));
+           vty_out (vty, "%-15s ", inet_ntoa (nbr->src));
+           vty_out (vty, "%-15s %5ld %5ld %5d%s",
+                    IF_NAME (oi), ospf_ls_retransmit_count (nbr),
+                    ospf_ls_request_count (nbr), ospf_db_summary_count (nbr),
+                    VTY_NEWLINE);
+         }
+}
+
+DEFUN (show_ip_ospf_neighbor,
+       show_ip_ospf_neighbor_cmd,
+       "show ip ospf neighbor",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n")
+{
+  listnode node;
+
+  if (!ospf_top)
+    {
+      vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* Show All neighbors. */
+  vty_out (vty, "%sNeighbor ID     Pri   State           Dead "
+           "Time   Address         Interface           RXmtL "
+           "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE);
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+      show_ip_ospf_neighbor_sub (vty, getdata (node));
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_ospf_neighbor_all,
+       show_ip_ospf_neighbor_all_cmd,
+       "show ip ospf neighbor all",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n"
+       "include down status neighbor\n")
+{
+  listnode node;
+
+  if (!ospf_top)
+    {
+      vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* Show All neighbors. */
+  vty_out (vty, "%sNeighbor ID     Pri   State           Dead "
+           "Time   Address         Interface           RXmtL "
+           "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE);
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      listnode nbr_node;
+
+      show_ip_ospf_neighbor_sub (vty, oi);
+
+    /* print Down neighbor status */
+    for (nbr_node = listhead (oi->nbr_nbma); nbr_node; nextnode (nbr_node))
+      {
+       struct ospf_nbr_nbma *nbr_nbma;
+
+       nbr_nbma = getdata (nbr_node);
+
+       if (nbr_nbma->nbr == NULL
+           || nbr_nbma->nbr->state == NSM_Down)
+         {
+           vty_out (vty, "%-15s %3d   %-15s %8s    ",
+                    "-", nbr_nbma->priority, "Down", "-");
+           vty_out (vty, "%-15s %-15s %5d %5d %5d%s", 
+                    inet_ntoa (nbr_nbma->addr), IF_NAME (oi),
+                    0, 0, 0, VTY_NEWLINE);
+         }
+      }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_ospf_neighbor_int,
+       show_ip_ospf_neighbor_int_cmd,
+       "show ip ospf neighbor A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n"
+       "Interface name\n")
+{
+  struct ospf_interface *oi;
+  struct in_addr addr;
+  int ret;
+  
+  if (!ospf_top)
+    {
+      vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  ret = inet_aton (argv[0], &addr);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify interface address by A.B.C.D%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if ((oi = ospf_if_is_configured (&addr)) == NULL)
+    vty_out (vty, "No such interface address%s", VTY_NEWLINE);
+  else
+    {
+      vty_out (vty, "%sNeighbor ID     Pri   State           Dead "
+               "Time   Address         Interface           RXmtL "
+               "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE);
+      show_ip_ospf_neighbor_sub (vty, oi);
+    }
+
+  return CMD_SUCCESS;
+}
+
+void
+show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi,
+                                 struct ospf_nbr_nbma *nbr_nbma)
+{
+  char timebuf[9];
+
+  /* Show neighbor ID. */
+  vty_out (vty, " Neighbor %s,", "-");
+
+  /* Show interface address. */
+  vty_out (vty, " interface address %s%s",
+          inet_ntoa (nbr_nbma->addr), VTY_NEWLINE);
+  /* Show Area ID. */
+  vty_out (vty, "    In the area %s via interface %s%s",
+          ospf_area_desc_string (oi->area), IF_NAME (oi), VTY_NEWLINE);
+  /* Show neighbor priority and state. */
+  vty_out (vty, "    Neighbor priority is %d, State is %s,",
+          nbr_nbma->priority, "Down");
+  /* Show state changes. */
+  vty_out (vty, " %d state changes%s", nbr_nbma->state_change, VTY_NEWLINE);
+
+  /* Show PollInterval */
+  vty_out (vty, "    Poll interval %d%s", nbr_nbma->v_poll, VTY_NEWLINE);
+
+  /* Show poll-interval timer. */
+  vty_out (vty, "    Poll timer due in %s%s",
+          ospf_timer_dump (nbr_nbma->t_poll, timebuf, 9), VTY_NEWLINE);
+
+  /* Show poll-interval timer thread. */
+  vty_out (vty, "    Thread Poll Timer %s%s", 
+          nbr_nbma->t_poll != NULL ? "on" : "off", VTY_NEWLINE);
+}
+
+void
+show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
+                                 struct ospf_neighbor *nbr)
+{
+  char timebuf[9];
+
+  /* Show neighbor ID. */
+  if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0)
+    vty_out (vty, " Neighbor %s,", "-");
+  else
+  vty_out (vty, " Neighbor %s,", inet_ntoa (nbr->router_id));
+
+  /* Show interface address. */
+  vty_out (vty, " interface address %s%s",
+          inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
+  /* Show Area ID. */
+  vty_out (vty, "    In the area %s via interface %s%s",
+          ospf_area_desc_string (oi->area), oi->ifp->name, VTY_NEWLINE);
+  /* Show neighbor priority and state. */
+  vty_out (vty, "    Neighbor priority is %d, State is %s,",
+          nbr->priority, LOOKUP (ospf_nsm_state_msg, nbr->state));
+  /* Show state changes. */
+  vty_out (vty, " %d state changes%s", nbr->state_change, VTY_NEWLINE);
+
+  /* Show Designated Rotuer ID. */
+  vty_out (vty, "    DR is %s,", inet_ntoa (nbr->d_router));
+  /* Show Backup Designated Rotuer ID. */
+  vty_out (vty, " BDR is %s%s", inet_ntoa (nbr->bd_router), VTY_NEWLINE);
+  /* Show options. */
+  vty_out (vty, "    Options %d %s%s", nbr->options,
+          ospf_options_dump (nbr->options), VTY_NEWLINE);
+  /* Show Router Dead interval timer. */
+  vty_out (vty, "    Dead timer due in %s%s",
+          ospf_timer_dump (nbr->t_inactivity, timebuf, 9), VTY_NEWLINE);
+  /* Show Database Summary list. */
+  vty_out (vty, "    Database Summary List %d%s",
+          ospf_db_summary_count (nbr), VTY_NEWLINE);
+  /* Show Link State Request list. */
+  vty_out (vty, "    Link State Request List %ld%s",
+          ospf_ls_request_count (nbr), VTY_NEWLINE);
+  /* Show Link State Retransmission list. */
+  vty_out (vty, "    Link State Retransmission List %ld%s",
+          ospf_ls_retransmit_count (nbr), VTY_NEWLINE);
+  /* Show inactivity timer thread. */
+  vty_out (vty, "    Thread Inactivity Timer %s%s", 
+          nbr->t_inactivity != NULL ? "on" : "off", VTY_NEWLINE);
+  /* Show Database Description retransmission thread. */
+  vty_out (vty, "    Thread Database Description Retransmision %s%s",
+          nbr->t_db_desc != NULL ? "on" : "off", VTY_NEWLINE);
+  /* Show Link State Request Retransmission thread. */
+  vty_out (vty, "    Thread Link State Request Retransmission %s%s",
+          nbr->t_ls_req != NULL ? "on" : "off", VTY_NEWLINE);
+  /* Show Link State Update Retransmission thread. */
+  vty_out (vty, "    Thread Link State Update Retransmission %s%s%s",
+          nbr->t_ls_upd != NULL ? "on" : "off", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+DEFUN (show_ip_ospf_neighbor_id,
+       show_ip_ospf_neighbor_id_cmd,
+       "show ip ospf neighbor A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n"
+       "Neighbor ID\n")
+{
+  listnode node;
+  struct ospf_neighbor *nbr;
+  struct in_addr router_id;
+  int ret;
+
+  ret = inet_aton (argv[0], &router_id);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify Neighbor ID by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+
+      if ((nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id)))
+       {
+         show_ip_ospf_neighbor_detail_sub (vty, oi, nbr);
+         return CMD_SUCCESS;
+       }
+    }
+
+  /* Nothing to show. */
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_ospf_neighbor_detail,
+       show_ip_ospf_neighbor_detail_cmd,
+       "show ip ospf neighbor detail",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n"
+       "detail of all neighbors\n")
+{
+  listnode node;
+
+  if (!ospf_top)
+    return CMD_SUCCESS;
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info))
+         if (nbr != oi->nbr_self)
+           if (nbr->state != NSM_Down)
+             show_ip_ospf_neighbor_detail_sub (vty, oi, nbr);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_ospf_neighbor_detail_all,
+       show_ip_ospf_neighbor_detail_all_cmd,
+       "show ip ospf neighbor detail all",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n"
+       "detail of all neighbors\n"
+       "include down status neighbor\n")
+{
+  listnode node;
+
+  if (!ospf_top)
+    return CMD_SUCCESS;
+
+  for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info))
+         if (nbr != oi->nbr_self)
+           if (oi->type == OSPF_IFTYPE_NBMA && nbr->state != NSM_Down)
+             show_ip_ospf_neighbor_detail_sub (vty, oi, rn->info);
+
+      if (oi->type == OSPF_IFTYPE_NBMA)
+       {
+         listnode nd;
+
+         for (nd = listhead (oi->nbr_nbma); nd; nextnode (nd))
+           {
+             struct ospf_nbr_nbma *nbr_nbma = getdata (nd);
+             if (nbr_nbma->nbr == NULL
+                 || nbr_nbma->nbr->state == NSM_Down)
+               show_ip_ospf_nbr_nbma_detail_sub (vty, oi, nbr_nbma);
+           }
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_ospf_neighbor_int_detail,
+       show_ip_ospf_neighbor_int_detail_cmd,
+       "show ip ospf neighbor A.B.C.D detail",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Neighbor list\n"
+       "Interface address\n"
+       "detail of all neighbors")
+{
+  struct ospf_interface *oi;
+  struct in_addr addr;
+  int ret;
+  
+  ret = inet_aton (argv[0], &addr);
+  if (!ret)
+    {
+      vty_out (vty, "Please specify interface address by A.B.C.D%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if ((oi = ospf_if_is_configured (&addr)) == NULL)
+    vty_out (vty, "No such interface address%s", VTY_NEWLINE);
+  else
+    {
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+
+      for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+       if ((nbr = rn->info))
+         if (nbr != oi->nbr_self)
+           if (nbr->state != NSM_Down)
+             show_ip_ospf_neighbor_detail_sub (vty, oi, nbr);
+    }
+
+  return CMD_SUCCESS;
+}
+
+\f
+/* Show functions */
+int
+show_lsa_summary (struct ospf_lsa *lsa, void *v, int self)
+{
+  struct vty *vty = (struct vty *) v;
+  struct router_lsa *rl;
+  struct summary_lsa *sl;
+  struct as_external_lsa *asel;
+  struct prefix_ipv4 p;
+
+  if (lsa != NULL)
+    /* If self option is set, check LSA self flag. */
+    if (self == 0 || IS_LSA_SELF (lsa))
+      {
+       /* LSA common part show. */
+       vty_out (vty, "%-15s ", inet_ntoa (lsa->data->id));
+       vty_out (vty, "%-15s %4d 0x%08lx 0x%04x",
+                inet_ntoa (lsa->data->adv_router), LS_AGE (lsa),
+                (u_long)ntohl (lsa->data->ls_seqnum), ntohs (lsa->data->checksum));
+       /* LSA specific part show. */
+       switch (lsa->data->type)
+         {
+         case OSPF_ROUTER_LSA:
+           rl = (struct router_lsa *) lsa->data;
+           vty_out (vty, " %-d", ntohs (rl->links));
+           break;
+         case OSPF_SUMMARY_LSA:
+           sl = (struct summary_lsa *) lsa->data;
+
+           p.family = AF_INET;
+           p.prefix = sl->header.id;
+           p.prefixlen = ip_masklen (sl->mask);
+           apply_mask_ipv4 (&p);
+
+           vty_out (vty, " %s/%d", inet_ntoa (p.prefix), p.prefixlen);
+           break;
+         case OSPF_AS_EXTERNAL_LSA:
+           asel = (struct as_external_lsa *) lsa->data;
+
+           p.family = AF_INET;
+           p.prefix = asel->header.id;
+           p.prefixlen = ip_masklen (asel->mask);
+           apply_mask_ipv4 (&p);
+
+           vty_out (vty, " %s %s/%d [0x%lx]",
+                    IS_EXTERNAL_METRIC (asel->e[0].tos) ? "E2" : "E1",
+                    inet_ntoa (p.prefix), p.prefixlen,
+                    (u_long)ntohl (asel->e[0].route_tag));
+           break;
+         case OSPF_NETWORK_LSA:
+         case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_OPAQUE_LSA
+         case OSPF_OPAQUE_LINK_LSA:
+         case OSPF_OPAQUE_AREA_LSA:
+         case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+         default:
+           break;
+         }
+       vty_out (vty, VTY_NEWLINE);
+      }
+
+  return 0;
+}
+
+char *show_database_desc[] =
+{
+  "unknown",
+  "Router Link States",
+  "Net Link States",
+  "Summary Link States",
+  "ASBR-Summary Link States",
+  "AS External Link States",
+#if defined  (HAVE_NSSA) || defined (HAVE_OPAQUE_LSA)
+  "Group Membership LSA",
+  "NSSA-external Link States",
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+  "Type-8 LSA",
+  "Link-Local Opaque-LSA",
+  "Area-Local Opaque-LSA",
+  "AS-external Opaque-LSA",
+#endif /* HAVE_OPAQUE_LSA */
+};
+
+#define SHOW_OSPF_COMMON_HEADER \
+  "Link ID         ADV Router      Age  Seq#       CkSum"
+
+char *show_database_header[] =
+{
+  "",
+  "Link ID         ADV Router      Age  Seq#       CkSum  Link count",
+  "Link ID         ADV Router      Age  Seq#       CkSum",
+  "Link ID         ADV Router      Age  Seq#       CkSum  Route",
+  "Link ID         ADV Router      Age  Seq#       CkSum",
+  "Link ID         ADV Router      Age  Seq#       CkSum  Route",
+#ifdef HAVE_NSSA
+  " --- header for Group Member ----",
+  "Link ID         ADV Router      Age  Seq#       CkSum  Route",
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+#ifndef HAVE_NSSA
+  " --- type-6 ---",
+  " --- type-7 ---",
+#endif /* HAVE_NSSA */
+  " --- type-8 ---",
+  "Opaque-Type/Id  ADV Router      Age  Seq#       CkSum",
+  "Opaque-Type/Id  ADV Router      Age  Seq#       CkSum",
+  "Opaque-Type/Id  ADV Router      Age  Seq#       CkSum",
+#endif /* HAVE_OPAQUE_LSA */
+};
+
+void
+show_ip_ospf_database_header (struct vty *vty, struct ospf_lsa *lsa)
+{
+  struct router_lsa *rlsa = (struct router_lsa*) lsa->data;
+
+  vty_out (vty, "  LS age: %d%s", LS_AGE (lsa), VTY_NEWLINE);
+  vty_out (vty, "  Options: %d%s", lsa->data->options, VTY_NEWLINE);
+
+  if (lsa->data->type == OSPF_ROUTER_LSA)
+    {
+      vty_out (vty, "  Flags: 0x%x" , rlsa->flags);
+
+      if (rlsa->flags)
+       vty_out (vty, " :%s%s%s%s",
+                IS_ROUTER_LSA_BORDER (rlsa) ? " ABR" : "",
+                IS_ROUTER_LSA_EXTERNAL (rlsa) ? " ASBR" : "",
+                IS_ROUTER_LSA_VIRTUAL (rlsa) ? " VL-endpoint" : "",
+                IS_ROUTER_LSA_SHORTCUT (rlsa) ? " Shortcut" : "");
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "  LS Type: %s%s",
+           LOOKUP (ospf_lsa_type_msg, lsa->data->type), VTY_NEWLINE);
+  vty_out (vty, "  Link State ID: %s %s%s", inet_ntoa (lsa->data->id),
+           LOOKUP (ospf_link_state_id_type_msg, lsa->data->type), VTY_NEWLINE);
+  vty_out (vty, "  Advertising Router: %s%s",
+           inet_ntoa (lsa->data->adv_router), VTY_NEWLINE);
+  vty_out (vty, "  LS Seq Number: %08lx%s", (u_long)ntohl (lsa->data->ls_seqnum),
+           VTY_NEWLINE);
+  vty_out (vty, "  Checksum: 0x%04x%s", ntohs (lsa->data->checksum),
+           VTY_NEWLINE);
+  vty_out (vty, "  Length: %d%s", ntohs (lsa->data->length), VTY_NEWLINE);
+}
+
+char *link_type_desc[] =
+{
+  "(null)",
+  "another Router (point-to-point)",
+  "a Transit Network",
+  "Stub Network",
+  "a Virtual Link",
+};
+
+char *link_id_desc[] =
+{
+  "(null)",
+  "Neighboring Router ID",
+  "Designated Router address",
+  "Network/subnet number",
+  "Neighboring Router ID",
+};
+
+char *link_data_desc[] =
+{
+  "(null)",
+  "Router Interface address",
+  "Router Interface address",
+  "Network Mask",
+  "Router Interface address",
+};
+
+/* Show router-LSA each Link information. */
+void
+show_ip_ospf_database_router_links (struct vty *vty,
+                                    struct router_lsa *rl)
+{
+  int len, i, type;
+
+  len = ntohs (rl->header.length) - 4;
+  for (i = 0; i < ntohs (rl->links) && len > 0; len -= 12, i++)
+    {
+      type = rl->link[i].type;
+
+      vty_out (vty, "    Link connected to: %s%s",
+              link_type_desc[type], VTY_NEWLINE);
+      vty_out (vty, "     (Link ID) %s: %s%s", link_id_desc[type],
+              inet_ntoa (rl->link[i].link_id), VTY_NEWLINE);
+      vty_out (vty, "     (Link Data) %s: %s%s", link_data_desc[type],
+              inet_ntoa (rl->link[i].link_data), VTY_NEWLINE);
+      vty_out (vty, "      Number of TOS metrics: 0%s", VTY_NEWLINE);
+      vty_out (vty, "       TOS 0 Metric: %d%s",
+              ntohs (rl->link[i].metric), VTY_NEWLINE);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+/* Show router-LSA detail information. */
+int
+show_router_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      struct router_lsa *rl = (struct router_lsa *) lsa->data;
+
+      show_ip_ospf_database_header (vty, lsa);
+          
+      vty_out (vty, "   Number of Links: %d%s%s", ntohs (rl->links),
+              VTY_NEWLINE, VTY_NEWLINE);
+
+      show_ip_ospf_database_router_links (vty, rl);
+    }
+
+  return 0;
+}
+
+/* Show network-LSA detail information. */
+int
+show_network_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  int length, i;
+
+  if (lsa != NULL)
+    {
+      struct network_lsa *nl = (struct network_lsa *) lsa->data;
+
+      show_ip_ospf_database_header (vty, lsa);
+
+      vty_out (vty, "  Network Mask: /%d%s",
+              ip_masklen (nl->mask), VTY_NEWLINE);
+
+      length = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE - 4;
+
+      for (i = 0; length > 0; i++, length -= 4)
+       vty_out (vty, "        Attached Router: %s%s",
+                inet_ntoa (nl->routers[i]), VTY_NEWLINE);
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+/* Show summary-LSA detail information. */
+int
+show_summary_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      struct summary_lsa *sl = (struct summary_lsa *) lsa->data;
+
+      show_ip_ospf_database_header (vty, lsa);
+
+      vty_out (vty, "  Network Mask: /%d%s", ip_masklen (sl->mask),
+              VTY_NEWLINE);
+      vty_out (vty, "        TOS: 0  Metric: %d%s", GET_METRIC (sl->metric),
+              VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+/* Show summary-ASBR-LSA detail information. */
+int
+show_summary_asbr_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      struct summary_lsa *sl = (struct summary_lsa *) lsa->data;
+
+      show_ip_ospf_database_header (vty, lsa);
+
+      vty_out (vty, "  Network Mask: /%d%s",
+              ip_masklen (sl->mask), VTY_NEWLINE);
+      vty_out (vty, "        TOS: 0  Metric: %d%s", GET_METRIC (sl->metric),
+              VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+/* Show AS-external-LSA detail information. */
+int
+show_as_external_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      struct as_external_lsa *al = (struct as_external_lsa *) lsa->data;
+
+      show_ip_ospf_database_header (vty, lsa);
+
+      vty_out (vty, "  Network Mask: /%d%s",
+              ip_masklen (al->mask), VTY_NEWLINE);
+      vty_out (vty, "        Metric Type: %s%s",
+              IS_EXTERNAL_METRIC (al->e[0].tos) ?
+              "2 (Larger than any link state path)" : "1", VTY_NEWLINE);
+      vty_out (vty, "        TOS: 0%s", VTY_NEWLINE);
+      vty_out (vty, "        Metric: %d%s",
+              GET_METRIC (al->e[0].metric), VTY_NEWLINE);
+      vty_out (vty, "        Forward Address: %s%s",
+              inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE);
+
+      vty_out (vty, "        External Route Tag: %lu%s%s",
+              (u_long)ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+#ifdef HAVE_NSSA
+int
+show_as_external_lsa_stdvty (struct ospf_lsa *lsa)
+{
+  struct as_external_lsa *al = (struct as_external_lsa *) lsa->data;
+
+  /* show_ip_ospf_database_header (vty, lsa); */
+
+  zlog_info( "  Network Mask: /%d%s",
+            ip_masklen (al->mask), "\n");
+  zlog_info( "        Metric Type: %s%s",
+            IS_EXTERNAL_METRIC (al->e[0].tos) ?
+            "2 (Larger than any link state path)" : "1", "\n");
+  zlog_info( "        TOS: 0%s", "\n");
+  zlog_info( "        Metric: %d%s",
+            GET_METRIC (al->e[0].metric), "\n");
+  zlog_info( "        Forward Address: %s%s",
+            inet_ntoa (al->e[0].fwd_addr), "\n");
+
+  zlog_info( "        External Route Tag: %u%s%s",
+            ntohl (al->e[0].route_tag), "\n", "\n");
+
+  return 0;
+}
+
+/* Show AS-NSSA-LSA detail information. */
+int
+show_as_nssa_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      struct as_external_lsa *al = (struct as_external_lsa *) lsa->data;
+
+      show_ip_ospf_database_header (vty, lsa);
+
+      vty_out (vty, "  Network Mask: /%d%s",
+              ip_masklen (al->mask), VTY_NEWLINE);
+      vty_out (vty, "        Metric Type: %s%s",
+              IS_EXTERNAL_METRIC (al->e[0].tos) ?
+              "2 (Larger than any link state path)" : "1", VTY_NEWLINE);
+      vty_out (vty, "        TOS: 0%s", VTY_NEWLINE);
+      vty_out (vty, "        Metric: %d%s",
+              GET_METRIC (al->e[0].metric), VTY_NEWLINE);
+      vty_out (vty, "        NSSA: Forward Address: %s%s",
+              inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE);
+
+      vty_out (vty, "        External Route Tag: %u%s%s",
+              ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+#endif /* HAVE_NSSA */
+
+int
+show_func_dummy (struct vty *vty, struct ospf_lsa *lsa)
+{
+  return 0;
+}
+
+#ifdef HAVE_OPAQUE_LSA
+int
+show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      show_ip_ospf_database_header (vty, lsa);
+      show_opaque_info_detail (vty, lsa);
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+#endif /* HAVE_OPAQUE_LSA */
+
+int (*show_function[])(struct vty *, struct ospf_lsa *) =
+{
+  NULL,
+  show_router_lsa_detail,
+  show_network_lsa_detail,
+  show_summary_lsa_detail,
+  show_summary_asbr_lsa_detail,
+  show_as_external_lsa_detail,
+#ifdef HAVE_NSSA
+  show_func_dummy,
+  show_as_nssa_lsa_detail,  /* almost same as external */
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+#ifndef HAVE_NSSA
+  show_func_dummy,
+  show_func_dummy,
+#endif /* HAVE_NSSA */
+  NULL,                                /* type-8 */
+  show_opaque_lsa_detail,
+  show_opaque_lsa_detail,
+  show_opaque_lsa_detail,
+#endif /* HAVE_OPAQUE_LSA */
+};
+
+void
+show_lsa_prefix_set (struct vty *vty, struct prefix_ls *lp, struct in_addr *id,
+                    struct in_addr *adv_router)
+{
+  memset (lp, 0, sizeof (struct prefix_ls));
+  lp->family = 0;
+  if (id == NULL)
+    lp->prefixlen = 0;
+  else if (adv_router == NULL)
+    {
+      lp->prefixlen = 32;
+      lp->id = *id;
+    }
+  else
+    {
+      lp->prefixlen = 64;
+      lp->id = *id;
+      lp->adv_router = *adv_router;
+    }
+}
+
+void
+show_lsa_detail_proc (struct vty *vty, struct route_table *rt,
+                     struct in_addr *id, struct in_addr *adv_router)
+{
+  struct prefix_ls lp;
+  struct route_node *rn, *start;
+  struct ospf_lsa *lsa;
+
+  show_lsa_prefix_set (vty, &lp, id, adv_router);
+  start = route_node_get (rt, (struct prefix *) &lp);
+  if (start)
+    {
+      route_lock_node (start);
+      for (rn = start; rn; rn = route_next_until (rn, start))
+       if ((lsa = rn->info))
+         {
+#ifdef HAVE_NSSA
+           /* Stay away from any Local Translated Type-7 LSAs */
+           if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+             continue;
+#endif /* HAVE_NSSA */
+
+           if (show_function[lsa->data->type] != NULL)
+             show_function[lsa->data->type] (vty, lsa);
+         }
+      route_unlock_node (start);
+    }
+}
+
+/* Show detail LSA information
+   -- if id is NULL then show all LSAs. */
+void
+show_lsa_detail (struct vty *vty, int type,
+                struct in_addr *id, struct in_addr *adv_router)
+{
+  listnode node;
+
+  switch (type)
+    {
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      vty_out (vty, "                %s %s%s",
+               show_database_desc[type],
+               VTY_NEWLINE, VTY_NEWLINE);
+      show_lsa_detail_proc (vty, AS_LSDB (ospf_top, type), id, adv_router);
+      break;
+    default:
+      for (node = listhead (ospf_top->areas); node; nextnode (node))
+        {
+          struct ospf_area *area = node->data;
+          vty_out (vty, "%s                %s (Area %s)%s%s",
+                   VTY_NEWLINE, show_database_desc[type],
+                   ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE);
+          show_lsa_detail_proc (vty, AREA_LSDB (area, type), id, adv_router);
+        }
+      break;
+    }
+}
+
+void
+show_lsa_detail_adv_router_proc (struct vty *vty, struct route_table *rt,
+                                struct in_addr *adv_router)
+{
+  struct route_node *rn;
+  struct ospf_lsa *lsa;
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((lsa = rn->info))
+      if (IPV4_ADDR_SAME (adv_router, &lsa->data->adv_router))
+       {
+#ifdef HAVE_NSSA
+         if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+           continue;
+#endif /* HAVE_NSSA */
+         if (show_function[lsa->data->type] != NULL)
+           show_function[lsa->data->type] (vty, lsa);
+       }
+}
+
+/* Show detail LSA information. */
+void
+show_lsa_detail_adv_router (struct vty *vty, int type,
+                           struct in_addr *adv_router)
+{
+  listnode node;
+
+  switch (type)
+    {
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      vty_out (vty, "                %s %s%s",
+               show_database_desc[type],
+               VTY_NEWLINE, VTY_NEWLINE);
+      show_lsa_detail_adv_router_proc (vty, AS_LSDB (ospf_top, type),
+                                       adv_router);
+      break;
+    default:
+      for (node = listhead (ospf_top->areas); node; nextnode (node))
+        {
+          struct ospf_area *area = node->data;
+          vty_out (vty, "%s                %s (Area %s)%s%s",
+                   VTY_NEWLINE, show_database_desc[type],
+                   ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE);
+          show_lsa_detail_adv_router_proc (vty, AREA_LSDB (area, type),
+                                           adv_router);
+       }
+      break;
+    }
+}
+
+void
+show_ip_ospf_database_summary (struct vty *vty, int self)
+{
+  listnode node;
+  int type;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = node->data;
+      for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++)
+       {
+         switch (type)
+           {
+           case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+            case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+             continue;
+           default:
+             break;
+           }
+          if (ospf_lsdb_count_self (area->lsdb, type) > 0 ||
+              (!self && ospf_lsdb_count (area->lsdb, type) > 0))
+            {
+              vty_out (vty, "                %s (Area %s)%s%s",
+                       show_database_desc[type],
+                      ospf_area_desc_string (area),
+                       VTY_NEWLINE, VTY_NEWLINE);
+              vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE);
+
+              foreach_lsa (AREA_LSDB (area, type), vty, self, show_lsa_summary);
+
+              vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       }
+    }
+
+  for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++)
+    {
+      switch (type)
+        {
+          case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+          case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+            break;;
+          default:
+            continue;
+        }
+      if (ospf_lsdb_count_self (ospf_top->lsdb, type) ||
+         (!self && ospf_lsdb_count (ospf_top->lsdb, type)))
+        {
+          vty_out (vty, "                %s%s%s",
+              show_database_desc[type],
+              VTY_NEWLINE, VTY_NEWLINE);
+          vty_out (vty, "%s%s", show_database_header[type],
+              VTY_NEWLINE);
+          foreach_lsa (AS_LSDB (ospf_top, type), vty, self, show_lsa_summary);
+          vty_out (vty, "%s", VTY_NEWLINE);
+        }
+    }
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+show_ip_ospf_database_maxage (struct vty *vty)
+{
+  listnode node;
+  struct ospf_lsa *lsa;
+
+  vty_out (vty, "%s                MaxAge Link States:%s%s",
+           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+  for (node = listhead (ospf_top->maxage_lsa); node; nextnode (node))
+    if ((lsa = node->data) != NULL)
+      {
+       vty_out (vty, "Link type: %d%s", lsa->data->type, VTY_NEWLINE);
+       vty_out (vty, "Link State ID: %s%s",
+                inet_ntoa (lsa->data->id), VTY_NEWLINE);
+       vty_out (vty, "Advertising Router: %s%s",
+                inet_ntoa (lsa->data->adv_router), VTY_NEWLINE);
+       vty_out (vty, "LSA lock count: %d%s", lsa->lock, VTY_NEWLINE);
+       vty_out (vty, "%s", VTY_NEWLINE);
+      }
+}
+
+#ifdef HAVE_NSSA
+#define OSPF_LSA_TYPE_NSSA_DESC      "NSSA external link state\n"
+#define OSPF_LSA_TYPE_NSSA_CMD_STR   "|nssa-external"
+#else  /* HAVE_NSSA */
+#define OSPF_LSA_TYPE_NSSA_DESC      ""
+#define OSPF_LSA_TYPE_NSSA_CMD_STR   ""
+#endif /* HAVE_NSSA */
+
+#ifdef HAVE_OPAQUE_LSA
+#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n"
+#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n"
+#define OSPF_LSA_TYPE_OPAQUE_AS_DESC   "Link AS Opaque-LSA\n"
+#define OSPF_LSA_TYPE_OPAQUE_CMD_STR   "|opaque-link|opaque-area|opaque-as"
+#else /* HAVE_OPAQUE_LSA */
+#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC ""
+#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC ""
+#define OSPF_LSA_TYPE_OPAQUE_AS_DESC   ""
+#define OSPF_LSA_TYPE_OPAQUE_CMD_STR   ""
+#endif /* HAVE_OPAQUE_LSA */
+
+#define OSPF_LSA_TYPES_CMD_STR                                                \
+    "asbr-summary|external|network|router|summary"                            \
+    OSPF_LSA_TYPE_NSSA_CMD_STR                                                \
+    OSPF_LSA_TYPE_OPAQUE_CMD_STR
+
+#define OSPF_LSA_TYPES_DESC                                                   \
+   "ASBR summary link states\n"                                               \
+   "External link states\n"                                                   \
+   "Network link states\n"                                                    \
+   "Router link states\n"                                                     \
+   "Network summary link states\n"                                            \
+   OSPF_LSA_TYPE_NSSA_DESC                                                    \
+   OSPF_LSA_TYPE_OPAQUE_LINK_DESC                                             \
+   OSPF_LSA_TYPE_OPAQUE_AREA_DESC                                             \
+   OSPF_LSA_TYPE_OPAQUE_AS_DESC     
+
+DEFUN (show_ip_ospf_database,
+       show_ip_ospf_database_cmd,
+       "show ip ospf database",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n")
+{
+  int type, ret;
+  struct in_addr id, adv_router;
+
+  if (ospf_top == NULL)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "%s       OSPF Router with ID (%s)%s%s", VTY_NEWLINE,
+           inet_ntoa (ospf_top->router_id), VTY_NEWLINE, VTY_NEWLINE);
+
+  /* Show all LSA. */
+  if (argc == 0)
+    {
+      show_ip_ospf_database_summary (vty, 0);
+      return CMD_SUCCESS;
+    }
+
+  /* Set database type to show. */
+  if (strncmp (argv[0], "r", 1) == 0)
+    type = OSPF_ROUTER_LSA;
+  else if (strncmp (argv[0], "ne", 2) == 0)
+    type = OSPF_NETWORK_LSA;
+#ifdef HAVE_NSSA
+  else if (strncmp (argv[0], "ns", 2) == 0)
+    type = OSPF_AS_NSSA_LSA;
+#endif /* HAVE_NSSA */
+  else if (strncmp (argv[0], "su", 2) == 0)
+    type = OSPF_SUMMARY_LSA;
+  else if (strncmp (argv[0], "a", 1) == 0)
+    type = OSPF_ASBR_SUMMARY_LSA;
+  else if (strncmp (argv[0], "e", 1) == 0)
+    type = OSPF_AS_EXTERNAL_LSA;
+  else if (strncmp (argv[0], "se", 2) == 0)
+    {
+      show_ip_ospf_database_summary (vty, 1);
+      return CMD_SUCCESS;
+    }
+  else if (strncmp (argv[0], "m", 1) == 0)
+    {
+      show_ip_ospf_database_maxage (vty);
+      return CMD_SUCCESS;
+    }
+#ifdef HAVE_OPAQUE_LSA
+  else if (strncmp (argv[0], "opaque-l", 8) == 0)
+    type = OSPF_OPAQUE_LINK_LSA;
+  else if (strncmp (argv[0], "opaque-ar", 9) == 0)
+    type = OSPF_OPAQUE_AREA_LSA;
+  else if (strncmp (argv[0], "opaque-as", 9) == 0)
+    type = OSPF_OPAQUE_AS_LSA;
+#endif /* HAVE_OPAQUE_LSA */
+  else
+    return CMD_WARNING;
+
+  /* `show ip ospf database LSA'. */
+  if (argc == 1)
+    show_lsa_detail (vty, type, NULL, NULL);
+  else if (argc >= 2)
+    {
+      ret = inet_aton (argv[1], &id);
+      if (!ret)
+       return CMD_WARNING;
+      
+      /* `show ip ospf database LSA ID'. */
+      if (argc == 2)
+       show_lsa_detail (vty, type, &id, NULL);
+      /* `show ip ospf database LSA ID adv-router ADV_ROUTER'. */
+      else if (argc == 3)
+       {
+         if (strncmp (argv[2], "s", 1) == 0)
+           adv_router = ospf_top->router_id;
+         else
+           {
+             ret = inet_aton (argv[2], &adv_router);
+             if (!ret)
+               return CMD_WARNING;
+           }
+         show_lsa_detail (vty, type, &id, &adv_router);
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ip_ospf_database,
+       show_ip_ospf_database_type_cmd,
+       "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR "|max-age|self-originate)",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "LSAs in MaxAge list\n"
+       "Self-originated link states\n")
+
+ALIAS (show_ip_ospf_database,
+       show_ip_ospf_database_type_id_cmd,
+       "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "Link State ID (as an IP address)\n")
+
+ALIAS (show_ip_ospf_database,
+       show_ip_ospf_database_type_id_adv_router_cmd,
+       "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D adv-router A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "Link State ID (as an IP address)\n"
+       "Advertising Router link states\n"
+       "Advertising Router (as an IP address)\n")
+
+ALIAS (show_ip_ospf_database,
+       show_ip_ospf_database_type_id_self_cmd,
+       "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D (self-originate|)",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "Link State ID (as an IP address)\n"
+       "Self-originated link states\n"
+       "\n")
+
+DEFUN (show_ip_ospf_database_type_adv_router,
+       show_ip_ospf_database_type_adv_router_cmd,
+       "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") adv-router A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "Advertising Router link states\n"
+       "Advertising Router (as an IP address)\n")
+{
+  int type, ret;
+  struct in_addr adv_router;
+
+  if (ospf_top == NULL)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "%s       OSPF Router with ID (%s)%s%s", VTY_NEWLINE,
+           inet_ntoa (ospf_top->router_id), VTY_NEWLINE, VTY_NEWLINE);
+
+  if (argc != 2)
+    return CMD_WARNING;
+
+  /* Set database type to show. */
+  if (strncmp (argv[0], "r", 1) == 0)
+    type = OSPF_ROUTER_LSA;
+  else if (strncmp (argv[0], "ne", 2) == 0)
+    type = OSPF_NETWORK_LSA;
+#ifdef HAVE_NSSA
+  else if (strncmp (argv[0], "ns", 2) == 0)
+    type = OSPF_AS_NSSA_LSA;
+#endif /* HAVE_NSSA */
+  else if (strncmp (argv[0], "s", 1) == 0)
+    type = OSPF_SUMMARY_LSA;
+  else if (strncmp (argv[0], "a", 1) == 0)
+    type = OSPF_ASBR_SUMMARY_LSA;
+  else if (strncmp (argv[0], "e", 1) == 0)
+    type = OSPF_AS_EXTERNAL_LSA;
+#ifdef HAVE_OPAQUE_LSA
+  else if (strncmp (argv[0], "opaque-l", 8) == 0)
+    type = OSPF_OPAQUE_LINK_LSA;
+  else if (strncmp (argv[0], "opaque-ar", 9) == 0)
+    type = OSPF_OPAQUE_AREA_LSA;
+  else if (strncmp (argv[0], "opaque-as", 9) == 0)
+    type = OSPF_OPAQUE_AS_LSA;
+#endif /* HAVE_OPAQUE_LSA */
+  else
+    return CMD_WARNING;
+
+  /* `show ip ospf database LSA adv-router ADV_ROUTER'. */
+  if (strncmp (argv[1], "s", 1) == 0)
+    adv_router = ospf_top->router_id;
+  else
+    {
+      ret = inet_aton (argv[1], &adv_router);
+      if (!ret)
+       return CMD_WARNING;
+    }
+
+  show_lsa_detail_adv_router (vty, type, &adv_router);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ip_ospf_database_type_adv_router,
+       show_ip_ospf_database_type_self_cmd,
+       "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") (self-originate|)",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "Self-originated link states\n")
+
+\f
+DEFUN (ip_ospf_authentication_args,
+       ip_ospf_authentication_args_addr_cmd,
+       "ip ospf authentication (null|message-digest) A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Use null authentication\n"
+       "Use message-digest authentication\n"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  /* Handle null authentication */
+  if ( argv[0][0] == 'n' )
+    {
+      SET_IF_PARAM (params, auth_type);
+      params->auth_type = OSPF_AUTH_NULL;
+      return CMD_SUCCESS;
+    }
+
+  /* Handle message-digest authentication */
+  if ( argv[0][0] == 'm' )
+    {
+      SET_IF_PARAM (params, auth_type);
+      params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+      return CMD_SUCCESS;
+    }
+
+  vty_out (vty, "You shouldn't get here!%s", VTY_NEWLINE);
+  return CMD_WARNING;
+}
+
+ALIAS (ip_ospf_authentication_args,
+       ip_ospf_authentication_args_cmd,
+       "ip ospf authentication (null|message-digest)",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Use null authentication\n"
+       "Use message-digest authentication\n")
+
+DEFUN (ip_ospf_authentication,
+       ip_ospf_authentication_addr_cmd,
+       "ip ospf authentication A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  SET_IF_PARAM (params, auth_type);
+  params->auth_type = OSPF_AUTH_SIMPLE;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_authentication,
+       ip_ospf_authentication_cmd,
+       "ip ospf authentication",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n")
+
+DEFUN (no_ip_ospf_authentication,
+       no_ip_ospf_authentication_addr_cmd,
+       "no ip ospf authentication A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  params->auth_type = OSPF_AUTH_NOTSET;
+  UNSET_IF_PARAM (params, auth_type);
+  
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_authentication,
+       no_ip_ospf_authentication_cmd,
+       "no ip ospf authentication",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n")
+
+DEFUN (ip_ospf_authentication_key,
+       ip_ospf_authentication_key_addr_cmd,
+       "ip ospf authentication-key AUTH_KEY A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "The OSPF password (key)\n"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+
+  memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1);
+  strncpy (params->auth_simple, argv[0], OSPF_AUTH_SIMPLE_SIZE);
+  SET_IF_PARAM (params, auth_simple);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_authentication_key,
+       ip_ospf_authentication_key_cmd,
+       "ip ospf authentication-key AUTH_KEY",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "The OSPF password (key)")
+
+ALIAS (ip_ospf_authentication_key,
+       ospf_authentication_key_cmd,
+       "ospf authentication-key AUTH_KEY",
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "The OSPF password (key)")
+
+DEFUN (no_ip_ospf_authentication_key,
+       no_ip_ospf_authentication_key_addr_cmd,
+       "no ip ospf authentication-key A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE);
+  UNSET_IF_PARAM (params, auth_simple);
+  
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_authentication_key,
+       no_ip_ospf_authentication_key_cmd,
+       "no ip ospf authentication-key",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n")
+
+ALIAS (no_ip_ospf_authentication_key,
+       no_ospf_authentication_key_cmd,
+       "no ospf authentication-key",
+       NO_STR
+       "OSPF interface commands\n"
+       "Authentication password (key)\n")
+
+DEFUN (ip_ospf_message_digest_key,
+       ip_ospf_message_digest_key_addr_cmd,
+       "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Use MD5 algorithm\n"
+       "The OSPF password (key)"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct crypt_key *ck;
+  u_char key_id;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 3)
+    {
+      ret = inet_aton(argv[2], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  key_id = strtol (argv[0], NULL, 10);
+  if (ospf_crypt_key_lookup (params->auth_crypt, key_id) != NULL)
+    {
+      vty_out (vty, "OSPF: Key %d already exists%s", key_id, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ck = ospf_crypt_key_new ();
+  ck->key_id = (u_char) key_id;
+  memset (ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1);
+  strncpy (ck->auth_key, argv[1], OSPF_AUTH_MD5_SIZE);
+
+  ospf_crypt_key_add (params->auth_crypt, ck);
+  SET_IF_PARAM (params, auth_crypt);
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_message_digest_key,
+       ip_ospf_message_digest_key_cmd,
+       "ip ospf message-digest-key <1-255> md5 KEY",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Use MD5 algorithm\n"
+       "The OSPF password (key)")
+
+ALIAS (ip_ospf_message_digest_key,
+       ospf_message_digest_key_cmd,
+       "ospf message-digest-key <1-255> md5 KEY",
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Use MD5 algorithm\n"
+       "The OSPF password (key)")
+
+DEFUN (no_ip_ospf_message_digest_key,
+       no_ip_ospf_message_digest_key_addr_cmd,
+       "no ip ospf message-digest-key <1-255> A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Address of interface")
+{
+  struct interface *ifp;
+  struct crypt_key *ck;
+  int key_id;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  key_id = strtol (argv[0], NULL, 10);
+  ck = ospf_crypt_key_lookup (params->auth_crypt, key_id);
+  if (ck == NULL)
+    {
+      vty_out (vty, "OSPF: Key %d does not exist%s", key_id, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf_crypt_key_delete (params->auth_crypt, key_id);
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_message_digest_key,
+       no_ip_ospf_message_digest_key_cmd,
+       "no ip ospf message-digest-key <1-255>",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n")
+     
+ALIAS (no_ip_ospf_message_digest_key,
+       no_ospf_message_digest_key_cmd,
+       "no ospf message-digest-key <1-255>",
+       NO_STR
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n")
+
+DEFUN (ip_ospf_cost,
+       ip_ospf_cost_addr_cmd,
+       "ip ospf cost <1-65535> A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Cost\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  u_int32_t cost;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+      
+  params = IF_DEF_PARAMS (ifp);
+
+  cost = strtol (argv[0], NULL, 10);
+
+  /* cost range is <1-65535>. */
+  if (cost < 1 || cost > 65535)
+    {
+      vty_out (vty, "Interface output cost is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  SET_IF_PARAM (params, output_cost_cmd);
+  params->output_cost_cmd = cost;
+
+  ospf_if_recalculate_output_cost (ifp);
+    
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_cost,
+       ip_ospf_cost_cmd,
+       "ip ospf cost <1-65535>",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Cost")
+
+ALIAS (ip_ospf_cost,
+       ospf_cost_cmd,
+       "ospf cost <1-65535>",
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Cost")
+
+DEFUN (no_ip_ospf_cost,
+       no_ip_ospf_cost_addr_cmd,
+       "no ip ospf cost A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[0], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, output_cost_cmd);
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  ospf_if_recalculate_output_cost (ifp);
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_cost,
+       no_ip_ospf_cost_cmd,
+       "no ip ospf cost",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n")
+
+ALIAS (no_ip_ospf_cost,
+       no_ospf_cost_cmd,
+       "no ospf cost",
+       NO_STR
+       "OSPF interface commands\n"
+       "Interface cost\n")
+
+void
+ospf_nbr_timer_update (struct ospf_interface *oi)
+{
+  struct route_node *rn;
+  struct ospf_neighbor *nbr;
+
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info))
+      {
+       nbr->v_inactivity = OSPF_IF_PARAM (oi, v_wait);
+       nbr->v_db_desc = OSPF_IF_PARAM (oi, retransmit_interval);
+       nbr->v_ls_req = OSPF_IF_PARAM (oi, retransmit_interval);
+       nbr->v_ls_upd = OSPF_IF_PARAM (oi, retransmit_interval);
+      }
+}
+
+DEFUN (ip_ospf_dead_interval,
+       ip_ospf_dead_interval_addr_cmd,
+       "ip ospf dead-interval <1-65535> A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Seconds\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  u_int32_t seconds;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  struct ospf_interface *oi;
+  struct route_node *rn;
+      
+  params = IF_DEF_PARAMS (ifp);
+
+  seconds = strtol (argv[0], NULL, 10);
+
+  /* dead_interval range is <1-65535>. */
+  if (seconds < 1 || seconds > 65535)
+    {
+      vty_out (vty, "Router Dead Interval is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  SET_IF_PARAM (params, v_wait);
+  params->v_wait = seconds;
+  
+  /* Update timer values in neighbor structure. */
+  if (argc == 2)
+    {
+      oi = ospf_if_lookup_by_local_addr (ifp, addr);
+      if (oi)
+       ospf_nbr_timer_update (oi);
+    }
+  else
+    {
+      for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+       if ((oi = rn->info))
+         ospf_nbr_timer_update (oi);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_dead_interval,
+       ip_ospf_dead_interval_cmd,
+       "ip ospf dead-interval <1-65535>",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Seconds\n")
+
+ALIAS (ip_ospf_dead_interval,
+       ospf_dead_interval_cmd,
+       "ospf dead-interval <1-65535>",
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Seconds\n")
+
+DEFUN (no_ip_ospf_dead_interval,
+       no_ip_ospf_dead_interval_addr_cmd,
+       "no ip ospf dead-interval A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  struct ospf_interface *oi;
+  struct route_node *rn;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[0], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, v_wait);
+  params->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  /* Update timer values in neighbor structure. */
+  if (argc == 1)
+    {
+      oi = ospf_if_lookup_by_local_addr (ifp, addr);
+      if (oi)
+       ospf_nbr_timer_update (oi);
+    }
+  else
+    {
+      for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+       if ((oi = rn->info))
+         ospf_nbr_timer_update (oi);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_dead_interval,
+       no_ip_ospf_dead_interval_cmd,
+       "no ip ospf dead-interval",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n")
+
+ALIAS (no_ip_ospf_dead_interval,
+       no_ospf_dead_interval_cmd,
+       "no ospf dead-interval",
+       NO_STR
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n")
+
+DEFUN (ip_ospf_hello_interval,
+       ip_ospf_hello_interval_addr_cmd,
+       "ip ospf hello-interval <1-65535> A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Seconds\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  u_int32_t seconds;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+      
+  params = IF_DEF_PARAMS (ifp);
+
+  seconds = strtol (argv[0], NULL, 10);
+  
+  /* HelloInterval range is <1-65535>. */
+  if (seconds < 1 || seconds > 65535)
+    {
+      vty_out (vty, "Hello Interval is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  SET_IF_PARAM (params, v_hello); 
+  params->v_hello = seconds;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_hello_interval,
+       ip_ospf_hello_interval_cmd,
+       "ip ospf hello-interval <1-65535>",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Seconds\n")
+
+ALIAS (ip_ospf_hello_interval,
+       ospf_hello_interval_cmd,
+       "ospf hello-interval <1-65535>",
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Seconds\n")
+
+DEFUN (no_ip_ospf_hello_interval,
+       no_ip_ospf_hello_interval_addr_cmd,
+       "no ip ospf hello-interval A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[0], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, v_hello);
+  params->v_hello = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_hello_interval,
+       no_ip_ospf_hello_interval_cmd,
+       "no ip ospf hello-interval",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n")
+
+ALIAS (no_ip_ospf_hello_interval,
+       no_ospf_hello_interval_cmd,
+       "no ospf hello-interval",
+       NO_STR
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n")
+
+DEFUN (ip_ospf_network,
+       ip_ospf_network_cmd,
+       "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Network type\n"
+       "Specify OSPF broadcast multi-access network\n"
+       "Specify OSPF NBMA network\n"
+       "Specify OSPF point-to-multipoint network\n"
+       "Specify OSPF point-to-point network\n")
+{
+  struct interface *ifp = vty->index;
+  int old_type = IF_DEF_PARAMS (ifp)->type;
+  struct route_node *rn;
+  
+  if (strncmp (argv[0], "b", 1) == 0)
+    IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
+  else if (strncmp (argv[0], "n", 1) == 0)
+    IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_NBMA;
+  else if (strncmp (argv[0], "point-to-m", 10) == 0)
+    IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT;
+  else if (strncmp (argv[0], "point-to-p", 10) == 0)
+    IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT;
+
+  if (IF_DEF_PARAMS (ifp)->type == old_type)
+    return CMD_SUCCESS;
+
+  SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
+
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      struct ospf_interface *oi = rn->info;
+
+      if (!oi)
+       continue;
+      
+      oi->type = IF_DEF_PARAMS (ifp)->type;
+      
+      if (oi->state > ISM_Down)
+       {
+         OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
+         OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp);
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_network,
+       ospf_network_cmd,
+       "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)",
+       "OSPF interface commands\n"
+       "Network type\n"
+       "Specify OSPF broadcast multi-access network\n"
+       "Specify OSPF NBMA network\n"
+       "Specify OSPF point-to-multipoint network\n"
+       "Specify OSPF point-to-point network\n")
+
+DEFUN (no_ip_ospf_network,
+       no_ip_ospf_network_cmd,
+       "no ip ospf network",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Network type\n")
+{
+  struct interface *ifp = vty->index;
+  int old_type = IF_DEF_PARAMS (ifp)->type;
+  struct route_node *rn;
+
+  IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
+
+  if (IF_DEF_PARAMS (ifp)->type == old_type)
+    return CMD_SUCCESS;
+
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      struct ospf_interface *oi = rn->info;
+
+      if (!oi)
+       continue;
+      
+      oi->type = IF_DEF_PARAMS (ifp)->type;
+      
+      if (oi->state > ISM_Down)
+       {
+         OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
+         OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp);
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_network,
+       no_ospf_network_cmd,
+       "no ospf network",
+       NO_STR
+       "OSPF interface commands\n"
+       "Network type\n")
+
+DEFUN (ip_ospf_priority,
+       ip_ospf_priority_addr_cmd,
+       "ip ospf priority <0-255> A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Priority\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  u_int32_t priority;
+  struct route_node *rn;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+      
+  params = IF_DEF_PARAMS (ifp);
+
+  priority = strtol (argv[0], NULL, 10);
+  
+  /* Router Priority range is <0-255>. */
+  if (priority < 0 || priority > 255)
+    {
+      vty_out (vty, "Router Priority is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  SET_IF_PARAM (params, priority);
+  params->priority = priority;
+
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      struct ospf_interface *oi = rn->info;
+      
+      if (!oi)
+       continue;
+      
+
+      if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority))
+       {
+         PRIORITY (oi) = OSPF_IF_PARAM (oi, priority);
+         OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
+       }
+    }
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_priority,
+       ip_ospf_priority_cmd,
+       "ip ospf priority <0-255>",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Priority\n")
+
+ALIAS (ip_ospf_priority,
+       ospf_priority_cmd,
+       "ospf priority <0-255>",
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Priority\n")
+
+DEFUN (no_ip_ospf_priority,
+       no_ip_ospf_priority_addr_cmd,
+       "no ip ospf priority A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  struct route_node *rn;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[0], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, priority);
+  params->priority = OSPF_ROUTER_PRIORITY_DEFAULT;
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+  
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    {
+      struct ospf_interface *oi = rn->info;
+      
+      if (!oi)
+       continue;
+      
+      
+      if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority))
+       {
+         PRIORITY (oi) = OSPF_IF_PARAM (oi, priority);
+         OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
+       }
+    }
+  
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_priority,
+       no_ip_ospf_priority_cmd,
+       "no ip ospf priority",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n")
+
+ALIAS (no_ip_ospf_priority,
+       no_ospf_priority_cmd,
+       "no ospf priority",
+       NO_STR
+       "OSPF interface commands\n"
+       "Router priority\n")
+
+DEFUN (ip_ospf_retransmit_interval,
+       ip_ospf_retransmit_interval_addr_cmd,
+       "ip ospf retransmit-interval <3-65535> A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Seconds\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  u_int32_t seconds;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+      
+  params = IF_DEF_PARAMS (ifp);
+  seconds = strtol (argv[0], NULL, 10);
+
+  /* Retransmit Interval range is <3-65535>. */
+  if (seconds < 3 || seconds > 65535)
+    {
+      vty_out (vty, "Retransmit Interval is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  SET_IF_PARAM (params, retransmit_interval);
+  params->retransmit_interval = seconds;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_retransmit_interval,
+       ip_ospf_retransmit_interval_cmd,
+       "ip ospf retransmit-interval <3-65535>",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Seconds\n")
+
+ALIAS (ip_ospf_retransmit_interval,
+       ospf_retransmit_interval_cmd,
+       "ospf retransmit-interval <3-65535>",
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Seconds\n")
+
+DEFUN (no_ip_ospf_retransmit_interval,
+       no_ip_ospf_retransmit_interval_addr_cmd,
+       "no ip ospf retransmit-interval A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[0], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, retransmit_interval);
+  params->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT;
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_retransmit_interval,
+       no_ip_ospf_retransmit_interval_cmd,
+       "no ip ospf retransmit-interval",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n")
+
+ALIAS (no_ip_ospf_retransmit_interval,
+       no_ospf_retransmit_interval_cmd,
+       "no ospf retransmit-interval",
+       NO_STR
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n")
+
+DEFUN (ip_ospf_transmit_delay,
+       ip_ospf_transmit_delay_addr_cmd,
+       "ip ospf transmit-delay <1-65535> A.B.C.D",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Seconds\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  u_int32_t seconds;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+      
+  params = IF_DEF_PARAMS (ifp);
+  seconds = strtol (argv[0], NULL, 10);
+
+  /* Transmit Delay range is <1-65535>. */
+  if (seconds < 1 || seconds > 65535)
+    {
+      vty_out (vty, "Transmit Delay is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 2)
+    {
+      ret = inet_aton(argv[1], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_get_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  SET_IF_PARAM (params, transmit_delay); 
+  params->transmit_delay = seconds;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ip_ospf_transmit_delay,
+       ip_ospf_transmit_delay_cmd,
+       "ip ospf transmit-delay <1-65535>",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Seconds\n")
+
+ALIAS (ip_ospf_transmit_delay,
+       ospf_transmit_delay_cmd,
+       "ospf transmit-delay <1-65535>",
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Seconds\n")
+
+DEFUN (no_ip_ospf_transmit_delay,
+       no_ip_ospf_transmit_delay_addr_cmd,
+       "no ip ospf transmit-delay A.B.C.D",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Address of interface")
+{
+  struct interface *ifp = vty->index;
+  struct in_addr addr;
+  int ret;
+  struct ospf_if_params *params;
+  
+  ifp = vty->index;
+  params = IF_DEF_PARAMS (ifp);
+
+  if (argc == 1)
+    {
+      ret = inet_aton(argv[0], &addr);
+      if (!ret)
+       {
+         vty_out (vty, "Please specify interface address by A.B.C.D%s",
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      params = ospf_lookup_if_params (ifp, addr);
+      if (params == NULL)
+       return CMD_SUCCESS;
+    }
+
+  UNSET_IF_PARAM (params, transmit_delay);
+  params->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT;
+
+  if (params != IF_DEF_PARAMS (ifp))
+    {
+      ospf_free_if_params (ifp, addr);
+      ospf_if_update_params (ifp, addr);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_ospf_transmit_delay,
+       no_ip_ospf_transmit_delay_cmd,
+       "no ip ospf transmit-delay",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n")
+
+ALIAS (no_ip_ospf_transmit_delay,
+       no_ospf_transmit_delay_cmd,
+       "no ospf transmit-delay",
+       NO_STR
+       "OSPF interface commands\n"
+       "Link state transmit delay\n")
+
+\f
+DEFUN (ospf_redistribute_source_metric_type,
+       ospf_redistribute_source_metric_type_routemap_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int source;
+  int type = -1;
+  int metric = -1;
+
+  /* Get distribute source. */
+  if (!str2distribute_source (argv[0], &source))
+    return CMD_WARNING;
+
+  /* Get metric value. */
+  if (argc >= 2)
+    if (!str2metric (argv[1], &metric))
+      return CMD_WARNING;
+
+  /* Get metric type. */
+  if (argc >= 3)
+    if (!str2metric_type (argv[2], &type))
+      return CMD_WARNING;
+
+  if (argc == 4)
+    ospf_routemap_set (source, argv[3]);
+  else
+    ospf_routemap_unset (source);
+  
+  return ospf_redistribute_set (source, type, metric);
+}
+
+ALIAS (ospf_redistribute_source_metric_type,
+       ospf_redistribute_source_metric_type_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2)",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+ALIAS (ospf_redistribute_source_metric_type,
+       ospf_redistribute_source_metric_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n")
+
+DEFUN (ospf_redistribute_source_type_metric,
+       ospf_redistribute_source_type_metric_routemap_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int source;
+  int type = -1;
+  int metric = -1;
+
+  /* Get distribute source. */
+  if (!str2distribute_source (argv[0], &source))
+    return CMD_WARNING;
+
+  /* Get metric value. */
+  if (argc >= 2)
+    if (!str2metric_type (argv[1], &type))
+      return CMD_WARNING;
+
+  /* Get metric type. */
+  if (argc >= 3)
+    if (!str2metric (argv[2], &metric))
+      return CMD_WARNING;
+
+  if (argc == 4)
+    ospf_routemap_set (source, argv[3]);
+  else
+    ospf_routemap_unset (source);
+
+  return ospf_redistribute_set (source, type, metric);
+}
+
+ALIAS (ospf_redistribute_source_type_metric,
+       ospf_redistribute_source_type_metric_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n")
+
+ALIAS (ospf_redistribute_source_type_metric,
+       ospf_redistribute_source_type_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+ALIAS (ospf_redistribute_source_type_metric,
+       ospf_redistribute_source_cmd,
+       "redistribute (kernel|connected|static|rip|bgp)",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFUN (ospf_redistribute_source_metric_routemap,
+       ospf_redistribute_source_metric_routemap_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int source;
+  int metric = -1;
+
+  /* Get distribute source. */
+  if (!str2distribute_source (argv[0], &source))
+    return CMD_WARNING;
+
+  /* Get metric value. */
+  if (argc >= 2)
+    if (!str2metric (argv[1], &metric))
+      return CMD_WARNING;
+
+  if (argc == 3)
+    ospf_routemap_set (source, argv[2]);
+  else
+    ospf_routemap_unset (source);
+  
+  return ospf_redistribute_set (source, -1, metric);
+}
+
+DEFUN (ospf_redistribute_source_type_routemap,
+       ospf_redistribute_source_type_routemap_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int source;
+  int type = -1;
+
+  /* Get distribute source. */
+  if (!str2distribute_source (argv[0], &source))
+    return CMD_WARNING;
+
+  /* Get metric value. */
+  if (argc >= 2)
+    if (!str2metric_type (argv[1], &type))
+      return CMD_WARNING;
+
+  if (argc == 3)
+    ospf_routemap_set (source, argv[2]);
+  else
+    ospf_routemap_unset (source);
+
+  return ospf_redistribute_set (source, type, -1);
+}
+
+DEFUN (ospf_redistribute_source_routemap,
+       ospf_redistribute_source_routemap_cmd,
+       "redistribute (kernel|connected|static|rip|bgp) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int source;
+
+  /* Get distribute source. */
+  if (!str2distribute_source (argv[0], &source))
+    return CMD_WARNING;
+
+  if (argc == 2)
+    ospf_routemap_set (source, argv[1]);
+  else
+    ospf_routemap_unset (source);
+
+  return ospf_redistribute_set (source, -1, -1);
+}
+
+DEFUN (no_ospf_redistribute_source,
+       no_ospf_redistribute_source_cmd,
+       "no redistribute (kernel|connected|static|rip|bgp)",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int source;
+
+  if (!str2distribute_source (argv[0], &source))
+    return CMD_WARNING;
+
+  ospf_routemap_unset (source);
+  return ospf_redistribute_unset (source);
+}
+
+DEFUN (ospf_distribute_list_out,
+       ospf_distribute_list_out_cmd,
+       "distribute-list WORD out (kernel|connected|static|rip|bgp)",
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       OUT_STR
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int source;
+
+  /* Get distribute source. */
+  if (!str2distribute_source (argv[1], &source))
+    return CMD_WARNING;
+
+  return ospf_distribute_list_out_set (source, argv[0]);
+}
+
+DEFUN (no_ospf_distribute_list_out,
+       no_ospf_distribute_list_out_cmd,
+       "no distribute-list WORD out (kernel|connected|static|rip|bgp)",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       OUT_STR
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int source;
+
+  if (!str2distribute_source (argv[1], &source))
+    return CMD_WARNING;
+
+  return ospf_distribute_list_out_unset (source, argv[0]);
+}
+
+/* Default information originate. */
+DEFUN (ospf_default_information_originate_metric_type_routemap,
+       ospf_default_information_originate_metric_type_routemap_cmd,
+       "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type = -1;
+  int metric = -1;
+
+  /* Get metric value. */
+  if (argc >= 1)
+    if (!str2metric (argv[0], &metric))
+      return CMD_WARNING;
+
+  /* Get metric type. */
+  if (argc >= 2)
+    if (!str2metric_type (argv[1], &type))
+      return CMD_WARNING;
+
+  if (argc == 3)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[2]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, type, metric);
+}
+
+ALIAS (ospf_default_information_originate_metric_type_routemap,
+       ospf_default_information_originate_metric_type_cmd,
+       "default-information originate metric <0-16777214> metric-type (1|2)",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+ALIAS (ospf_default_information_originate_metric_type_routemap,
+       ospf_default_information_originate_metric_cmd,
+       "default-information originate metric <0-16777214>",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n")
+
+ALIAS (ospf_default_information_originate_metric_type_routemap,
+       ospf_default_information_originate_cmd,
+       "default-information originate",
+       "Control distribution of default information\n"
+       "Distribute a default route\n")
+
+/* Default information originate. */
+DEFUN (ospf_default_information_originate_metric_routemap,
+       ospf_default_information_originate_metric_routemap_cmd,
+       "default-information originate metric <0-16777214> route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int metric = -1;
+
+  /* Get metric value. */
+  if (argc >= 1)
+    if (!str2metric (argv[0], &metric))
+      return CMD_WARNING;
+
+  if (argc == 2)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[1]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, -1, metric);
+}
+
+/* Default information originate. */
+DEFUN (ospf_default_information_originate_routemap,
+       ospf_default_information_originate_routemap_cmd,
+       "default-information originate route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  if (argc == 1)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[0]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, -1, -1);
+}
+
+DEFUN (ospf_default_information_originate_type_metric_routemap,
+       ospf_default_information_originate_type_metric_routemap_cmd,
+       "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type = -1;
+  int metric = -1;
+
+  /* Get metric type. */
+  if (argc >= 1)
+    if (!str2metric_type (argv[0], &type))
+      return CMD_WARNING;
+
+  /* Get metric value. */
+  if (argc >= 2)
+    if (!str2metric (argv[1], &metric))
+      return CMD_WARNING;
+
+  if (argc == 3)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[2]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, type, metric);
+}
+
+ALIAS (ospf_default_information_originate_type_metric_routemap,
+       ospf_default_information_originate_type_metric_cmd,
+       "default-information originate metric-type (1|2) metric <0-16777214>",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n")
+
+ALIAS (ospf_default_information_originate_type_metric_routemap,
+       ospf_default_information_originate_type_cmd,
+       "default-information originate metric-type (1|2)",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFUN (ospf_default_information_originate_type_routemap,
+       ospf_default_information_originate_type_routemap_cmd,
+       "default-information originate metric-type (1|2) route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type = -1;
+
+  /* Get metric type. */
+  if (argc >= 1)
+    if (!str2metric_type (argv[0], &type))
+      return CMD_WARNING;
+
+  if (argc == 2)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[1]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ZEBRA, type, -1);
+}
+
+DEFUN (ospf_default_information_originate_always_metric_type_routemap,
+       ospf_default_information_originate_always_metric_type_routemap_cmd,
+       "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type = -1;
+  int metric = -1;
+
+  /* Get metric value. */
+  if (argc >= 1)
+    if (!str2metric (argv[0], &metric))
+      return CMD_WARNING;
+
+  /* Get metric type. */
+  if (argc >= 2)
+    if (!str2metric_type (argv[1], &type))
+      return CMD_WARNING;
+
+  if (argc == 3)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[2]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS,
+                                       type, metric);
+}
+
+ALIAS (ospf_default_information_originate_always_metric_type_routemap,
+       ospf_default_information_originate_always_metric_type_cmd,
+       "default-information originate always metric <0-16777214> metric-type (1|2)",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+ALIAS (ospf_default_information_originate_always_metric_type_routemap,
+       ospf_default_information_originate_always_metric_cmd,
+       "default-information originate always metric <0-16777214>",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n")
+
+ALIAS (ospf_default_information_originate_always_metric_type_routemap,
+       ospf_default_information_originate_always_cmd,
+       "default-information originate always",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n")
+
+DEFUN (ospf_default_information_originate_always_metric_routemap,
+       ospf_default_information_originate_always_metric_routemap_cmd,
+       "default-information originate always metric <0-16777214> route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int metric = -1;
+
+  /* Get metric value. */
+  if (argc >= 1)
+    if (!str2metric (argv[0], &metric))
+      return CMD_WARNING;
+
+  if (argc == 2)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[1]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, -1, metric);
+}
+
+DEFUN (ospf_default_information_originate_always_routemap,
+       ospf_default_information_originate_always_routemap_cmd,
+       "default-information originate always route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  if (argc == 1)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[0]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS, -1, -1);
+}
+
+DEFUN (ospf_default_information_originate_always_type_metric_routemap,
+       ospf_default_information_originate_always_type_metric_routemap_cmd,
+       "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type = -1;
+  int metric = -1;
+
+  /* Get metric type. */
+  if (argc >= 1)
+    if (!str2metric_type (argv[0], &type))
+      return CMD_WARNING;
+
+  /* Get metric value. */
+  if (argc >= 2)
+    if (!str2metric (argv[1], &metric))
+      return CMD_WARNING;
+
+  if (argc == 3)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[2]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS,
+                                       type, metric);
+}
+
+ALIAS (ospf_default_information_originate_always_type_metric_routemap,
+       ospf_default_information_originate_always_type_metric_cmd,
+       "default-information originate always metric-type (1|2) metric <0-16777214>",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n")
+
+ALIAS (ospf_default_information_originate_always_type_metric_routemap,
+       ospf_default_information_originate_always_type_cmd,
+       "default-information originate always metric-type (1|2)",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFUN (ospf_default_information_originate_always_type_routemap,
+       ospf_default_information_originate_always_type_routemap_cmd,
+       "default-information originate always metric-type (1|2) route-map WORD",
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int type = -1;
+
+  /* Get metric type. */
+  if (argc >= 1)
+    if (!str2metric_type (argv[0], &type))
+      return CMD_WARNING;
+
+  if (argc == 2)
+    ospf_routemap_set (DEFAULT_ROUTE, argv[1]);
+  else
+    ospf_routemap_unset (DEFAULT_ROUTE);
+
+  return ospf_redistribute_default_set (DEFAULT_ORIGINATE_ALWAYS,
+                                       type, -1);
+}
+
+DEFUN (no_ospf_default_information_originate,
+       no_ospf_default_information_originate_cmd,
+       "no default-information originate",
+       NO_STR
+       "Control distribution of default information\n"
+       "Distribute a default route\n")
+{
+  struct prefix_ipv4 p;
+  struct in_addr nexthop;
+    
+  p.family = AF_INET;
+  p.prefix.s_addr = 0;
+  p.prefixlen = 0;
+
+  ospf_external_lsa_flush (DEFAULT_ROUTE, &p, 0, nexthop);
+
+  if (EXTERNAL_INFO (DEFAULT_ROUTE)) {
+    ospf_external_info_delete (DEFAULT_ROUTE, p);
+    route_table_finish (EXTERNAL_INFO (DEFAULT_ROUTE));
+    EXTERNAL_INFO (DEFAULT_ROUTE) = NULL;
+  }
+
+  ospf_routemap_unset (DEFAULT_ROUTE);
+  return ospf_redistribute_default_unset ();
+}
+
+DEFUN (ospf_default_metric,
+       ospf_default_metric_cmd,
+       "default-metric <0-16777214>",
+       "Set metric of redistributed routes\n"
+       "Default metric\n")
+{
+  int metric = -1;
+
+  if (!str2metric (argv[0], &metric))
+    return CMD_WARNING;
+
+  ospf_top->default_metric = metric;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_default_metric,
+       no_ospf_default_metric_cmd,
+       "no default-metric",
+       NO_STR
+       "Set metric of redistributed routes\n")
+{
+  ospf_top->default_metric = -1;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ospf_default_metric,
+       no_ospf_default_metric_val_cmd,
+       "no default-metric <0-16777214>",
+       NO_STR
+       "Set metric of redistributed routes\n"
+       "Default metric\n")
+
+DEFUN (ospf_distance,
+       ospf_distance_cmd,
+       "distance <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n")
+{
+  ospf_top->distance_all = atoi (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_distance,
+       no_ospf_distance_cmd,
+       "no distance <1-255>",
+       NO_STR
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n")
+{
+  ospf_top->distance_all = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_distance_ospf,
+       no_ospf_distance_ospf_cmd,
+       "no distance ospf",
+       NO_STR
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "OSPF Distance\n")
+{
+  ospf_top->distance_intra = 0;
+  ospf_top->distance_inter = 0;
+  ospf_top->distance_external = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_intra,
+       ospf_distance_ospf_intra_cmd,
+       "distance ospf intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  ospf_top->distance_intra = atoi (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_intra_inter,
+       ospf_distance_ospf_intra_inter_cmd,
+       "distance ospf intra-area <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  ospf_top->distance_intra = atoi (argv[0]);
+  ospf_top->distance_inter = atoi (argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_intra_external,
+       ospf_distance_ospf_intra_external_cmd,
+       "distance ospf intra-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  ospf_top->distance_intra = atoi (argv[0]);
+  ospf_top->distance_external = atoi (argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_intra_inter_external,
+       ospf_distance_ospf_intra_inter_external_cmd,
+       "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  ospf_top->distance_intra = atoi (argv[0]);
+  ospf_top->distance_inter = atoi (argv[1]);
+  ospf_top->distance_external = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_intra_external_inter,
+       ospf_distance_ospf_intra_external_inter_cmd,
+       "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  ospf_top->distance_intra = atoi (argv[0]);
+  ospf_top->distance_external = atoi (argv[1]);
+  ospf_top->distance_inter = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_inter,
+       ospf_distance_ospf_inter_cmd,
+       "distance ospf inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  ospf_top->distance_inter = atoi (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_inter_intra,
+       ospf_distance_ospf_inter_intra_cmd,
+       "distance ospf inter-area <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  ospf_top->distance_inter = atoi (argv[0]);
+  ospf_top->distance_intra = atoi (argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_inter_external,
+       ospf_distance_ospf_inter_external_cmd,
+       "distance ospf inter-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  ospf_top->distance_inter = atoi (argv[0]);
+  ospf_top->distance_external = atoi (argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_inter_intra_external,
+       ospf_distance_ospf_inter_intra_external_cmd,
+       "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  ospf_top->distance_inter = atoi (argv[0]);
+  ospf_top->distance_intra = atoi (argv[1]);
+  ospf_top->distance_external = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_inter_external_intra,
+       ospf_distance_ospf_inter_external_intra_cmd,
+       "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  ospf_top->distance_inter = atoi (argv[0]);
+  ospf_top->distance_external = atoi (argv[1]);
+  ospf_top->distance_intra = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_external,
+       ospf_distance_ospf_external_cmd,
+       "distance ospf external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  ospf_top->distance_external = atoi (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_external_intra,
+       ospf_distance_ospf_external_intra_cmd,
+       "distance ospf external <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  ospf_top->distance_external = atoi (argv[0]);
+  ospf_top->distance_intra = atoi (argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_external_inter,
+       ospf_distance_ospf_external_inter_cmd,
+       "distance ospf external <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  ospf_top->distance_external = atoi (argv[0]);
+  ospf_top->distance_inter = atoi (argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_external_intra_inter,
+       ospf_distance_ospf_external_intra_inter_cmd,
+       "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  ospf_top->distance_external = atoi (argv[0]);
+  ospf_top->distance_intra = atoi (argv[1]);
+  ospf_top->distance_inter = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_ospf_external_inter_intra,
+       ospf_distance_ospf_external_inter_intra_cmd,
+       "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  ospf_top->distance_external = atoi (argv[0]);
+  ospf_top->distance_inter = atoi (argv[1]);
+  ospf_top->distance_intra = atoi (argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_source,
+       ospf_distance_source_cmd,
+       "distance <1-255> A.B.C.D/M",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  ospf_distance_set (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_distance_source,
+       no_ospf_distance_source_cmd,
+       "no distance <1-255> A.B.C.D/M",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  ospf_distance_unset (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf_distance_source_access_list,
+       ospf_distance_source_access_list_cmd,
+       "distance <1-255> A.B.C.D/M WORD",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  ospf_distance_set (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_distance_source_access_list,
+       no_ospf_distance_source_access_list_cmd,
+       "no distance <1-255> A.B.C.D/M WORD",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  ospf_distance_unset (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+
+void
+show_ip_ospf_route_network (struct vty *vty, struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  listnode pnode;
+  struct ospf_path *path;
+
+  vty_out (vty, "============ OSPF network routing table ============%s",
+          VTY_NEWLINE);
+
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((or = rn->info) != NULL)
+      {
+       char buf1[19];
+       snprintf (buf1, 19, "%s/%d",
+                 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+
+       switch (or->path_type)
+         {
+         case OSPF_PATH_INTER_AREA:
+           if (or->type == OSPF_DESTINATION_NETWORK)
+             vty_out (vty, "N IA %-18s    [%d] area: %s%s", buf1, or->cost,
+                      inet_ntoa (or->u.std.area_id), VTY_NEWLINE);
+           else if (or->type == OSPF_DESTINATION_DISCARD)
+             vty_out (vty, "D IA %-18s    Discard entry%s", buf1, VTY_NEWLINE);
+           break;
+         case OSPF_PATH_INTRA_AREA:
+           vty_out (vty, "N    %-18s    [%d] area: %s%s", buf1, or->cost,
+                    inet_ntoa (or->u.std.area_id), VTY_NEWLINE);
+           break;
+         default:
+           break;
+         }
+
+        if (or->type == OSPF_DESTINATION_NETWORK)
+         for (pnode = listhead (or->path); pnode; nextnode (pnode))
+           {
+             path = getdata (pnode);
+             if (path->oi != NULL)
+               {
+                 if (path->nexthop.s_addr == 0)
+                   vty_out (vty, "%24s   directly attached to %s%s",
+                            "", path->oi->ifp->name, VTY_NEWLINE);
+                 else 
+                   vty_out (vty, "%24s   via %s, %s%s", "",
+                            inet_ntoa (path->nexthop), path->oi->ifp->name,
+                            VTY_NEWLINE);
+               }
+           }
+      }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+show_ip_ospf_route_router (struct vty *vty, struct route_table *rtrs)
+{
+  struct route_node *rn;
+  struct ospf_route *or;
+  listnode pn, nn;
+  struct ospf_path *path;
+
+  vty_out (vty, "============ OSPF router routing table =============%s",
+          VTY_NEWLINE);
+  for (rn = route_top (rtrs); rn; rn = route_next (rn))
+    if (rn->info)
+      {
+       int flag = 0;
+
+       vty_out (vty, "R    %-15s    ", inet_ntoa (rn->p.u.prefix4));
+
+       for (nn = listhead ((list) rn->info); nn; nextnode (nn))
+         if ((or = getdata (nn)) != NULL)
+           {
+             if (flag++)
+               vty_out(vty,"                              " );
+
+             /* Show path. */
+             vty_out (vty, "%s [%d] area: %s",
+                      (or->path_type == OSPF_PATH_INTER_AREA ? "IA" : "  "),
+                      or->cost, inet_ntoa (or->u.std.area_id));
+             /* Show flags. */
+             vty_out (vty, "%s%s%s",
+                      (or->u.std.flags & ROUTER_LSA_BORDER ? ", ABR" : ""),
+                      (or->u.std.flags & ROUTER_LSA_EXTERNAL ? ", ASBR" : ""),
+                      VTY_NEWLINE);
+
+             for (pn = listhead (or->path); pn; nextnode (pn))
+               {
+                 path = getdata (pn);
+                 if (path->nexthop.s_addr == 0)
+                   vty_out (vty, "%24s   directly attached to %s%s",
+                            "", path->oi->ifp->name, VTY_NEWLINE);
+                 else 
+                   vty_out (vty, "%24s   via %s, %s%s", "",
+                            inet_ntoa (path->nexthop), path->oi->ifp->name,
+                            VTY_NEWLINE);
+               }
+           }
+      }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+void
+show_ip_ospf_route_external (struct vty *vty, struct route_table *rt)
+{
+  struct route_node *rn;
+  struct ospf_route *er;
+  listnode pnode;
+  struct ospf_path *path;
+
+  vty_out (vty, "============ OSPF external routing table ===========%s",
+          VTY_NEWLINE);
+  for (rn = route_top (rt); rn; rn = route_next (rn))
+    if ((er = rn->info) != NULL)
+      {
+       char buf1[19];
+       snprintf (buf1, 19, "%s/%d",
+                 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+
+       switch (er->path_type)
+         {
+         case OSPF_PATH_TYPE1_EXTERNAL:
+           vty_out (vty, "N E1 %-18s    [%d] tag: %u%s", buf1,
+                    er->cost, er->u.ext.tag, VTY_NEWLINE);
+           break;
+         case OSPF_PATH_TYPE2_EXTERNAL:
+           vty_out (vty, "N E2 %-18s    [%d/%d] tag: %u%s", buf1, er->cost,
+                    er->u.ext.type2_cost, er->u.ext.tag, VTY_NEWLINE);
+           break;
+         }
+
+        for (pnode = listhead (er->path); pnode; nextnode (pnode))
+          {
+            path = getdata (pnode);
+            if (path->oi != NULL)
+              {
+                if (path->nexthop.s_addr == 0)
+                 vty_out (vty, "%24s   directly attached to %s%s",
+                          "", path->oi->ifp->name, VTY_NEWLINE);
+                else 
+                 vty_out (vty, "%24s   via %s, %s%s", "",
+                          inet_ntoa (path->nexthop), path->oi->ifp->name,
+                          VTY_NEWLINE);
+              }
+           }
+        }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+#ifdef HAVE_NSSA
+DEFUN (show_ip_ospf_border_routers,
+       show_ip_ospf_border_routers_cmd,
+       "show ip ospf border-routers",
+       SHOW_STR
+       IP_STR
+       "show all the ABR's and ASBR's\n"
+       "for this area\n")
+{
+  if (ospf_top == NULL)
+    {
+      vty_out (vty, "OSPF is not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (ospf_top->new_table == NULL)
+    {
+      vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* Show Network routes.
+  show_ip_ospf_route_network (vty, ospf_top->new_table);   */
+
+  /* Show Router routes. */
+  show_ip_ospf_route_router (vty, ospf_top->new_rtrs);
+
+  return CMD_SUCCESS;
+}
+#endif /* HAVE_NSSA */
+
+DEFUN (show_ip_ospf_route,
+       show_ip_ospf_route_cmd,
+       "show ip ospf route",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "OSPF routing table\n")
+{
+  if (ospf_top == NULL)
+    {
+      vty_out (vty, "OSPF is not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (ospf_top->new_table == NULL)
+    {
+      vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* Show Network routes. */
+  show_ip_ospf_route_network (vty, ospf_top->new_table);
+
+  /* Show Router routes. */
+  show_ip_ospf_route_router (vty, ospf_top->new_rtrs);
+
+  /* Show AS External routes. */
+  show_ip_ospf_route_external (vty, ospf_top->old_external_route);
+
+  return CMD_SUCCESS;
+}
+
+\f
+char *ospf_abr_type_str[] = 
+{
+  "unknown",
+  "standard",
+  "ibm",
+  "cisco",
+  "shortcut"
+};
+
+char *ospf_shortcut_mode_str[] = 
+{
+  "default",
+  "enable",
+  "disable"
+};
+
+
+void
+area_id2str (char *buf, int length, struct ospf_area *area)
+{
+  memset (buf, 0, length);
+
+  if (area->format == OSPF_AREA_ID_FORMAT_ADDRESS)
+    strncpy (buf, inet_ntoa (area->area_id), length);
+  else
+    sprintf (buf, "%lu", (unsigned long) ntohl (area->area_id.s_addr));
+}
+
+\f
+char *ospf_int_type_str[] = 
+{
+  "unknown",           /* should never be used. */
+  "point-to-point",
+  "broadcast",
+  "non-broadcast",
+  "point-to-multipoint",
+  "virtual-link",      /* should never be used. */
+  "loopback"
+};
+
+/* Configuration write function for ospfd. */
+int
+config_write_interface (struct vty *vty)
+{
+  listnode n1, n2;
+  struct interface *ifp;
+  struct crypt_key *ck;
+  int write = 0;
+  struct route_node *rn = NULL;
+  struct ospf_if_params *params;
+
+  for (n1 = listhead (iflist); n1; nextnode (n1))
+    {
+      ifp = getdata (n1);
+
+      if (memcmp (ifp->name, "VLINK", 5) == 0)
+       continue;
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+      vty_out (vty, "interface %s%s", ifp->name,
+               VTY_NEWLINE);
+      if (ifp->desc)
+        vty_out (vty, " description %s%s", ifp->desc,
+               VTY_NEWLINE);
+
+      write++;
+
+      params = IF_DEF_PARAMS (ifp);
+      
+      do {
+       /* Interface Network print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, type) &&
+           params->type != OSPF_IFTYPE_BROADCAST &&
+           params->type != OSPF_IFTYPE_LOOPBACK)
+         {
+           vty_out (vty, " ip ospf network %s",
+                    ospf_int_type_str[params->type]);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       /* OSPF interface authentication print */
+       if (OSPF_IF_PARAM_CONFIGURED (params, auth_type) &&
+           params->auth_type != OSPF_AUTH_NOTSET)
+         {
+           char *auth_str;
+           
+           /* Translation tables are not that much help here due to syntax
+              of the simple option */
+           switch (params->auth_type)
+             {
+               
+             case OSPF_AUTH_NULL:
+               auth_str = " null";
+               break;
+               
+             case OSPF_AUTH_SIMPLE:
+               auth_str = "";
+               break;
+               
+             case OSPF_AUTH_CRYPTOGRAPHIC:
+               auth_str = " message-digest";
+               break;
+               
+             default:
+               auth_str = "";
+               break;
+             }
+           
+           vty_out (vty, " ip ospf authentication%s", auth_str);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+
+       /* Simple Authentication Password print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, auth_simple) &&
+           params->auth_simple[0] != '\0')
+         {
+           vty_out (vty, " ip ospf authentication-key %s",
+                    params->auth_simple);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       /* Cryptographic Authentication Key print. */
+       for (n2 = listhead (params->auth_crypt); n2; nextnode (n2))
+         {
+           ck = getdata (n2);
+           vty_out (vty, " ip ospf message-digest-key %d md5 %s",
+                    ck->key_id, ck->auth_key);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       /* Interface Output Cost print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, output_cost_cmd))
+         {
+           vty_out (vty, " ip ospf cost %u", params->output_cost_cmd);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       /* Hello Interval print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, v_hello) &&
+           params->v_hello != OSPF_HELLO_INTERVAL_DEFAULT)
+         {
+           vty_out (vty, " ip ospf hello-interval %u", params->v_hello);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       
+       /* Router Dead Interval print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, v_wait) &&
+           params->v_wait != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT)
+         {
+           vty_out (vty, " ip ospf dead-interval %u", params->v_wait);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+      /* Router Priority print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, priority) &&
+           params->priority != OSPF_ROUTER_PRIORITY_DEFAULT)
+         {
+           vty_out (vty, " ip ospf priority %u", params->priority);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       /* Retransmit Interval print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, retransmit_interval) &&
+           params->retransmit_interval != OSPF_RETRANSMIT_INTERVAL_DEFAULT)
+         {
+           vty_out (vty, " ip ospf retransmit-interval %u",
+                    params->retransmit_interval);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+       
+       /* Transmit Delay print. */
+       if (OSPF_IF_PARAM_CONFIGURED (params, transmit_delay) &&
+           params->transmit_delay != OSPF_TRANSMIT_DELAY_DEFAULT)
+         {
+           vty_out (vty, " ip ospf transmit-delay %u", params->transmit_delay);
+           if (params != IF_DEF_PARAMS (ifp))
+             vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+
+       while (1)
+         {
+           if (rn == NULL)
+             rn = route_top (IF_OIFS_PARAMS (ifp));
+           else
+             rn = route_next (rn);
+
+           if (rn == NULL)
+             break;
+           params = rn->info;
+           if (params != NULL)
+             break;
+         }
+      } while (rn);
+      
+#ifdef HAVE_OPAQUE_LSA
+      ospf_opaque_config_write_if (vty, ifp);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  return write;
+}
+
+int
+config_write_network_area (struct vty *vty)
+{
+  struct route_node *rn;
+  u_char buf[INET_ADDRSTRLEN];
+
+  /* `network area' print. */
+  for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn))
+    if (rn->info)
+      {
+       struct ospf_network *n = rn->info;
+
+       memset (buf, 0, INET_ADDRSTRLEN);
+
+       /* Create Area ID string by specified Area ID format. */
+       if (n->format == OSPF_AREA_ID_FORMAT_ADDRESS)
+         strncpy (buf, inet_ntoa (n->area_id), INET_ADDRSTRLEN);
+       else
+         sprintf (buf, "%lu", 
+                  (unsigned long int) ntohl (n->area_id.s_addr));
+
+       /* Network print. */
+       vty_out (vty, " network %s/%d area %s%s",
+                inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+                buf, VTY_NEWLINE);
+      }
+
+  return 0;
+}
+
+int
+config_write_ospf_area (struct vty *vty)
+{
+  listnode node;
+  u_char buf[INET_ADDRSTRLEN];
+
+  /* Area configuration print. */
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = getdata (node);
+      struct route_node *rn1;
+
+      area_id2str (buf, INET_ADDRSTRLEN, area);
+
+      if (area->auth_type != OSPF_AUTH_NULL)
+       {
+         if (area->auth_type == OSPF_AUTH_SIMPLE)
+           vty_out (vty, " area %s authentication%s", buf, VTY_NEWLINE);
+         else
+           vty_out (vty, " area %s authentication message-digest%s",
+                    buf, VTY_NEWLINE);
+       }
+
+      if (area->shortcut_configured != OSPF_SHORTCUT_DEFAULT)
+       vty_out (vty, " area %s shortcut %s%s", buf,
+                ospf_shortcut_mode_str[area->shortcut_configured],
+                VTY_NEWLINE);
+
+      if ((area->external_routing == OSPF_AREA_STUB)
+#ifdef HAVE_NSSA
+         || (area->external_routing == OSPF_AREA_NSSA)
+#endif /* HAVE_NSSA */
+         )
+       {
+#ifdef HAVE_NSSA
+         if (area->external_routing == OSPF_AREA_NSSA)
+           vty_out (vty, " area %s nssa", buf);
+         else
+#endif /* HAVE_NSSA */
+           vty_out (vty, " area %s stub", buf);
+
+         if (area->no_summary)
+           vty_out (vty, " no-summary");
+
+         vty_out (vty, "%s", VTY_NEWLINE);
+
+         if (area->default_cost != 1)
+           vty_out (vty, " area %s default-cost %d%s", buf, 
+                    area->default_cost, VTY_NEWLINE);
+       }
+
+      for (rn1 = route_top (area->ranges); rn1; rn1 = route_next (rn1))
+       if (rn1->info)
+         {
+           struct ospf_area_range *range = rn1->info;
+
+           vty_out (vty, " area %s range %s/%d", buf,
+                    inet_ntoa (rn1->p.u.prefix4), rn1->p.prefixlen);
+
+           if (range->cost_config != -1)
+             vty_out (vty, " cost %d", range->cost_config);
+
+           if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE))
+             vty_out (vty, " not-advertise");
+
+           if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE))
+             vty_out (vty, " substitute %s/%d",
+                      inet_ntoa (range->subst_addr), range->subst_masklen);
+
+           vty_out (vty, "%s", VTY_NEWLINE);
+         }
+
+      if (EXPORT_NAME (area))
+       vty_out (vty, " area %s export-list %s%s", buf,
+                EXPORT_NAME (area), VTY_NEWLINE);
+
+      if (IMPORT_NAME (area))
+       vty_out (vty, " area %s import-list %s%s", buf,
+                IMPORT_NAME (area), VTY_NEWLINE);
+
+      if (PREFIX_NAME_IN (area))
+       vty_out (vty, " area %s filter-list prefix %s in%s", buf,
+                PREFIX_NAME_IN (area), VTY_NEWLINE);
+
+      if (PREFIX_NAME_OUT (area))
+       vty_out (vty, " area %s filter-list prefix %s out%s", buf,
+                PREFIX_NAME_OUT (area), VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+int
+config_write_ospf_nbr_nbma (struct vty *vty)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+  struct route_node *rn;
+
+  /* Static Neighbor configuration print. */
+  for (rn = route_top (ospf_top->nbr_nbma); rn; rn = route_next (rn))
+    if ((nbr_nbma = rn->info))
+      {
+       vty_out (vty, " neighbor %s", inet_ntoa (nbr_nbma->addr));
+
+       if (nbr_nbma->priority != OSPF_NEIGHBOR_PRIORITY_DEFAULT)
+         vty_out (vty, " priority %d", nbr_nbma->priority);
+
+       if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT)
+         vty_out (vty, " poll-interval %d", nbr_nbma->v_poll);
+
+       vty_out (vty, "%s", VTY_NEWLINE);
+      }
+
+  return 0;
+}
+
+int
+config_write_virtual_link (struct vty *vty)
+{
+  listnode node;
+  u_char buf[INET_ADDRSTRLEN];
+
+  /* Virtual-Link print */
+  for (node = listhead (ospf_top->vlinks); node; nextnode (node))
+    {
+      listnode n2;
+      struct crypt_key *ck;
+      struct ospf_vl_data *vl_data = getdata (node);
+      struct ospf_interface *oi;
+
+      if (vl_data != NULL)
+       {
+         memset (buf, 0, INET_ADDRSTRLEN);
+         
+         if (vl_data->format == OSPF_AREA_ID_FORMAT_ADDRESS)
+           strncpy (buf, inet_ntoa (vl_data->vl_area_id), INET_ADDRSTRLEN);
+         else
+           sprintf (buf, "%lu", 
+                    (unsigned long int) ntohl (vl_data->vl_area_id.s_addr));
+         oi = vl_data->vl_oi;
+
+         /* timers */
+         if (OSPF_IF_PARAM (oi, v_hello) != OSPF_HELLO_INTERVAL_DEFAULT ||
+             OSPF_IF_PARAM (oi, v_wait) != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT ||
+             OSPF_IF_PARAM (oi, retransmit_interval) != OSPF_RETRANSMIT_INTERVAL_DEFAULT ||
+             OSPF_IF_PARAM (oi, transmit_delay) != OSPF_TRANSMIT_DELAY_DEFAULT)
+           vty_out (vty, " area %s virtual-link %s hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d%s",
+                    buf,
+                    inet_ntoa (vl_data->vl_peer), 
+                    OSPF_IF_PARAM (oi, v_hello),
+                    OSPF_IF_PARAM (oi, retransmit_interval),
+                    OSPF_IF_PARAM (oi, transmit_delay),
+                    OSPF_IF_PARAM (oi, v_wait),
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, " area %s virtual-link %s%s", buf,
+                    inet_ntoa (vl_data->vl_peer), VTY_NEWLINE);
+         /* Auth key */
+         if (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple[0] != '\0')
+           vty_out (vty, " area %s virtual-link %s authentication-key %s%s",
+                    buf,
+                    inet_ntoa (vl_data->vl_peer),
+                    IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple,
+                    VTY_NEWLINE);
+         /* md5 keys */
+         for (n2 = listhead (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_crypt); n2; nextnode (n2))
+           {
+             ck = getdata (n2);
+             vty_out (vty, " area %s virtual-link %s message-digest-key %d md5 %s%s",
+                      buf,
+                      inet_ntoa (vl_data->vl_peer),
+                      ck->key_id, ck->auth_key, VTY_NEWLINE);
+           }
+        
+       }
+    }
+
+  return 0;
+}
+
+\f
+char *distribute_str[] = { "system", "kernel", "connected", "static", "rip",
+                          "ripng", "ospf", "ospf6", "bgp"};
+int
+config_write_ospf_redistribute (struct vty *vty)
+{
+  int type;
+
+  /* redistribute print. */
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+    if (type != zclient->redist_default && zclient->redist[type])
+      {
+        vty_out (vty, " redistribute %s", distribute_str[type]);
+       if (ospf_top->dmetric[type].value >= 0)
+         vty_out (vty, " metric %d", ospf_top->dmetric[type].value);
+       
+        if (ospf_top->dmetric[type].type == EXTERNAL_METRIC_TYPE_1)
+         vty_out (vty, " metric-type 1");
+
+       if (ROUTEMAP_NAME (type))
+         vty_out (vty, " route-map %s", ROUTEMAP_NAME (type));
+       
+        vty_out (vty, "%s", VTY_NEWLINE);
+      }
+
+  return 0;
+}
+
+int
+config_write_ospf_default_metric (struct vty *vty)
+{
+  if (ospf_top->default_metric != -1)
+    vty_out (vty, " default-metric %d%s", ospf_top->default_metric,
+            VTY_NEWLINE);
+  return 0;
+}
+
+int
+config_write_ospf_distribute (struct vty *vty)
+{
+  int type;
+
+  if (ospf_top)
+    {
+      /* distribute-list print. */
+      for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+       if (ospf_top->dlist[type].name)
+         vty_out (vty, " distribute-list %s out %s%s", 
+                  ospf_top->dlist[type].name,
+                  distribute_str[type], VTY_NEWLINE);
+
+      /* default-information print. */
+      if (ospf_top->default_originate != DEFAULT_ORIGINATE_NONE)
+       {
+         if (ospf_top->default_originate == DEFAULT_ORIGINATE_ZEBRA)
+           vty_out (vty, " default-information originate");
+         else
+           vty_out (vty, " default-information originate always");
+
+         if (ospf_top->dmetric[DEFAULT_ROUTE].value >= 0)
+           vty_out (vty, " metric %d",
+                    ospf_top->dmetric[DEFAULT_ROUTE].value);
+         if (ospf_top->dmetric[DEFAULT_ROUTE].type == EXTERNAL_METRIC_TYPE_1)
+           vty_out (vty, " metric-type 1");
+
+         if (ROUTEMAP_NAME (DEFAULT_ROUTE))
+           vty_out (vty, " route-map %s", ROUTEMAP_NAME (DEFAULT_ROUTE));
+         
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+
+    }
+
+  return 0;
+}
+
+int
+config_write_ospf_distance (struct vty *vty)
+{
+  struct route_node *rn;
+  struct ospf_distance *odistance;
+
+  if (ospf_top->distance_all)
+    vty_out (vty, " distance %d%s", ospf_top->distance_all, VTY_NEWLINE);
+
+  if (ospf_top->distance_intra 
+      || ospf_top->distance_inter 
+      || ospf_top->distance_external)
+    {
+      vty_out (vty, " distance ospf");
+
+      if (ospf_top->distance_intra)
+       vty_out (vty, " intra-area %d", ospf_top->distance_intra);
+      if (ospf_top->distance_inter)
+       vty_out (vty, " inter-area %d", ospf_top->distance_inter);
+      if (ospf_top->distance_external)
+       vty_out (vty, " external %d", ospf_top->distance_external);
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  
+  for (rn = route_top (ospf_top->distance_table); rn; rn = route_next (rn))
+    if ((odistance = rn->info) != NULL)
+      {
+       vty_out (vty, " distance %d %s/%d %s%s", odistance->distance,
+                inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+                odistance->access_list ? odistance->access_list : "",
+                VTY_NEWLINE);
+      }
+  return 0;
+}
+
+/* OSPF configuration write function. */
+int
+ospf_config_write (struct vty *vty)
+{
+  listnode node;
+  int write = 0;
+
+  if (ospf_top != NULL)
+    {
+      /* `router ospf' print. */
+      vty_out (vty, "router ospf%s", VTY_NEWLINE);
+
+      write++;
+
+      if (!ospf_top->networks)
+        return write;
+
+      /* Router ID print. */
+      if (ospf_top->router_id_static.s_addr != 0)
+        vty_out (vty, " ospf router-id %s%s",
+                 inet_ntoa (ospf_top->router_id_static), VTY_NEWLINE);
+
+      /* ABR type print. */
+      if (ospf_top->abr_type != OSPF_ABR_STAND)
+        vty_out (vty, " ospf abr-type %s%s", 
+                 ospf_abr_type_str[ospf_top->abr_type], VTY_NEWLINE);
+
+      /* RFC1583 compatibility flag print -- Compatible with CISCO 12.1. */
+      if (CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE))
+       vty_out (vty, " compatible rfc1583%s", VTY_NEWLINE);
+
+      /* auto-cost reference-bandwidth configuration.  */
+      if (ospf_top->ref_bandwidth != OSPF_DEFAULT_REF_BANDWIDTH)
+       vty_out (vty, " auto-cost reference-bandwidth %d%s",
+                ospf_top->ref_bandwidth / 1000, VTY_NEWLINE);
+
+      /* SPF timers print. */
+      if (ospf_top->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
+         ospf_top->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT)
+       vty_out (vty, " timers spf %d %d%s",
+                ospf_top->spf_delay, ospf_top->spf_holdtime, VTY_NEWLINE);
+
+      /* SPF refresh parameters print. */
+      if (ospf_top->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
+       vty_out (vty, " refresh timer %d%s",
+                ospf_top->lsa_refresh_interval, VTY_NEWLINE);
+
+      /* Redistribute information print. */
+      config_write_ospf_redistribute (vty);
+
+      /* passive-interface print. */
+      for (node = listhead (ospf_top->iflist); node; nextnode (node))
+        {
+          struct interface *ifp = getdata (node);
+
+         if (!ifp)
+           continue;
+         if (IF_DEF_PARAMS (ifp)->passive_interface == OSPF_IF_PASSIVE)
+           vty_out (vty, " passive-interface %s%s",
+                    ifp->name, VTY_NEWLINE);
+        }
+
+      for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+        {
+          struct ospf_interface *oi = getdata (node);
+
+         if (OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface) &&
+             oi->params->passive_interface == OSPF_IF_PASSIVE)
+           vty_out (vty, " passive-interface %s%s",
+                    inet_ntoa (oi->address->u.prefix4), VTY_NEWLINE);
+        }
+
+      
+      /* Network area print. */
+      config_write_network_area (vty);
+
+      /* Area config print. */
+      config_write_ospf_area (vty);
+
+      /* static neighbor print. */
+      config_write_ospf_nbr_nbma (vty);
+
+      /* Virtual-Link print. */
+      config_write_virtual_link (vty);
+
+      /* Default metric configuration.  */
+      config_write_ospf_default_metric (vty);
+
+      /* Distribute-list and default-information print. */
+      config_write_ospf_distribute (vty);
+
+      /* Distance configuration. */
+      config_write_ospf_distance (vty);
+
+#ifdef HAVE_OPAQUE_LSA
+      ospf_opaque_config_write_router (vty, ospf_top);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  return write;
+}
+
+void
+ospf_vty_show_init ()
+{
+  /* "show ip ospf" commands. */
+  install_element (VIEW_NODE, &show_ip_ospf_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_cmd);
+
+  /* "show ip ospf database" commands. */
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_database_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_cmd);
+
+  /* "show ip ospf interface" commands. */
+  install_element (VIEW_NODE, &show_ip_ospf_interface_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd);
+
+  /* "show ip ospf neighbor" commands. */
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd);
+
+  /* "show ip ospf route" commands. */
+  install_element (VIEW_NODE, &show_ip_ospf_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_route_cmd);
+#ifdef HAVE_NSSA
+  install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd);
+  install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd);
+#endif /* HAVE_NSSA */
+}
+
+\f
+/* ospfd's interface node. */
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+  1
+};
+
+/* Initialization of OSPF interface. */
+void
+ospf_vty_if_init ()
+{
+  /* Install interface node. */
+  install_node (&interface_node, config_write_interface);
+
+  install_element (CONFIG_NODE, &interface_cmd);
+  install_default (INTERFACE_NODE);
+
+  /* "description" commands. */
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+
+  /* "ip ospf authentication" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd);
+
+  /* "ip ospf message-digest-key" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd);
+
+  /* "ip ospf cost" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_cost_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_cost_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_cost_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd);
+
+  /* "ip ospf dead-interval" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd);
+
+  /* "ip ospf hello-interval" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd);
+
+  /* "ip ospf network" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_network_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd);
+
+  /* "ip ospf priority" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_priority_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd);
+
+  /* "ip ospf retransmit-interval" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd);
+
+  /* "ip ospf transmit-delay" commands. */
+  install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd);
+  install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd);
+  install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd);
+
+  /* These commands are compatibitliy for previous version. */
+  install_element (INTERFACE_NODE, &ospf_authentication_key_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd);
+  install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd);
+  install_element (INTERFACE_NODE, &ospf_cost_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_cost_cmd);
+  install_element (INTERFACE_NODE, &ospf_dead_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd);
+  install_element (INTERFACE_NODE, &ospf_hello_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd);
+  install_element (INTERFACE_NODE, &ospf_network_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_network_cmd);
+  install_element (INTERFACE_NODE, &ospf_priority_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_priority_cmd);
+  install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd);
+  install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd);
+  install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd);
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-router)#",
+};
+
+void
+ospf_vty_zebra_init ()
+{
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_redistribute_source_metric_type_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_redistribute_source_type_metric_routemap_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd);
+  install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd);
+  
+  install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd);
+
+  install_element (OSPF_NODE, &ospf_distribute_list_out_cmd);
+  install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd);
+
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_metric_type_cmd);
+  install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_type_metric_cmd);
+  install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd);
+  install_element (OSPF_NODE, &ospf_default_information_originate_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_metric_type_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_metric_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_type_metric_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_type_cmd);
+
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_metric_type_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_metric_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_type_metric_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_type_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_metric_type_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_metric_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_type_metric_routemap_cmd);
+  install_element (OSPF_NODE,
+                  &ospf_default_information_originate_always_type_routemap_cmd);
+
+  install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd);
+
+  install_element (OSPF_NODE, &ospf_default_metric_cmd);
+  install_element (OSPF_NODE, &no_ospf_default_metric_cmd);
+  install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd);
+
+  install_element (OSPF_NODE, &ospf_distance_cmd);
+  install_element (OSPF_NODE, &no_ospf_distance_cmd);
+  install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd);
+#if 0
+  install_element (OSPF_NODE, &ospf_distance_source_cmd);
+  install_element (OSPF_NODE, &no_ospf_distance_source_cmd);
+  install_element (OSPF_NODE, &ospf_distance_source_access_list_cmd);
+  install_element (OSPF_NODE, &no_ospf_distance_source_access_list_cmd);
+#endif /* 0 */
+}
+
+struct cmd_node ospf_node =
+{
+  OSPF_NODE,
+  "%s(config-router)# ",
+  1
+};
+
+\f
+/* Install OSPF related vty commands. */
+void
+ospf_vty_init ()
+{
+  /* Install ospf top node. */
+  install_node (&ospf_node, ospf_config_write);
+
+  /* "router ospf" commands. */
+  install_element (CONFIG_NODE, &router_ospf_cmd);
+  install_element (CONFIG_NODE, &no_router_ospf_cmd);
+
+  install_default (OSPF_NODE);
+
+  /* "ospf router-id" commands. */
+  install_element (OSPF_NODE, &ospf_router_id_cmd);
+  install_element (OSPF_NODE, &no_ospf_router_id_cmd);
+  install_element (OSPF_NODE, &router_id_cmd);
+  install_element (OSPF_NODE, &no_router_id_cmd);
+
+  /* "passive-interface" commands. */
+  install_element (OSPF_NODE, &passive_interface_addr_cmd);
+  install_element (OSPF_NODE, &passive_interface_cmd);
+  install_element (OSPF_NODE, &no_passive_interface_addr_cmd);
+  install_element (OSPF_NODE, &no_passive_interface_cmd);
+
+  /* "ospf abr-type" commands. */
+  install_element (OSPF_NODE, &ospf_abr_type_cmd);
+  install_element (OSPF_NODE, &no_ospf_abr_type_cmd);
+
+  /* "ospf rfc1583-compatible" commands. */
+  install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd);
+  install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd);
+  install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd);
+  install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd);
+
+  /* "network area" commands. */
+  install_element (OSPF_NODE, &network_area_cmd);
+  install_element (OSPF_NODE, &no_network_area_cmd);
+
+  /* "area authentication" commands. */
+  install_element (OSPF_NODE, &area_authentication_message_digest_cmd);
+  install_element (OSPF_NODE, &area_authentication_cmd);
+  install_element (OSPF_NODE, &no_area_authentication_cmd);
+
+  /* "area range" commands.  */
+  install_element (OSPF_NODE, &area_range_cmd);
+  install_element (OSPF_NODE, &area_range_advertise_cmd);
+  install_element (OSPF_NODE, &area_range_cost_cmd);
+  install_element (OSPF_NODE, &area_range_advertise_cost_cmd);
+  install_element (OSPF_NODE, &area_range_not_advertise_cmd);
+  install_element (OSPF_NODE, &no_area_range_cmd);
+  install_element (OSPF_NODE, &no_area_range_advertise_cmd);
+  install_element (OSPF_NODE, &no_area_range_cost_cmd);
+  install_element (OSPF_NODE, &no_area_range_advertise_cost_cmd);
+  install_element (OSPF_NODE, &area_range_substitute_cmd);
+  install_element (OSPF_NODE, &no_area_range_substitute_cmd);
+
+  /* "area virtual-link" commands. */
+  install_element (OSPF_NODE, &area_vlink_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_param1_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_param1_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_param2_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_param2_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_param3_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_param3_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_param4_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_param4_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_authtype_args_cmd);
+  install_element (OSPF_NODE, &area_vlink_authtype_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_authtype_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_md5_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_md5_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_authkey_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_authkey_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_authtype_args_authkey_cmd);
+  install_element (OSPF_NODE, &area_vlink_authtype_authkey_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_authtype_authkey_cmd);
+
+  install_element (OSPF_NODE, &area_vlink_authtype_args_md5_cmd);
+  install_element (OSPF_NODE, &area_vlink_authtype_md5_cmd);
+  install_element (OSPF_NODE, &no_area_vlink_authtype_md5_cmd);
+
+  /* "area stub" commands. */
+  install_element (OSPF_NODE, &area_stub_no_summary_cmd);
+  install_element (OSPF_NODE, &area_stub_cmd);
+  install_element (OSPF_NODE, &no_area_stub_no_summary_cmd);
+  install_element (OSPF_NODE, &no_area_stub_cmd);
+
+#ifdef HAVE_NSSA
+  /* "area nssa" commands. */
+  install_element (OSPF_NODE, &area_nssa_cmd);
+  install_element (OSPF_NODE, &area_nssa_translate_no_summary_cmd);
+  install_element (OSPF_NODE, &area_nssa_translate_cmd);
+  install_element (OSPF_NODE, &area_nssa_no_summary_cmd);
+  install_element (OSPF_NODE, &no_area_nssa_cmd);
+  install_element (OSPF_NODE, &no_area_nssa_no_summary_cmd);
+#endif /* HAVE_NSSA */
+
+  install_element (OSPF_NODE, &area_default_cost_cmd);
+  install_element (OSPF_NODE, &no_area_default_cost_cmd);
+
+  install_element (OSPF_NODE, &area_shortcut_cmd);
+  install_element (OSPF_NODE, &no_area_shortcut_cmd);
+
+  install_element (OSPF_NODE, &area_export_list_cmd);
+  install_element (OSPF_NODE, &no_area_export_list_cmd);
+
+  install_element (OSPF_NODE, &area_filter_list_cmd);
+  install_element (OSPF_NODE, &no_area_filter_list_cmd);
+
+  install_element (OSPF_NODE, &area_import_list_cmd);
+  install_element (OSPF_NODE, &no_area_import_list_cmd);
+
+  install_element (OSPF_NODE, &timers_spf_cmd);
+  install_element (OSPF_NODE, &no_timers_spf_cmd);
+
+  install_element (OSPF_NODE, &refresh_timer_cmd);
+  install_element (OSPF_NODE, &no_refresh_timer_val_cmd);
+  install_element (OSPF_NODE, &no_refresh_timer_cmd);
+  
+  install_element (OSPF_NODE, &auto_cost_reference_bandwidth_cmd);
+  install_element (OSPF_NODE, &no_auto_cost_reference_bandwidth_cmd);
+
+  /* "neighbor" commands. */
+  install_element (OSPF_NODE, &neighbor_cmd);
+  install_element (OSPF_NODE, &neighbor_priority_poll_interval_cmd);
+  install_element (OSPF_NODE, &neighbor_priority_cmd);
+  install_element (OSPF_NODE, &neighbor_poll_interval_cmd);
+  install_element (OSPF_NODE, &neighbor_poll_interval_priority_cmd);
+  install_element (OSPF_NODE, &no_neighbor_cmd);
+  install_element (OSPF_NODE, &no_neighbor_priority_cmd);
+  install_element (OSPF_NODE, &no_neighbor_poll_interval_cmd);
+
+  /* Init interface related vty commands. */
+  ospf_vty_if_init ();
+
+  /* Init zebra related vty commands. */
+  ospf_vty_zebra_init ();
+}
+
diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h
new file mode 100644 (file)
index 0000000..9f30e20
--- /dev/null
@@ -0,0 +1,85 @@
+/* OSPF VTY interface.
+ * Copyright (C) 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/* Macros. */
+#define VTY_GET_UINT32(NAME,V,STR)                                            \
+{                                                                             \
+  char *endptr = NULL;                                                        \
+  (V) = strtoul ((STR), &endptr, 10);                                         \
+  if (*endptr != '\0' || ((V) == ULONG_MAX && errno == ERANGE))               \
+    {                                                                         \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);              \
+      return CMD_WARNING;                                                     \
+    }                                                                         \
+}
+
+#define VTY_GET_IPV4_ADDRESS(NAME,V,STR)                                      \
+{                                                                             \
+  int retv;                                                                   \
+  retv = inet_aton ((STR), &(V));                                             \
+  if (!retv)                                                                  \
+    {                                                                         \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);              \
+      return CMD_WARNING;                                                     \
+    }                                                                         \
+}
+
+#define VTY_GET_IPV4_PREFIX(NAME,V,STR)                                       \
+{                                                                             \
+  int retv;                                                                   \
+  retv = str2prefix_ipv4 ((STR), &(V));                                       \
+  if (retv <= 0)                                                              \
+    {                                                                         \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);              \
+      return CMD_WARNING;                                                     \
+    }                                                                         \
+}
+
+#define VTY_GET_OSPF_AREA_ID(V,F,STR)                                         \
+{                                                                             \
+  int retv;                                                                   \
+  retv = ospf_str2area_id ((STR), &(V), &(F));                                \
+  if (retv < 0)                                                               \
+    {                                                                         \
+      vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE);                \
+      return CMD_WARNING;                                                     \
+    }                                                                         \
+}
+
+#define VTY_GET_OSPF_AREA_ID_NO_BB(NAME,V,F,STR)                              \
+{                                                                             \
+  int retv;                                                                   \
+  retv = ospf_str2area_id ((STR), &(V), &(F));                                \
+  if (retv < 0)                                                               \
+    {                                                                         \
+      vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE);                \
+      return CMD_WARNING;                                                     \
+    }                                                                         \
+  if (OSPF_IS_AREA_ID_BACKBONE ((V)))                                         \
+    {                                                                         \
+      vty_out (vty, "%% You can't configure %s to backbone%s",                \
+               NAME, VTY_NEWLINE);                                            \
+    }                                                                         \
+}
+
+/* Prototypes. */
+void ospf_vty_init ();
+void ospf_vty_show_init ();
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
new file mode 100644 (file)
index 0000000..1ad31f2
--- /dev/null
@@ -0,0 +1,1180 @@
+/*
+ * Zebra connect library for OSPFd
+ * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "command.h"
+#include "network.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "table.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "filter.h"
+#include "log.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#ifdef HAVE_SNMP
+#include "ospfd/ospf_snmp.h"
+#endif /* HAVE_SNMP */
+
+/* Zebra structure to hold current status. */
+struct zclient *zclient = NULL;
+
+/* For registering threads. */
+extern struct thread_master *master;
+
+/* Inteface addition message from zebra. */
+int
+ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    zlog_info ("Zebra: interface add %s index %d flags %ld metric %d mtu %d",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
+    {
+      SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
+      IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
+      
+      if (if_is_broadcast (ifp))
+       IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
+      else if (if_is_pointopoint (ifp))
+       IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT;
+      else if (if_is_loopback (ifp))
+       IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_LOOPBACK;
+    }
+
+  ospf_if_update ();
+
+#ifdef HAVE_SNMP
+  ospf_snmp_if_update (ifp);
+#endif /* HAVE_SNMP */
+
+  return 0;
+}
+
+int
+ospf_interface_delete (int command, struct zclient *zclient,
+                      zebra_size_t length)
+{
+  struct interface *ifp;
+  struct stream *s;
+  struct route_node *rn;
+
+  s = zclient->ibuf;  
+  /* zebra_interface_state_read() updates interface structure in iflist */
+  ifp = zebra_interface_state_read (s);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (if_is_up (ifp))
+    zlog_warn ("Zebra: got delete of %s, but interface is still up",
+              ifp->name);
+  
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    zlog_info ("Zebra: interface delete %s index %d flags %ld metric %d mtu %d",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);  
+
+#ifdef HAVE_SNMP
+  ospf_snmp_if_delete (ifp);
+#endif /* HAVE_SNMP */
+
+  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+    if (rn->info)
+      ospf_if_free ((struct ospf_interface *) rn->info);
+
+  for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
+    if (rn->info)
+      ospf_del_if_params (rn->info);
+  
+  if_delete (ifp);
+
+  return 0;
+}
+
+struct interface *
+zebra_interface_if_lookup (struct stream *s)
+{
+  struct interface *ifp;
+  u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+  /* Read interface name. */
+  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+  /* Lookup this by interface index. */
+  ifp = if_lookup_by_name (ifname_tmp);
+
+  /* If such interface does not exist, indicate an error */
+  if (!ifp)
+    return NULL;
+
+  return ifp;
+}
+
+void
+zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
+{
+  /* Read interface's index. */
+  ifp->ifindex = stream_getl (s);
+
+  /* Read interface's value. */
+  ifp->flags = stream_getl (s);
+  ifp->metric = stream_getl (s);
+  ifp->mtu = stream_getl (s);
+  ifp->bandwidth = stream_getl (s);
+}
+
+int
+ospf_interface_state_up (int command, struct zclient *zclient,
+                        zebra_size_t length)
+{
+  struct interface *ifp;
+  struct interface if_tmp;
+  struct ospf_interface *oi;
+  struct route_node *rn;
+  
+  ifp = zebra_interface_if_lookup (zclient->ibuf);
+
+  if (ifp == NULL)
+    return 0;
+
+  /* Interface is already up. */
+  if (if_is_up (ifp))
+    {
+      /* Temporarily keep ifp values. */
+      memcpy (&if_tmp, ifp, sizeof (struct interface));
+
+      zebra_interface_if_set_value (zclient->ibuf, ifp);
+
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+       zlog_info ("Zebra: Interface[%s] state update.", ifp->name);
+
+      if (if_tmp.bandwidth != ifp->bandwidth)
+       {
+         if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+           zlog_info ("Zebra: Interface[%s] bandwidth change %d -> %d.",
+                      ifp->name, if_tmp.bandwidth, ifp->bandwidth);
+
+         ospf_if_recalculate_output_cost (ifp);
+       }
+      return 0;
+    }
+  
+  zebra_interface_if_set_value (zclient->ibuf, ifp);
+  
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    zlog_info ("Zebra: Interface[%s] state change to up.", ifp->name);
+  
+  for (rn = route_top (IF_OIFS (ifp));rn; rn = route_next (rn))
+    {
+      if ( (oi = rn->info) == NULL)
+       continue;
+      
+      ospf_if_up (oi);
+    }
+  
+  return 0;
+}
+
+int
+ospf_interface_state_down (int command, struct zclient *zclient,
+                          zebra_size_t length)
+{
+  struct interface *ifp;
+  struct ospf_interface *oi;
+  struct route_node *node;
+
+  ifp = zebra_interface_state_read (zclient->ibuf);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    zlog_info ("Zebra: Interface[%s] state change to down.", ifp->name);
+
+  for (node = route_top (IF_OIFS (ifp));node; node = route_next (node))
+    {
+      if ( (oi = node->info) == NULL)
+       continue;
+      ospf_if_down (oi);
+    }
+
+  return 0;
+}
+
+int
+ospf_interface_address_add (int command, struct zclient *zclient,
+                           zebra_size_t length)
+{
+  struct connected *c;
+
+  c = zebra_interface_address_add_read (zclient->ibuf);
+
+  if (c == NULL)
+    return 0;
+
+#if 0
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    {
+      struct prefix *p;
+
+      p = c->address;
+      if (p->family == AF_INET)
+       zlog_info (" connected address %s/%d", 
+                  inet_atop (p->u.prefix4), p->prefixlen);
+    }
+#endif
+
+  ospf_if_update ();
+
+#ifdef HAVE_SNMP
+  ospf_snmp_if_update (c->ifp);
+#endif /* HAVE_SNMP */
+
+  return 0;
+}
+
+int
+ospf_interface_address_delete (int command, struct zclient *zclient,
+                              zebra_size_t length)
+{
+  struct connected *c;
+  struct interface *ifp;
+  struct ospf_interface *oi;
+  struct route_node *rn;
+  struct prefix p;
+
+  c = zebra_interface_address_delete_read (zclient->ibuf);
+
+  if (c == NULL)
+    return 0;
+
+  ifp = c->ifp;
+  p = *c->address;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+  rn = route_node_lookup (IF_OIFS (ifp), &p);
+  if (! rn)
+    return 0;
+
+  assert (rn->info);
+  oi = rn->info;
+  
+  /* Call interface hook functions to clean up */
+  ospf_if_free (oi);
+  
+#ifdef HAVE_SNMP
+  ospf_snmp_if_update (c->ifp);
+#endif /* HAVE_SNMP */
+
+  connected_free (c);
+
+  ospf_if_update();
+
+  return 0;
+}
+\f
+void
+ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
+{
+  u_char message;
+  u_char distance;
+  u_char flags;
+  int psize;
+  struct stream *s;
+  struct ospf_path *path;
+  listnode node;
+
+  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+    {
+      message = 0;
+      flags = 0;
+
+      /* OSPF pass nexthop and metric */
+      SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
+      SET_FLAG (message, ZAPI_MESSAGE_METRIC);
+
+      /* Distance value. */
+      distance = ospf_distance_apply (p, or);
+      if (distance)
+       SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
+
+      /* Make packet. */
+      s = zclient->obuf;
+      stream_reset (s);
+
+      /* Length place holder. */
+      stream_putw (s, 0);
+
+      /* Put command, type, flags, message. */
+      stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+      stream_putc (s, ZEBRA_ROUTE_OSPF);
+      stream_putc (s, flags);
+      stream_putc (s, message);
+  
+      /* Put prefix information. */
+      psize = PSIZE (p->prefixlen);
+      stream_putc (s, p->prefixlen);
+      stream_write (s, (u_char *)&p->prefix, psize);
+
+      /* Nexthop count. */
+      stream_putc (s, or->path->count);
+
+      /* Nexthop, ifindex, distance and metric information. */
+      for (node = listhead (or->path); node; nextnode (node))
+       {
+         path = getdata (node);
+
+         if (path->nexthop.s_addr != INADDR_ANY)
+           {
+             stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+             stream_put_in_addr (s, &path->nexthop);
+           }
+         else
+           {
+             stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+             if (path->oi)
+               stream_putl (s, path->oi->ifp->ifindex);
+             else
+               stream_putl (s, 0);
+           }
+       }
+
+      if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+       stream_putc (s, distance);
+      if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+       {
+         if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
+           stream_putl (s, or->cost + or->u.ext.type2_cost);
+         else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
+           stream_putl (s, or->u.ext.type2_cost);
+         else
+           stream_putl (s, or->cost);
+       }
+
+      stream_putw_at (s, 0, stream_get_endp (s));
+
+      writen (zclient->sock, s->data, stream_get_endp (s));
+
+#if 0
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+       {
+         char *nexthop_str;
+
+         nexthop_str = strdup (inet_ntoa (*nexthop));
+         zlog_info ("Zebra: Route add %s/%d nexthop %s metric %d",
+                    inet_ntoa (p->prefix), p->prefixlen, nexthop_str,
+                    metric);
+         free (nexthop_str);
+       }
+#endif /* 0 */
+    }
+}
+
+void
+ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+    {
+      api.type = ZEBRA_ROUTE_OSPF;
+      api.flags = 0;
+      api.message = 0;
+      zapi_ipv4_delete (zclient, p, &api);
+
+#if 0
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+       {
+         char *nexthop_str;
+
+         nexthop_str = strdup (inet_ntoa (*nexthop));
+         zlog_info ("Zebra: Route delete %s/%d nexthop %s",
+                    inet_ntoa (p->prefix), p->prefixlen, nexthop_str);
+         free (nexthop_str);
+       }
+#endif /* 0 */
+    }
+}
+
+void
+ospf_zebra_add_discard (struct prefix_ipv4 *p)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+    {
+      api.type = ZEBRA_ROUTE_OSPF;
+      api.flags = ZEBRA_FLAG_BLACKHOLE;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 0;
+      api.ifindex_num = 0;
+
+      zapi_ipv4_add (zclient, p, &api);
+    }
+}
+
+void
+ospf_zebra_delete_discard (struct prefix_ipv4 *p)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+    {
+      api.type = ZEBRA_ROUTE_OSPF;
+      api.flags = ZEBRA_FLAG_BLACKHOLE;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 0;
+      api.ifindex_num = 0;
+
+      zapi_ipv4_delete (zclient, p, &api);
+    }
+}
+
+int
+ospf_is_type_redistributed (int type)
+{
+  return (DEFAULT_ROUTE_TYPE (type)) ?
+    zclient->default_information : zclient->redist[type];
+}
+
+int
+ospf_redistribute_set (int type, int mtype, int mvalue)
+{
+  int force = 0;
+  
+  if (ospf_is_type_redistributed (type))
+    {
+      if (mtype != ospf_top->dmetric[type].type)
+       {
+         ospf_top->dmetric[type].type = mtype;
+         force = LSA_REFRESH_FORCE;
+       }
+      if (mvalue != ospf_top->dmetric[type].value)
+       {
+         ospf_top->dmetric[type].value = mvalue;
+         force = LSA_REFRESH_FORCE;
+       }
+         
+      ospf_external_lsa_refresh_type (type, force);
+      
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+       zlog_info ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
+                  LOOKUP (ospf_redistributed_proto, type),
+                  metric_type (type), metric_value (type));
+      
+      return CMD_SUCCESS;
+    }
+
+  ospf_top->dmetric[type].type = mtype;
+  ospf_top->dmetric[type].value = mvalue;
+
+  zclient_redistribute_set (zclient, type);
+
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+    zlog_info ("Redistribute[%s]: Start  Type[%d], Metric[%d]",
+              LOOKUP (ospf_redistributed_proto, type),
+              metric_type (type), metric_value (type));
+  
+  ospf_asbr_status_update (++ospf_top->redistribute);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_redistribute_unset (int type)
+{
+  if (type == zclient->redist_default)
+    return CMD_SUCCESS;
+
+  if (! ospf_is_type_redistributed (type))
+    return CMD_SUCCESS;
+
+  zclient_redistribute_unset (zclient, type);
+  
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+    zlog_info ("Redistribute[%s]: Stop",
+              LOOKUP (ospf_redistributed_proto, type));
+
+  ospf_top->dmetric[type].type = -1;
+  ospf_top->dmetric[type].value = -1;
+
+  /* Remove the routes from OSPF table. */
+  ospf_redistribute_withdraw (type);
+
+  ospf_asbr_status_update (--ospf_top->redistribute);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_redistribute_default_set (int originate, int mtype, int mvalue)
+{
+  int force = 0;
+  if (ospf_is_type_redistributed (DEFAULT_ROUTE))
+    {
+      if (mtype != ospf_top->dmetric[DEFAULT_ROUTE].type)
+       {
+         ospf_top->dmetric[DEFAULT_ROUTE].type = mtype;
+         force = 1;
+       }
+      if (mvalue != ospf_top->dmetric[DEFAULT_ROUTE].value)
+       {
+         force = 1;
+         ospf_top->dmetric[DEFAULT_ROUTE].value = mvalue;
+       }
+      
+      ospf_external_lsa_refresh_default ();
+      
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+       zlog_info ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
+                  LOOKUP (ospf_redistributed_proto, DEFAULT_ROUTE),
+                  metric_type (DEFAULT_ROUTE),
+                  metric_value (DEFAULT_ROUTE));
+      return CMD_SUCCESS;
+    }
+
+  ospf_top->default_originate = originate;
+  ospf_top->dmetric[DEFAULT_ROUTE].type = mtype;
+  ospf_top->dmetric[DEFAULT_ROUTE].value = mvalue;
+
+  zclient_redistribute_default_set (zclient);
+  
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+    zlog_info ("Redistribute[DEFAULT]: Start  Type[%d], Metric[%d]",
+              metric_type (DEFAULT_ROUTE), metric_value (DEFAULT_ROUTE));
+
+
+  if (ospf_top->router_id.s_addr == 0)
+    ospf_top->external_origin |= (1 << DEFAULT_ROUTE);
+  else
+    thread_add_timer (master, ospf_default_originate_timer,
+                     &ospf_top->default_originate, 1);
+
+  ospf_asbr_status_update (++ospf_top->redistribute);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_redistribute_default_unset ()
+{
+  if (!ospf_is_type_redistributed (DEFAULT_ROUTE))
+    return CMD_SUCCESS;
+
+  ospf_top->default_originate = DEFAULT_ORIGINATE_NONE;
+  ospf_top->dmetric[DEFAULT_ROUTE].type = -1;
+  ospf_top->dmetric[DEFAULT_ROUTE].value = -1;
+
+  zclient_redistribute_default_unset (zclient);
+
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+    zlog_info ("Redistribute[DEFAULT]: Stop");
+  
+  ospf_asbr_status_update (--ospf_top->redistribute);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_external_lsa_originate_check (struct external_info *ei)
+{
+  /* If prefix is multicast, then do not originate LSA. */
+  if (IN_MULTICAST (htonl (ei->p.prefix.s_addr)))
+    {
+      zlog_info ("LSA[Type5:%s]: Not originate AS-external-LSA, "
+                "Prefix belongs multicast", inet_ntoa (ei->p.prefix));
+      return 0;
+    }
+
+  /* Take care of default-originate. */
+  if (is_prefix_default (&ei->p))
+    if (ospf_top->default_originate == DEFAULT_ORIGINATE_NONE)
+      {
+       zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-exntenal-LSA "
+                  "for default");
+       return 0;
+      }
+
+  return 1;
+}
+
+/* If connected prefix is OSPF enable interface, then do not announce. */
+int
+ospf_distribute_check_connected (struct external_info *ei)
+{
+  struct route_node *rn;
+
+  for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn))
+    if (rn->info != NULL)
+      if (prefix_match (&rn->p, (struct prefix *)&ei->p))
+       return 0;
+
+  return 1;
+}
+
+/* return 1 if external LSA must be originated, 0 otherwise */
+int
+ospf_redistribute_check (struct external_info *ei, int *changed)
+{
+  struct route_map_set_values save_values;
+  struct prefix_ipv4 *p = &ei->p;
+  u_char type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
+  
+  if (changed)
+    *changed = 0;
+
+  if (!ospf_external_lsa_originate_check (ei))
+    return 0;
+
+  /* Take care connected route. */
+  if (type == ZEBRA_ROUTE_CONNECT && !ospf_distribute_check_connected (ei))
+    return 0;
+
+  if (!DEFAULT_ROUTE_TYPE (type) && DISTRIBUTE_NAME (type))
+    /* distirbute-list exists, but access-list may not? */
+    if (DISTRIBUTE_LIST (type))
+      if (access_list_apply (DISTRIBUTE_LIST (type), p) == FILTER_DENY)
+       {
+         if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+           zlog_info ("Redistribute[%s]: %s/%d filtered by ditribute-list.",
+                      LOOKUP (ospf_redistributed_proto, type),
+                      inet_ntoa (p->prefix), p->prefixlen);
+         return 0;
+       }
+
+  save_values = ei->route_map_set;
+  ospf_reset_route_map_set_values (&ei->route_map_set);
+  
+  /* apply route-map if needed */
+  if (ROUTEMAP_NAME (type))
+    {
+      int ret;
+
+      ret = route_map_apply (ROUTEMAP (type), (struct prefix *)p,
+                            RMAP_OSPF, ei);
+
+      if (ret == RMAP_DENYMATCH)
+       {
+         ei->route_map_set = save_values;
+         if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+           zlog_info ("Redistribute[%s]: %s/%d filtered by route-map.",
+                      LOOKUP (ospf_redistributed_proto, type),
+                      inet_ntoa (p->prefix), p->prefixlen);
+         return 0;
+       }
+      
+      /* check if 'route-map set' changed something */
+      if (changed)
+       *changed = !ospf_route_map_set_compare (&ei->route_map_set,
+                                               &save_values);
+    }
+
+  return 1;
+}
+
+/* OSPF route-map set for redistribution */
+void
+ospf_routemap_set (int type, char *name)
+{
+  if (ROUTEMAP_NAME (type))
+    free (ROUTEMAP_NAME (type));
+
+  ROUTEMAP_NAME (type) = strdup (name);
+  ROUTEMAP (type) = route_map_lookup_by_name (name);
+}
+
+void
+ospf_routemap_unset (int type)
+{
+  if (ROUTEMAP_NAME (type))
+    free (ROUTEMAP_NAME (type));
+
+  ROUTEMAP_NAME (type) = NULL;
+  ROUTEMAP (type) = NULL;
+}
+
+/* Zebra route add and delete treatment. */
+int
+ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
+                     zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv4 api;
+  unsigned long ifindex;
+  struct in_addr nexthop;
+  struct prefix_ipv4 p;
+  struct external_info *ei;
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop.s_addr = 0;
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop.s_addr = stream_get_ipv4 (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+
+  if (command == ZEBRA_IPV4_ROUTE_ADD)
+    {
+      ei = ospf_external_info_add (api.type, p, ifindex, nexthop);
+
+      if (ospf_top->router_id.s_addr == 0)
+       /* Set flags to generate AS-external-LSA originate event
+          for each redistributed protocols later. */
+       ospf_top->external_origin |= (1 << api.type);
+      else
+       {
+         if (ei)
+           {
+             if (is_prefix_default (&p))
+               ospf_external_lsa_refresh_default ();
+             else
+               {
+                 struct ospf_lsa *current;
+
+                 current = ospf_external_info_find_lsa (&ei->p);
+                 if (!current)
+                   ospf_external_lsa_originate (ei);
+                 else if (IS_LSA_MAXAGE (current))
+                   ospf_external_lsa_refresh (current, ei, LSA_REFRESH_FORCE);
+                 else
+                   zlog_warn ("ospf_zebra_read_ipv4() : %s already exists",
+                              inet_ntoa (p.prefix));
+               }
+           }
+       }
+    }
+  else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
+    {
+      ospf_external_info_delete (api.type, p);
+      if ( !is_prefix_default (&p))
+       ospf_external_lsa_flush (api.type, &p, ifindex, nexthop);
+      else
+       ospf_external_lsa_refresh_default ();
+    }
+
+  return 0;
+}
+
+\f
+int
+ospf_distribute_list_out_set (int type, char *name)
+{
+  /* Lookup access-list for distribute-list. */
+  DISTRIBUTE_LIST (type) = access_list_lookup (AFI_IP, name);
+
+  /* Clear previous distribute-name. */
+  if (DISTRIBUTE_NAME (type))
+    free (DISTRIBUTE_NAME (type));
+
+  /* Set distribute-name. */
+  DISTRIBUTE_NAME (type) = strdup (name);
+
+  /* If access-list have been set, schedule update timer. */
+  if (DISTRIBUTE_LIST (type))
+    ospf_distribute_list_update (type);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_distribute_list_out_unset (int type, char *name)
+{
+  /* Schedule update timer. */
+  if (DISTRIBUTE_LIST (type))
+    ospf_distribute_list_update (type);
+
+  /* Unset distribute-list. */
+  DISTRIBUTE_LIST (type) = NULL;
+
+  /* Clear distribute-name. */
+  if (DISTRIBUTE_NAME (type))
+    free (DISTRIBUTE_NAME (type));
+  
+  DISTRIBUTE_NAME (type) = NULL;
+
+  return CMD_SUCCESS;
+}
+
+/* distribute-list update timer. */
+int
+ospf_distribute_list_update_timer (struct thread *thread)
+{
+  struct route_node *rn;
+  struct external_info *ei;
+  struct route_table *rt;
+  struct ospf_lsa *lsa;
+  u_char type;
+
+  type = (int) THREAD_ARG (thread);
+  rt = EXTERNAL_INFO (type);
+
+  ospf_top->t_distribute_update = NULL;
+
+  zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!");
+
+  /* foreach all external info. */
+  if (rt)
+    for (rn = route_top (rt); rn; rn = route_next (rn))
+      if ((ei = rn->info) != NULL)
+       {
+         if (is_prefix_default (&ei->p))
+           ospf_external_lsa_refresh_default ();
+         else if ((lsa = ospf_external_info_find_lsa (&ei->p)))
+           ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_IF_CHANGED);
+         else
+           ospf_external_lsa_originate (ei);
+       }
+  return 0;
+}
+
+#define OSPF_DISTRIBUTE_UPDATE_DELAY 5
+
+/* Update distribute-list and set timer to apply access-list. */
+void
+ospf_distribute_list_update (int type)
+{
+  struct route_table *rt;
+  
+  zlog_info ("ospf_distribute_list_update(): start");
+
+  /* External info does not exist. */
+  if (!(rt = EXTERNAL_INFO (type)))
+    return;
+
+  /* If exists previously invoked thread, then cancel it. */
+  if (ospf_top->t_distribute_update)
+    OSPF_TIMER_OFF (ospf_top->t_distribute_update);
+
+  /* Set timer. */
+  ospf_top->t_distribute_update =
+    thread_add_timer (master, ospf_distribute_list_update_timer,
+                     (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY);
+
+  zlog_info ("ospf_distribute_list_update(): stop");
+}
+
+/* If access-list is updated, apply some check. */
+void
+ospf_filter_update (struct access_list *access)
+{
+  int type;
+  int abr_inv = 0;
+  struct ospf_area *area;
+  listnode node;
+
+  /* If OSPF instatnce does not exist, return right now. */
+  if (!ospf_top)
+    return;
+
+
+  /* Update distribute-list, and apply filter. */
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+    {
+      if (ROUTEMAP (type) != NULL)
+       {
+         /* if route-map is not NULL it may be using this access list */
+         ospf_distribute_list_update (type);
+         continue;
+       }
+      
+
+      if (DISTRIBUTE_NAME (type))
+       {
+         /* Keep old access-list for distribute-list. */
+         struct access_list *old = DISTRIBUTE_LIST (type);
+         
+         /* Update access-list for distribute-list. */
+         DISTRIBUTE_LIST (type) =
+           access_list_lookup (AFI_IP, DISTRIBUTE_NAME (type));
+         
+         /* No update for this distribute type. */
+         if (old == NULL && DISTRIBUTE_LIST (type) == NULL)
+           continue;
+         
+         /* Schedule distribute-list update timer. */
+         if (DISTRIBUTE_LIST (type) == NULL ||
+             strcmp (DISTRIBUTE_NAME (type), access->name) == 0)
+           ospf_distribute_list_update (type);
+       }
+    }
+
+  /* Update Area access-list. */
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    if ((area = getdata (node)) != NULL)
+      {
+       if (EXPORT_NAME (area))
+         {
+           EXPORT_LIST (area) = NULL;
+           abr_inv++;
+         }
+
+       if (IMPORT_NAME (area))
+         {
+           IMPORT_LIST (area) = NULL;
+           abr_inv++;
+         }
+      }
+
+  /* Schedule ABR tasks -- this will be changed -- takada. */
+  if (OSPF_IS_ABR && abr_inv)
+    ospf_schedule_abr_task ();
+}
+
+\f
+struct ospf_distance *
+ospf_distance_new ()
+{
+  struct ospf_distance *new;
+  new = XMALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance));
+  memset (new, 0, sizeof (struct ospf_distance));
+  return new;
+}
+
+void
+ospf_distance_free (struct ospf_distance *odistance)
+{
+  XFREE (MTYPE_OSPF_DISTANCE, odistance);
+}
+
+int
+ospf_distance_set (struct vty *vty, char *distance_str, char *ip_str,
+                  char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct route_node *rn;
+  struct ospf_distance *odistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  /* Get OSPF distance node. */
+  rn = route_node_get (ospf_top->distance_table, (struct prefix *) &p);
+  if (rn->info)
+    {
+      odistance = rn->info;
+      route_unlock_node (rn);
+    }
+  else
+    {
+      odistance = ospf_distance_new ();
+      rn->info = odistance;
+    }
+
+  /* Set distance value. */
+  odistance->distance = distance;
+
+  /* Reset access-list configuration. */
+  if (odistance->access_list)
+    {
+      free (odistance->access_list);
+      odistance->access_list = NULL;
+    }
+  if (access_list_str)
+    odistance->access_list = strdup (access_list_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf_distance_unset (struct vty *vty, char *distance_str, char *ip_str,
+                    char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct route_node *rn;
+  struct ospf_distance *odistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  rn = route_node_lookup (ospf_top->distance_table, (struct prefix *)&p);
+  if (! rn)
+    {
+      vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  odistance = rn->info;
+
+  if (odistance->access_list)
+    free (odistance->access_list);
+  ospf_distance_free (odistance);
+
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf_distance_reset ()
+{
+  struct route_node *rn;
+  struct ospf_distance *odistance;
+
+  for (rn = route_top (ospf_top->distance_table); rn; rn = route_next (rn))
+    if ((odistance = rn->info) != NULL)
+      {
+       if (odistance->access_list)
+         free (odistance->access_list);
+       ospf_distance_free (odistance);
+       rn->info = NULL;
+       route_unlock_node (rn);
+      }
+}
+
+u_char
+ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or)
+{
+#if 0
+  struct route_node *rn;
+  struct ospf_distance *odistance;
+  struct access_list *alist;
+  struct prefix_ipv4 q;
+
+  memset (&q, 0, sizeof (struct prefix_ipv4));
+  q.family = AF_INET;
+  /* q.prefix =  */
+  q.prefixlen = IPV4_MAX_BITLEN;
+#endif /* 0 */
+
+  if (! ospf_top)
+    return 0;
+
+#if 0
+  rn = route_node_match (ospf_top->distance_table, (struct prefix *) &q);
+  if (rn)
+    {
+      odistance = rn->info;
+      route_unlock_node (rn);
+
+      if (odistance->access_list)
+       {
+         alist = access_list_lookup (AFI_IP, odistance->access_list);
+         if (alist == NULL)
+           return 0;
+         if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY)
+           return 0;
+
+         return odistance->distance;
+       }
+      else
+       return odistance->distance;
+    }
+#endif /* 0 */
+
+  if (ospf_top->distance_intra)
+    if (or->path_type == OSPF_PATH_INTRA_AREA)
+      return ospf_top->distance_intra;
+
+  if (ospf_top->distance_inter)
+    if (or->path_type == OSPF_PATH_INTER_AREA)
+      return ospf_top->distance_inter;
+
+  if (ospf_top->distance_external)
+    if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL
+       || or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
+      return ospf_top->distance_external;
+  
+  if (ospf_top->distance_all)
+    return ospf_top->distance_all;
+
+  return 0;
+}
+
+void
+ospf_zebra_init ()
+{
+  /* Allocate zebra structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_OSPF);
+  zclient->interface_add = ospf_interface_add;
+  zclient->interface_delete = ospf_interface_delete;
+  zclient->interface_up = ospf_interface_state_up;
+  zclient->interface_down = ospf_interface_state_down;
+  zclient->interface_address_add = ospf_interface_address_add;
+  zclient->interface_address_delete = ospf_interface_address_delete;
+  zclient->ipv4_route_add = ospf_zebra_read_ipv4;
+  zclient->ipv4_route_delete = ospf_zebra_read_ipv4;
+
+  access_list_add_hook (ospf_filter_update);
+  access_list_delete_hook (ospf_filter_update);
+}
diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h
new file mode 100644 (file)
index 0000000..5dbf573
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Zebra connect library for OSPFd
+ * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#ifndef _ZEBRA_OSPF_ZEBRA_H
+#define _ZEBRA_OSPF_ZEBRA_H
+
+#define EXTERNAL_METRIC_TYPE_1      0
+#define EXTERNAL_METRIC_TYPE_2      1
+
+#define DEFAULT_ROUTE              ZEBRA_ROUTE_MAX
+#define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE)
+
+/* OSPF distance. */
+struct ospf_distance
+{
+  /* Distance value for the IP source prefix. */
+  u_char distance;
+
+  /* Name of the access-list to be matched. */
+  char *access_list;
+};
+
+/* Prototypes */
+void ospf_zclient_start ();
+
+void ospf_zebra_add (struct prefix_ipv4 *, struct ospf_route *);
+void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *);
+
+void ospf_zebra_add_discard (struct prefix_ipv4 *);
+void ospf_zebra_delete_discard (struct prefix_ipv4 *);
+
+int ospf_default_originate_timer (struct thread *);
+
+int ospf_redistribute_check (struct external_info *, int *);
+int ospf_distribute_check_connected (struct external_info *);
+void ospf_distribute_list_update (int);
+
+int ospf_is_type_redistributed (int);
+int ospf_redistribute_unset (int);
+
+void ospf_distance_reset ();
+u_char ospf_distance_apply (struct prefix_ipv4 *, struct ospf_route *);
+
+struct vty;
+
+int ospf_redistribute_set (int, int, int);
+int ospf_redistribute_unset (int);
+int ospf_redistribute_default_set (int, int, int);
+int ospf_redistribute_default_unset ();
+int ospf_distribute_list_out_set (int, char *);
+int ospf_distribute_list_out_unset (int, char *);
+void ospf_routemap_set (int, char *);
+void ospf_routemap_unset (int);
+int ospf_distance_set (struct vty *, char *, char *, char *);
+int ospf_distance_unset (struct vty *, char *, char *, char *);
+void ospf_zebra_init ();
+
+#endif /* _ZEBRA_OSPF_ZEBRA_H */
+
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
new file mode 100644 (file)
index 0000000..e7de8ea
--- /dev/null
@@ -0,0 +1,1603 @@
+/* OSPF version 2 daemon program.
+   Copyright (C) 1999, 2000 Toshiaki Takada
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "vty.h"
+#include "command.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "if.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "sockunion.h"          /* for inet_aton () */
+#include "zclient.h"
+#include "plist.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+
+/* OSPF instance top. */
+struct ospf *ospf_top;
+
+extern struct zclient *zclient;
+
+\f
+void ospf_remove_vls_through_area (struct ospf_area *);
+void ospf_network_free (struct ospf_network *);
+void ospf_area_free (struct ospf_area *);
+void ospf_network_run (struct ospf *, struct prefix *, struct ospf_area *);
+
+/* Get Router ID from ospf interface list. */
+struct in_addr
+ospf_router_id_get (list if_list)
+{
+  listnode node;
+  struct in_addr router_id;
+
+  memset (&router_id, 0, sizeof (struct in_addr));
+
+  for (node = listhead (if_list); node; nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+
+      if (!if_is_up (oi->ifp) ||
+         OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+       continue;
+      
+      /* Ignore virtual link interface. */
+      if (oi->type != OSPF_IFTYPE_VIRTUALLINK &&
+         oi->type != OSPF_IFTYPE_LOOPBACK) 
+       if (IPV4_ADDR_CMP (&router_id, &oi->address->u.prefix4) < 0)
+         router_id = oi->address->u.prefix4;
+    }
+
+  return router_id;
+}
+
+#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1
+
+void
+ospf_router_id_update ()
+{
+  listnode node;
+  struct in_addr router_id, router_id_old;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Router-ID[OLD:%s]: Update",inet_ntoa (ospf_top->router_id));
+
+  router_id_old = ospf_top->router_id;
+
+  if (ospf_top->router_id_static.s_addr != 0)
+    router_id = ospf_top->router_id_static;
+  else
+    router_id = ospf_router_id_get (ospf_top->oiflist);
+
+  ospf_top->router_id = router_id;
+  
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Router-ID[NEW:%s]: Update", inet_ntoa (ospf_top->router_id));
+
+  if (!IPV4_ADDR_SAME (&router_id_old, &router_id))
+    {
+      for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+        {
+         struct ospf_interface *oi = getdata (node);
+
+          /* Update self-neighbor's router_id. */
+          oi->nbr_self->router_id = router_id;
+        }
+
+      /* If AS-external-LSA is queued, then flush those LSAs. */
+      if (router_id_old.s_addr == 0 && ospf_top->external_origin)
+       {
+         int type;
+         /* Originate each redistributed external route. */
+         for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+           if (ospf_top->external_origin & (1 << type))
+             thread_add_event (master, ospf_external_lsa_originate_timer,
+                               NULL, type);
+         /* Originate Deafult. */
+         if (ospf_top->external_origin & (1 << ZEBRA_ROUTE_MAX))
+           thread_add_event (master, ospf_default_originate_timer,
+                             &ospf_top->default_originate, 0);
+
+         ospf_top->external_origin = 0;
+       }
+
+      OSPF_TIMER_ON (ospf_top->t_router_lsa_update,
+                    ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
+    }
+}
+
+int
+ospf_router_id_update_timer (struct thread *thread)
+{
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Router-ID: Update timer fired!");
+
+  ospf_top->t_router_id_update = NULL;
+  ospf_router_id_update ();
+
+  return 0;
+}
+\f
+/* For OSPF area sort by area id. */
+int
+ospf_area_id_cmp (struct ospf_area *a1, struct ospf_area *a2)
+{
+  if (ntohl (a1->area_id.s_addr) > ntohl (a2->area_id.s_addr))
+    return 1;
+  if (ntohl (a1->area_id.s_addr) < ntohl (a2->area_id.s_addr))
+    return -1;
+  return 0;
+}
+
+/* Allocate new ospf structure. */
+struct ospf *
+ospf_new ()
+{
+  int i;
+
+  struct ospf *new = XCALLOC (MTYPE_OSPF_TOP, sizeof (struct ospf));
+
+  new->router_id.s_addr = htonl (0);
+  new->router_id_static.s_addr = htonl (0);
+
+  new->abr_type = OSPF_ABR_STAND;
+  new->iflist = iflist;
+  new->oiflist = list_new ();
+  new->vlinks = list_new ();
+  new->areas = list_new ();
+  new->areas->cmp = (int (*)(void *, void *)) ospf_area_id_cmp;
+  new->networks = route_table_init ();
+  new->nbr_nbma = route_table_init ();
+
+  new->lsdb = ospf_lsdb_new ();
+
+  new->default_originate = DEFAULT_ORIGINATE_NONE;
+
+  new->new_external_route = route_table_init ();
+  new->old_external_route = route_table_init ();
+  new->external_lsas = route_table_init ();
+
+  /* Distribute parameter init. */
+  for (i = 0; i <= ZEBRA_ROUTE_MAX; i++)
+    {
+      new->dmetric[i].type = -1;
+      new->dmetric[i].value = -1;
+    }
+  new->default_metric = -1;
+  new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH;
+
+  /* SPF timer value init. */
+  new->spf_delay = OSPF_SPF_DELAY_DEFAULT;
+  new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT;
+
+  /* MaxAge init. */
+  new->maxage_lsa = list_new ();
+  new->t_maxage_walker =
+    thread_add_timer (master, ospf_lsa_maxage_walker,
+                      NULL, OSPF_LSA_MAXAGE_CHECK_INTERVAL);
+
+  /* Distance table init. */
+  new->distance_table = route_table_init ();
+
+  new->lsa_refresh_queue.index = 0;
+  new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT;
+  new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
+                                          new, new->lsa_refresh_interval);
+  new->lsa_refresher_started = time (NULL);
+
+  new->fd = ospf_sock_init ();
+  if (new->fd >= 0)
+    new->t_read = thread_add_read (master, ospf_read, new, new->fd);
+  new->oi_write_q = list_new ();
+  
+  return new;
+}
+
+struct ospf *
+ospf_get ()
+{
+  if (ospf_top != NULL)
+    return ospf_top;
+
+  ospf_top = ospf_new ();
+
+  if (ospf_top->router_id_static.s_addr == 0)
+    ospf_router_id_update ();
+
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_type11_lsa_init (ospf_top);
+#endif /* HAVE_OPAQUE_LSA */
+
+  return ospf_top;
+}
+
+void
+ospf_finish (struct ospf *ospf)
+{
+  struct route_node *rn;
+  struct ospf_nbr_nbma *nbr_nbma;
+  listnode node;
+  int i;
+
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_type11_lsa_term (ospf);
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Unredister redistribution */
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    ospf_redistribute_unset (i);
+
+  for (node = listhead (ospf->areas); node;)
+    {
+      struct ospf_area *area = getdata (node);
+      nextnode (node);
+      
+      ospf_remove_vls_through_area (area);
+    }
+  
+  for (node = listhead (ospf->vlinks); node; )
+    {
+      struct ospf_vl_data *vl_data = node->data;
+      nextnode (node);
+      
+      ospf_vl_delete (vl_data);
+    }
+  
+  list_delete (ospf->vlinks);
+
+  /* Reset interface. */
+  for (node = listhead (ospf->oiflist); node;)
+    {
+      struct ospf_interface *oi = getdata (node);
+      nextnode (node);
+      
+      if (oi)
+       ospf_if_free (oi);
+    }
+
+  /* Clear static neighbors */
+  for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn))
+    if ((nbr_nbma = rn->info))
+      {
+       OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll);
+
+       if (nbr_nbma->nbr)
+         {
+           nbr_nbma->nbr->nbr_nbma = NULL;
+           nbr_nbma->nbr = NULL;
+         }
+
+       if (nbr_nbma->oi)
+         {
+           listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma);
+           nbr_nbma->oi = NULL;
+         }
+
+       XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma);
+      }
+
+  route_table_finish (ospf->nbr_nbma);
+
+  /* Clear networks and Areas. */
+  for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
+    {
+      struct ospf_network *network;
+
+      if ((network = rn->info) != NULL)
+       {
+         ospf_network_free (network);
+         rn->info = NULL;
+         route_unlock_node (rn);
+       }
+    }
+
+  for (node = listhead (ospf->areas); node;)
+    {
+      struct ospf_area *area = getdata (node);
+      nextnode (node);
+      
+      listnode_delete (ospf->areas, area);
+      ospf_area_free (area);
+    }
+
+  /* Cancel all timers. */
+  OSPF_TIMER_OFF (ospf->t_external_lsa);
+  OSPF_TIMER_OFF (ospf->t_router_id_update);
+  OSPF_TIMER_OFF (ospf->t_router_lsa_update);
+  OSPF_TIMER_OFF (ospf->t_spf_calc);
+  OSPF_TIMER_OFF (ospf->t_ase_calc);
+  OSPF_TIMER_OFF (ospf->t_maxage);
+  OSPF_TIMER_OFF (ospf->t_maxage_walker);
+  OSPF_TIMER_OFF (ospf->t_abr_task);
+  OSPF_TIMER_OFF (ospf->t_distribute_update);
+  OSPF_TIMER_OFF (ospf->t_lsa_refresher);
+  OSPF_TIMER_OFF (ospf->t_read);
+  OSPF_TIMER_OFF (ospf->t_write);
+
+  close (ospf->fd);
+   
+#ifdef HAVE_OPAQUE_LSA
+  foreach_lsa (OPAQUE_AS_LSDB (ospf), ospf_top->lsdb, 0,
+              ospf_lsa_discard_callback);
+#endif /* HAVE_OPAQUE_LSA */
+  foreach_lsa (EXTERNAL_LSDB (ospf), ospf->lsdb, 0,
+              ospf_lsa_discard_callback);
+  ospf_lsdb_delete_all (ospf->lsdb);
+  ospf_lsdb_free (ospf->lsdb);
+
+  for (node = listhead (ospf->maxage_lsa); node; nextnode (node))
+    ospf_lsa_unlock (getdata (node));
+
+  list_delete (ospf->maxage_lsa);
+
+  if (ospf->old_table)
+    ospf_route_table_free (ospf->old_table);
+  if (ospf->new_table)
+    {
+      ospf_route_delete (ospf->new_table);
+      ospf_route_table_free (ospf->new_table);
+    }
+  if (ospf->old_rtrs)
+    ospf_rtrs_free (ospf->old_rtrs);
+  if (ospf->new_rtrs)
+    ospf_rtrs_free (ospf->new_rtrs);
+  if (ospf->new_external_route)
+    {
+      ospf_route_delete (ospf->new_external_route);
+      ospf_route_table_free (ospf->new_external_route);
+    }
+  if (ospf->old_external_route)
+    {
+      ospf_route_delete (ospf->old_external_route);
+      ospf_route_table_free (ospf->old_external_route);
+    }
+  if (ospf->external_lsas)
+    {
+      ospf_ase_external_lsas_finish (ospf->external_lsas);
+    }
+
+  list_delete (ospf->areas);
+  
+  for (i = ZEBRA_ROUTE_SYSTEM; i <= ZEBRA_ROUTE_MAX; i++)
+    if (EXTERNAL_INFO (i) != NULL)
+      for (rn = route_top (EXTERNAL_INFO (i)); rn; rn = route_next (rn))
+       {
+         if (rn->info == NULL)
+           continue;
+         
+         XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info);
+         rn->info = NULL;
+         route_unlock_node (rn);
+       }
+
+  ospf_distance_reset ();
+  route_table_finish (ospf->distance_table);
+
+  XFREE (MTYPE_OSPF_TOP, ospf);
+
+  ospf_top = NULL;
+}
+
+\f
+/* allocate new OSPF Area object */
+struct ospf_area *
+ospf_area_new (struct in_addr area_id)
+{
+  struct ospf_area *new;
+
+  /* Allocate new config_network. */
+  new = XCALLOC (MTYPE_OSPF_AREA, sizeof (struct ospf_area));
+
+  new->top = ospf_top;
+
+  new->area_id = area_id;
+
+  new->external_routing = OSPF_AREA_DEFAULT;
+  new->default_cost = 1;
+  new->auth_type = OSPF_AUTH_NULL;
+
+  /* New LSDB init. */
+  new->lsdb = ospf_lsdb_new ();
+
+  /* Self-originated LSAs initialize. */
+  new->router_lsa_self = NULL;
+
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_type10_lsa_init (new);
+#endif /* HAVE_OPAQUE_LSA */
+
+  new->oiflist = list_new ();
+  new->ranges = route_table_init ();
+
+  if (area_id.s_addr == OSPF_AREA_BACKBONE)
+    ospf_top->backbone = new;
+
+  return new;
+}
+
+void
+ospf_area_free (struct ospf_area *area)
+{
+  /* Free LSDBs. */
+  foreach_lsa (ROUTER_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback);
+  foreach_lsa (NETWORK_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback);
+  foreach_lsa (SUMMARY_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback);
+  foreach_lsa (ASBR_SUMMARY_LSDB (area), area->lsdb, 0,
+              ospf_lsa_discard_callback);
+
+#ifdef HAVE_NSSA
+  foreach_lsa (NSSA_LSDB (area), area->lsdb, 0, ospf_lsa_discard_callback);
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+  foreach_lsa (OPAQUE_AREA_LSDB (area), area->lsdb, 0,
+               ospf_lsa_discard_callback);
+  foreach_lsa (OPAQUE_LINK_LSDB (area), area->lsdb, 0,
+               ospf_lsa_discard_callback);
+#endif /* HAVE_OPAQUE_LSA */
+
+  ospf_lsdb_delete_all (area->lsdb);
+  ospf_lsdb_free (area->lsdb);
+
+#ifdef HAVE_OPAQUE_LSA
+  ospf_opaque_type10_lsa_term (area);
+#endif /* HAVE_OPAQUE_LSA */
+  ospf_lsa_unlock (area->router_lsa_self);
+  
+  route_table_finish (area->ranges);
+  list_delete (area->oiflist);
+
+  if (EXPORT_NAME (area))
+    free (EXPORT_NAME (area));
+
+  if (IMPORT_NAME (area))
+    free (IMPORT_NAME (area));
+
+  /* Cancel timer. */
+  OSPF_TIMER_OFF (area->t_router_lsa_self);
+
+  if (OSPF_IS_AREA_BACKBONE (area))
+    ospf_top->backbone = NULL;
+
+  XFREE (MTYPE_OSPF_AREA, area);
+}
+
+void
+ospf_area_check_free (struct in_addr area_id)
+{
+  struct ospf_area *area;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area &&
+      listcount (area->oiflist) == 0 &&
+      area->ranges->top == NULL &&
+      area->shortcut_configured == OSPF_SHORTCUT_DEFAULT &&
+      area->external_routing == OSPF_AREA_DEFAULT &&
+      area->no_summary == 0 &&
+      area->default_cost == 1 &&
+      EXPORT_NAME (area) == NULL &&
+      IMPORT_NAME (area) == NULL &&
+      area->auth_type == OSPF_AUTH_NULL)
+    {
+      listnode_delete (ospf_top->areas, area);
+      ospf_area_free (area);
+    }
+}
+
+struct ospf_area *
+ospf_area_get (struct in_addr area_id, int format)
+{
+  struct ospf_area *area;
+  
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (!area)
+    {
+      area = ospf_area_new (area_id);
+      area->format = format;
+      listnode_add_sort (ospf_top->areas, area);
+      ospf_check_abr_status ();  
+    }
+
+  return area;
+}
+
+struct ospf_area *
+ospf_area_lookup_by_area_id (struct in_addr area_id)
+{
+  struct ospf_area *area;
+  listnode node;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      if (IPV4_ADDR_SAME (&area->area_id, &area_id))
+        return area;
+    }
+
+  return NULL;
+}
+
+void
+ospf_area_add_if (struct ospf_area *area, struct ospf_interface *oi)
+{
+  listnode_add (area->oiflist, oi);
+}
+
+void
+ospf_area_del_if (struct ospf_area *area, struct ospf_interface *oi)
+{
+  listnode_delete (area->oiflist, oi);
+}
+
+\f
+/* Config network statement related functions. */
+struct ospf_network *
+ospf_network_new (struct in_addr area_id, int format)
+{
+  struct ospf_network *new;
+  new = XCALLOC (MTYPE_OSPF_NETWORK, sizeof (struct ospf_network));
+
+  new->area_id = area_id;
+  new->format = format;
+  
+  return new;
+}
+
+void
+ospf_network_free (struct ospf_network *network)
+{
+  ospf_area_check_free (network->area_id);
+  ospf_schedule_abr_task ();
+  XFREE (MTYPE_OSPF_NETWORK, network);
+}
+
+int
+ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p,
+                 struct in_addr area_id)
+{
+  struct ospf_network *network;
+  struct ospf_area *area;
+  struct route_node *rn;
+  struct external_info *ei;
+  int ret = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  rn = route_node_get (ospf->networks, (struct prefix *)p);
+  if (rn->info)
+    {
+      /* There is already same network statement. */
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  rn->info = network = ospf_network_new (area_id, ret);
+  area = ospf_area_get (area_id, ret);
+
+  /* Run network config now. */
+  ospf_network_run (ospf, (struct prefix *)p, area);
+
+  /* Update connected redistribute. */
+  if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
+    if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT))
+      for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT));
+          rn; rn = route_next (rn))
+       if ((ei = rn->info) != NULL)
+         if (ospf_external_info_find_lsa (&ei->p))
+           if (!ospf_distribute_check_connected (ei))
+             ospf_external_lsa_flush (ei->type, &ei->p,
+                                      ei->ifindex, ei->nexthop);
+
+  ospf_area_check_free (area_id);
+
+  return 1;
+}
+
+int
+ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p,
+                   struct in_addr area_id)
+{
+  struct route_node *rn;
+  struct ospf_network *network;
+  struct external_info *ei;
+
+  rn = route_node_lookup (ospf->networks, (struct prefix *)p);
+  if (rn == NULL)
+    return 0;
+
+  network = rn->info;
+  if (!IPV4_ADDR_SAME (&area_id, &network->area_id))
+    return 0;
+
+  ospf_network_free (rn->info);
+  rn->info = NULL;
+  route_unlock_node (rn);
+
+  ospf_if_update ();
+  
+  /* Update connected redistribute. */
+  if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
+    if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT))
+      for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT));
+          rn; rn = route_next (rn))
+       if ((ei = rn->info) != NULL)
+         if (!ospf_external_info_find_lsa (&ei->p))
+           if (ospf_distribute_check_connected (ei))
+             ospf_external_lsa_originate (ei);
+
+  return 1;
+}
+
+\f
+void
+ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area)
+{
+  struct interface *ifp;
+  listnode node;
+
+  /* Schedule Router ID Update. */
+  if (ospf->router_id_static.s_addr == 0)
+    if (ospf->t_router_id_update == NULL)
+      {
+       ospf->t_router_id_update = 
+         thread_add_timer (master, ospf_router_id_update_timer, ospf,
+                           OSPF_ROUTER_ID_UPDATE_DELAY);
+      }
+
+  /* Get target interface. */
+  for (node = listhead (ospf->iflist); node; nextnode (node))
+    {
+      listnode cn;
+      
+      if ((ifp = getdata (node)) == NULL)
+       continue;
+
+      if (memcmp (ifp->name, "VLINK", 5) == 0)
+       continue;
+       
+      /* if interface prefix is match specified prefix,
+        then create socket and join multicast group. */
+      for (cn = listhead (ifp->connected); cn; nextnode (cn))
+       {
+         struct connected *co = getdata (cn);
+         struct prefix *addr;
+
+         if (if_is_pointopoint (ifp))
+           addr = co->destination;
+         else 
+           addr = co->address;
+
+         if (p->family == co->address->family &&
+             ! ospf_if_is_configured (&(addr->u.prefix4)))
+           if ((if_is_pointopoint (ifp) &&
+                IPV4_ADDR_SAME (&(addr->u.prefix4), &(p->u.prefix4))) ||
+               prefix_match (p, addr)) 
+           {
+               struct ospf_interface *oi;
+               
+               oi = ospf_if_new (ifp, co->address);
+               oi->connected = co;
+               
+               oi->nbr_self->address = *oi->address;
+
+               area->act_ints++;
+               oi->area = area;
+
+               oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4);
+               oi->output_cost = ospf_if_get_output_cost (oi);
+               
+               if (area->external_routing != OSPF_AREA_DEFAULT)
+                 UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+               oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority);
+               
+               /* Add pseudo neighbor. */
+               ospf_nbr_add_self (oi);
+
+               /* Make sure pseudo neighbor's router_id. */
+               oi->nbr_self->router_id = ospf_top->router_id;
+               oi->nbr_self->src = oi->address->u.prefix4;
+               
+               /* Relate ospf interface to ospf instance. */
+               oi->ospf = ospf_top;
+
+               /* update network type as interface flag */
+               /* If network type is specified previously,
+                  skip network type setting. */
+               oi->type = IF_DEF_PARAMS (ifp)->type;
+               
+               /* Set area flag. */
+               switch (area->external_routing)
+                 {
+                 case OSPF_AREA_DEFAULT:
+                   SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+                   break;
+                 case OSPF_AREA_STUB:
+                   UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+                   break;
+#ifdef HAVE_NSSA
+                 case OSPF_AREA_NSSA:
+                   UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+                   SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP);
+                   break;
+#endif /* HAVE_NSSA */
+                 }
+
+               ospf_area_add_if (oi->area, oi);
+
+               if (if_is_up (ifp)) 
+                 ospf_if_up (oi);
+
+               break;
+             }
+       }
+    }
+}
+
+void
+ospf_ls_upd_queue_empty (struct ospf_interface *oi)
+{
+  struct route_node *rn;
+  listnode node;
+  list lst;
+  struct ospf_lsa *lsa;
+
+  /* empty ls update queue */
+  for (rn = route_top (oi->ls_upd_queue); rn;
+       rn = route_next (rn))
+    if ((lst = (list) rn->info))
+      {
+       for (node = listhead (lst); node; nextnode (node))
+         if ((lsa = getdata (node)))
+           ospf_lsa_unlock (lsa);
+       list_free (lst);
+       rn->info = NULL;
+      }
+  
+  /* remove update event */
+  if (oi->t_ls_upd_event)
+    {
+      thread_cancel (oi->t_ls_upd_event);
+      oi->t_ls_upd_event = NULL;
+    }
+}
+
+void
+ospf_if_update ()
+{
+  struct route_node *rn;
+  listnode node;
+  listnode next;
+  struct ospf_network *network;
+  struct ospf_area *area;
+
+  if (ospf_top != NULL)
+    {
+      /* Update Router ID scheduled. */
+      if (ospf_top->router_id_static.s_addr == 0)
+        if (ospf_top->t_router_id_update == NULL)
+          {
+            ospf_top->t_router_id_update =
+              thread_add_timer (master, ospf_router_id_update_timer, NULL,
+                                OSPF_ROUTER_ID_UPDATE_DELAY);
+          }
+
+      /* Find interfaces that not configured already.  */
+      for (node = listhead (ospf_top->oiflist); node; node = next)
+       {
+         int found = 0;
+         struct ospf_interface *oi = getdata (node);
+         struct connected *co = oi->connected;
+         
+         next = nextnode (node);
+
+         if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+           continue;
+         
+         for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn))
+           {
+             if (rn->info == NULL)
+               continue;
+             
+             if ((oi->type == OSPF_IFTYPE_POINTOPOINT
+                  && IPV4_ADDR_SAME (&(co->destination->u.prefix4),
+                                     &(rn->p.u.prefix4)))
+                 || prefix_match (&(rn->p), co->address))
+               {
+                 found = 1;
+                 route_unlock_node (rn);
+                 break;
+               }
+           }
+
+         if (found == 0)
+           ospf_if_free (oi);
+       }
+       
+      /* Run each interface. */
+      for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn))
+       if (rn->info != NULL)
+         {
+           network = (struct ospf_network *) rn->info;
+           area = ospf_area_get (network->area_id, network->format);
+           ospf_network_run (ospf_top, &rn->p, area);
+         }
+    }
+}
+
+void
+ospf_remove_vls_through_area (struct ospf_area *area)
+{
+  listnode node, next;
+  struct ospf_vl_data *vl_data;
+
+  for (node = listhead (ospf_top->vlinks); node; node = next)
+    {
+      next = node->next;
+      if ((vl_data = getdata (node)) != NULL)
+       if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
+         ospf_vl_delete (vl_data);
+    }
+}
+
+\f
+struct message ospf_area_type_msg[] =
+{
+  { OSPF_AREA_DEFAULT, "Default" },
+  { OSPF_AREA_STUB,     "Stub" },
+  { OSPF_AREA_NSSA,     "NSSA" },
+};
+int ospf_area_type_msg_max = OSPF_AREA_TYPE_MAX;
+
+void
+ospf_area_type_set (struct ospf_area *area, int type)
+{
+  listnode node;
+  struct ospf_interface *oi;
+
+  if (area->external_routing == type)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_info ("Area[%s]: Types are the same, ignored.",
+                  inet_ntoa (area->area_id));
+      return;
+    }
+
+  area->external_routing = type;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Area[%s]: Configured as %s", inet_ntoa (area->area_id),
+              LOOKUP (ospf_area_type_msg, type));
+
+  switch (area->external_routing)
+    {
+    case OSPF_AREA_DEFAULT:
+      for (node = listhead (area->oiflist); node; nextnode (node))
+       if ((oi = getdata (node)) != NULL)
+         if (oi->nbr_self != NULL)
+           SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+      break;
+    case OSPF_AREA_STUB:
+      for (node = listhead (area->oiflist); node; nextnode (node))
+       if ((oi = getdata (node)) != NULL)
+         if (oi->nbr_self != NULL)
+           {
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("setting options on %s accordingly", IF_NAME (oi));
+             UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+             if (IS_DEBUG_OSPF_EVENT)
+               zlog_info ("options set on %s: %x",
+                          IF_NAME (oi), OPTIONS (oi));
+           }
+      break;
+    case OSPF_AREA_NSSA:
+#ifdef HAVE_NSSA
+      for (node = listhead (area->oiflist); node; nextnode (node))
+       if ((oi = getdata (node)) != NULL)
+         if (oi->nbr_self != NULL)
+           {
+             zlog_info ("setting nssa options on %s accordingly", IF_NAME (oi));
+             UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
+             SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP);
+             zlog_info ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi));
+           }
+#endif /* HAVE_NSSA */
+      break;
+    default:
+      break;
+    }
+
+  ospf_router_lsa_timer_add (area);
+  ospf_schedule_abr_task ();
+}
+
+int
+ospf_area_shortcut_set (struct ospf_area *area, int mode)
+{
+  if (area->shortcut_configured == mode)
+    return 0;
+
+  area->shortcut_configured = mode;
+  ospf_router_lsa_timer_add (area);
+  ospf_schedule_abr_task ();
+
+  ospf_area_check_free (area->area_id);
+
+  return 1;
+}
+
+int
+ospf_area_shortcut_unset (struct ospf_area *area)
+{
+  area->shortcut_configured = OSPF_SHORTCUT_DEFAULT;
+  ospf_router_lsa_timer_add (area);
+  ospf_area_check_free (area->area_id);
+  ospf_schedule_abr_task ();
+
+  return 1;
+}
+
+int
+ospf_area_vlink_count (struct ospf *ospf, struct ospf_area *area)
+{
+  struct ospf_vl_data *vl;
+  listnode node;
+  int count = 0;
+
+  for (node = listhead (ospf->vlinks); node; nextnode (node))
+    {
+      vl = getdata (node);
+      if (IPV4_ADDR_SAME (&vl->vl_area_id, &area->area_id))
+       count++;
+    }
+
+  return count;
+}
+
+int
+ospf_area_stub_set (struct ospf *ospf, struct in_addr area_id)
+{
+  struct ospf_area *area;
+  int format = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  area = ospf_area_get (area_id, format);
+  if (ospf_area_vlink_count (ospf, area))
+    return 0;
+
+  if (area->external_routing != OSPF_AREA_STUB)
+    ospf_area_type_set (area, OSPF_AREA_STUB);
+
+  return 1;
+}
+
+int
+ospf_area_stub_unset (struct ospf *ospf, struct in_addr area_id)
+{
+  struct ospf_area *area;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 1;
+
+  if (area->external_routing == OSPF_AREA_STUB)
+    ospf_area_type_set (area, OSPF_AREA_DEFAULT);
+
+  ospf_area_check_free (area_id);
+
+  return 1;
+}
+
+int
+ospf_area_no_summary_set (struct ospf *ospf, struct in_addr area_id)
+{
+  struct ospf_area *area;
+  int format = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  area = ospf_area_get (area_id, format);
+  area->no_summary = 1;
+
+  return 1;
+}
+
+int
+ospf_area_no_summary_unset (struct ospf *ospf, struct in_addr area_id)
+{
+  struct ospf_area *area;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 0;
+
+  area->no_summary = 0;
+  ospf_area_check_free (area_id);
+
+  return 1;
+}
+
+int
+ospf_area_nssa_set (struct ospf *ospf, struct in_addr area_id)
+{
+  struct ospf_area *area;
+  int format = OSPF_AREA_ID_FORMAT_DECIMAL;
+
+  area = ospf_area_get (area_id, format);
+  if (ospf_area_vlink_count (ospf, area))
+    return 0;
+
+  if (area->external_routing != OSPF_AREA_NSSA)
+    {
+      ospf_area_type_set (area, OSPF_AREA_NSSA);
+      ospf->anyNSSA++;
+    }
+
+  return 1;
+}
+
+int
+ospf_area_nssa_unset (struct ospf *ospf, struct in_addr area_id)
+{
+  struct ospf_area *area;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 0;
+
+  if (area->external_routing == OSPF_AREA_NSSA)
+    {
+      ospf->anyNSSA--;
+      ospf_area_type_set (area, OSPF_AREA_DEFAULT);
+    }
+
+  ospf_area_check_free (area_id);
+
+  return 1;
+}
+
+int
+ospf_area_nssa_translator_role_set (struct ospf *ospf, struct in_addr area_id,
+                                   int role)
+{
+  struct ospf_area *area;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 0;
+
+  area->NSSATranslator = role;
+
+  return 1;
+}
+
+int
+ospf_area_nssa_translator_role_unset (struct ospf *ospf,
+                                     struct in_addr area_id)
+{
+  struct ospf_area *area;
+
+  area = ospf_area_lookup_by_area_id (area_id);
+  if (area == NULL)
+    return 0;
+
+  area->NSSATranslator = OSPF_NSSA_ROLE_CANDIDATE;
+
+  ospf_area_check_free (area_id);
+
+  return 1;
+}
+
+int
+ospf_area_export_list_set (struct ospf_area *area, char *list_name)
+{
+  struct access_list *list;
+  list = access_list_lookup (AFI_IP, list_name);
+
+  EXPORT_LIST (area) = list;
+
+  if (EXPORT_NAME (area))
+    free (EXPORT_NAME (area));
+
+  EXPORT_NAME (area) = strdup (list_name);
+  ospf_schedule_abr_task ();
+
+  return 1;
+}
+
+int
+ospf_area_export_list_unset (struct ospf_area * area)
+{
+
+  EXPORT_LIST (area) = 0;
+
+  if (EXPORT_NAME (area))
+    free (EXPORT_NAME (area));
+
+  EXPORT_NAME (area) = NULL;
+
+  ospf_area_check_free (area->area_id);
+  
+  ospf_schedule_abr_task ();
+
+  return 1;
+}
+
+int
+ospf_area_import_list_set (struct ospf_area *area, char *name)
+{
+  struct access_list *list;
+  list = access_list_lookup (AFI_IP, name);
+
+  IMPORT_LIST (area) = list;
+
+  if (IMPORT_NAME (area))
+    free (IMPORT_NAME (area));
+
+  IMPORT_NAME (area) = strdup (name);
+  ospf_schedule_abr_task ();
+
+  return 1;
+}
+
+int
+ospf_area_import_list_unset (struct ospf_area * area)
+{
+  IMPORT_LIST (area) = 0;
+
+  if (IMPORT_NAME (area))
+    free (IMPORT_NAME (area));
+
+  IMPORT_NAME (area) = NULL;
+  ospf_area_check_free (area->area_id);
+
+  ospf_schedule_abr_task ();
+
+  return 1;
+}
+
+int
+ospf_timers_spf_set (struct ospf *ospf, u_int32_t delay, u_int32_t hold)
+{
+  ospf->spf_delay = delay;
+  ospf->spf_holdtime = hold;
+
+  return 1;
+}
+
+int
+ospf_timers_spf_unset (struct ospf *ospf)
+{
+  ospf->spf_delay = OSPF_SPF_DELAY_DEFAULT;
+  ospf->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT;
+
+  return 1;
+}
+
+int
+ospf_timers_refresh_set (struct ospf *ospf, int interval)
+{
+  int time_left;
+
+  if (ospf->lsa_refresh_interval == interval)
+    return 1;
+
+  time_left = ospf->lsa_refresh_interval -
+    (time (NULL) - ospf->lsa_refresher_started);
+  
+  if (time_left > interval)
+    {
+      OSPF_TIMER_OFF (ospf->t_lsa_refresher);
+      ospf->t_lsa_refresher =
+       thread_add_timer (master, ospf_lsa_refresh_walker, ospf, interval);
+    }
+  ospf->lsa_refresh_interval = interval;
+
+  return 1;
+}
+
+int
+ospf_timers_refresh_unset (struct ospf *ospf)
+{
+  int time_left;
+
+  time_left = ospf->lsa_refresh_interval -
+    (time (NULL) - ospf->lsa_refresher_started);
+
+  if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
+    {
+      OSPF_TIMER_OFF (ospf->t_lsa_refresher);
+      ospf->t_lsa_refresher =
+       thread_add_timer (master, ospf_lsa_refresh_walker, ospf,
+                         OSPF_LSA_REFRESH_INTERVAL_DEFAULT);
+    }
+
+  ospf->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT;
+
+  return 1;
+}
+
+\f
+struct ospf_nbr_nbma *
+ospf_nbr_nbma_new ()
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = XMALLOC (MTYPE_OSPF_NEIGHBOR_STATIC,
+                     sizeof (struct ospf_nbr_nbma));
+  memset (nbr_nbma, 0, sizeof (struct ospf_nbr_nbma));
+
+  nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
+  nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT;
+
+  return nbr_nbma;
+}
+
+void
+ospf_nbr_nbma_free (struct ospf_nbr_nbma *nbr_nbma)
+{
+  XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma);
+}
+
+void
+ospf_nbr_nbma_delete (struct ospf *ospf, struct ospf_nbr_nbma *nbr_nbma)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefix = nbr_nbma->addr;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p);
+  if (rn)
+    {
+      ospf_nbr_nbma_free (rn->info);
+      rn->info = NULL;
+      route_unlock_node (rn);
+      route_unlock_node (rn);
+    }
+}
+
+void
+ospf_nbr_nbma_down (struct ospf_nbr_nbma *nbr_nbma)
+{
+  OSPF_TIMER_OFF (nbr_nbma->t_poll);
+
+  if (nbr_nbma->nbr)
+    {
+      nbr_nbma->nbr->nbr_nbma = NULL;
+      OSPF_NSM_EVENT_EXECUTE (nbr_nbma->nbr, NSM_KillNbr);
+    }
+
+  if (nbr_nbma->oi)
+    listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma);
+}
+
+void
+ospf_nbr_nbma_add (struct ospf_nbr_nbma *nbr_nbma,
+                  struct ospf_interface *oi)
+{
+  struct ospf_neighbor *nbr;
+  struct route_node *rn;
+  struct prefix p;
+
+  if (oi->type != OSPF_IFTYPE_NBMA)
+    return;
+
+  if (nbr_nbma->nbr != NULL)
+    return;
+
+  if (IPV4_ADDR_SAME (&oi->nbr_self->address.u.prefix4, &nbr_nbma->addr))
+    return;
+      
+  nbr_nbma->oi = oi;
+  listnode_add (oi->nbr_nbma, nbr_nbma);
+
+  /* Get neighbor information from table. */
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.u.prefix4 = nbr_nbma->addr;
+
+  rn = route_node_get (oi->nbrs, (struct prefix *)&p);
+  if (rn->info)
+    {
+      nbr = rn->info;
+      nbr->nbr_nbma = nbr_nbma;
+      nbr_nbma->nbr = nbr;
+
+      route_unlock_node (rn);
+    }
+  else
+    {
+      nbr = rn->info = ospf_nbr_new (oi);
+      nbr->state = NSM_Down;
+      nbr->src = nbr_nbma->addr;
+      nbr->nbr_nbma = nbr_nbma;
+      nbr->priority = nbr_nbma->priority;
+      nbr->address = p;
+
+      nbr_nbma->nbr = nbr;
+
+      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_Start);
+    }
+}
+
+void
+ospf_nbr_nbma_if_update (struct ospf_interface *oi)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  if (oi->type != OSPF_IFTYPE_NBMA)
+    return;
+
+  for (rn = route_top (ospf_top->nbr_nbma); rn; rn = route_next (rn))
+    if ((nbr_nbma = rn->info))
+      if (nbr_nbma->oi == NULL && nbr_nbma->nbr == NULL)
+       {
+         p.family = AF_INET;
+         p.prefix = nbr_nbma->addr;
+         p.prefixlen = IPV4_MAX_BITLEN;
+
+         if (prefix_match (oi->address, (struct prefix *)&p))
+           ospf_nbr_nbma_add (nbr_nbma, oi);
+       }
+}
+
+struct ospf_nbr_nbma *
+ospf_nbr_nbma_lookup (struct ospf *ospf, struct in_addr nbr_addr)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefix = nbr_addr;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p);
+  if (rn)
+    {
+      route_unlock_node (rn);
+      return rn->info;
+    }
+  return NULL;
+}
+
+struct ospf_nbr_nbma *
+ospf_nbr_nbma_lookup_next (struct in_addr *addr, int first)
+{
+#if 0
+  struct ospf_nbr_nbma *nbr_nbma;
+  listnode node;
+#endif
+
+  if (! ospf_top)
+    return NULL;
+
+#if 0
+  for (node = listhead (ospf_top->nbr_nbma); node; nextnode (node))
+    {
+      nbr_nbma = getdata (node);
+
+      if (first)
+       {
+         *addr = nbr_nbma->addr;
+         return nbr_nbma;
+       }
+      else if (ntohl (nbr_nbma->addr.s_addr) > ntohl (addr->s_addr))
+       {
+         *addr = nbr_nbma->addr;
+         return nbr_nbma;
+       }
+    }
+#endif
+  return NULL;
+}
+
+int
+ospf_nbr_nbma_set (struct ospf *ospf, struct in_addr nbr_addr)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+  struct ospf_interface *oi;
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  listnode node;
+
+  nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr);
+  if (nbr_nbma)
+    return 0;
+
+  nbr_nbma = ospf_nbr_nbma_new ();
+  nbr_nbma->addr = nbr_addr;
+
+  p.family = AF_INET;
+  p.prefix = nbr_addr;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  rn = route_node_get (ospf->nbr_nbma, (struct prefix *)&p);
+  rn->info = nbr_nbma;
+
+  for (node = listhead (ospf->oiflist); node; nextnode (node))
+    {
+      oi = getdata (node);
+      if (oi->type == OSPF_IFTYPE_NBMA)
+       if (prefix_match (oi->address, (struct prefix *)&p))
+         {
+           ospf_nbr_nbma_add (nbr_nbma, oi);
+           break;
+         }
+    }
+
+  return 1;
+}
+
+int
+ospf_nbr_nbma_unset (struct ospf *ospf, struct in_addr nbr_addr)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr);
+  if (nbr_nbma == NULL)
+    return 0;
+
+  ospf_nbr_nbma_down (nbr_nbma);
+  ospf_nbr_nbma_delete (ospf, nbr_nbma);
+
+  return 1;
+}
+
+int
+ospf_nbr_nbma_priority_set (struct ospf *ospf, struct in_addr nbr_addr,
+                           u_char priority)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr);
+  if (nbr_nbma == NULL)
+    return 0;
+
+  if (nbr_nbma->priority != priority)
+    nbr_nbma->priority = priority;
+
+  return 1;
+}
+
+int
+ospf_nbr_nbma_priority_unset (struct ospf *ospf, struct in_addr nbr_addr)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr);
+  if (nbr_nbma == NULL)
+    return 0;
+
+  if (nbr_nbma != OSPF_NEIGHBOR_PRIORITY_DEFAULT)
+    nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
+
+  return 1;
+}
+
+int
+ospf_nbr_nbma_poll_interval_set (struct ospf *ospf, struct in_addr nbr_addr,
+                                int interval)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr);
+  if (nbr_nbma == NULL)
+    return 0;
+
+  if (nbr_nbma->v_poll != interval)
+    {
+      nbr_nbma->v_poll = interval;
+      if (nbr_nbma->oi && ospf_if_is_up (nbr_nbma->oi))
+       {
+         OSPF_TIMER_OFF (nbr_nbma->t_poll);
+         OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
+                             nbr_nbma->v_poll);
+       }
+    }
+
+  return 1;
+}
+
+int
+ospf_nbr_nbma_poll_interval_unset (struct ospf *ospf, struct in_addr addr)
+{
+  struct ospf_nbr_nbma *nbr_nbma;
+
+  nbr_nbma = ospf_nbr_nbma_lookup (ospf, addr);
+  if (nbr_nbma == NULL)
+    return 0;
+
+  if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT)
+    nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT;
+
+  return 1;
+}
+
+\f
+void
+ospf_prefix_list_update (struct prefix_list *plist)
+{
+  struct ospf_area *area;
+  listnode node;
+  int abr_inv = 0;
+
+  /* If OSPF instatnce does not exist, return right now. */
+  if (!ospf_top)
+    return;
+
+  /* Update Area prefix-list. */
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      area = getdata (node);
+
+      /* Update filter-list in. */
+      if (PREFIX_NAME_IN (area))
+       if (strcmp (PREFIX_NAME_IN (area), plist->name) == 0)
+         {
+           PREFIX_LIST_IN (area) = 
+             prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area));
+           abr_inv++;
+         }
+
+      /* Update filter-list out. */
+      if (PREFIX_NAME_OUT (area))
+       if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0)
+         {
+           PREFIX_LIST_IN (area) = 
+             prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area));
+           abr_inv++;
+         }
+    }
+
+  /* Schedule ABR tasks. */
+  if (OSPF_IS_ABR && abr_inv)
+    ospf_schedule_abr_task ();
+}
+
+void
+ospf_init ()
+{
+  /* Make empty list of ospf list. */
+  ospf_top = NULL;
+
+  prefix_list_add_hook (ospf_prefix_list_update);
+  prefix_list_delete_hook (ospf_prefix_list_update);
+}
diff --git a/ospfd/ospfd.conf.sample b/ospfd/ospfd.conf.sample
new file mode 100644 (file)
index 0000000..0e8ac67
--- /dev/null
@@ -0,0 +1,13 @@
+! -*- ospf -*-
+!
+! OSPFd sample configuration file
+!
+!
+hostname ospfd
+password zebra
+!enable password please-set-at-here
+!
+!router ospf
+!  network 192.168.1.0/24 area 0
+!
+log stdout
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
new file mode 100644 (file)
index 0000000..a83231b
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * OSPFd main header.
+ * Copyright (C) 1998, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_OSPFD_H
+#define _ZEBRA_OSPFD_H
+
+#include "filter.h"
+
+#define OSPF_VERSION            2
+
+/* Default protocol, port number. */
+#ifndef IPPROTO_OSPFIGP
+#define IPPROTO_OSPFIGP         89
+#endif /* IPPROTO_OSPFIGP */
+
+/* VTY port number. */
+#define OSPF_VTY_PORT          2604
+#define OSPF_VTYSH_PATH        "/tmp/.ospfd"
+
+/* IP TTL for OSPF protocol. */
+#define OSPF_IP_TTL             1
+#define OSPF_VL_IP_TTL          100
+
+/* Default configuration file name for ospfd. */
+#define OSPF_DEFAULT_CONFIG   "ospfd.conf"
+
+/* Architectual Constants */
+#ifdef DEBUG
+#define OSPF_LS_REFRESH_TIME                    60
+#else
+#define OSPF_LS_REFRESH_TIME                  1800
+#endif
+#define OSPF_MIN_LS_INTERVAL                     5
+#define OSPF_MIN_LS_ARRIVAL                      1
+#define OSPF_LSA_MAXAGE                       3600
+#define OSPF_CHECK_AGE                         300
+#define OSPF_LSA_MAXAGE_DIFF                   900
+#define OSPF_LS_INFINITY                  0xffffff
+#define OSPF_DEFAULT_DESTINATION        0x00000000      /* 0.0.0.0 */
+#define OSPF_INITIAL_SEQUENCE_NUMBER    0x80000001
+#define OSPF_MAX_SEQUENCE_NUMBER        0x7fffffff
+
+#define OSPF_LSA_MAXAGE_CHECK_INTERVAL          30
+
+#define OSPF_ALLSPFROUTERS              0xe0000005      /* 224.0.0.5 */
+#define OSPF_ALLDROUTERS                0xe0000006      /* 224.0.0.6 */
+
+#ifdef HAVE_NSSA
+#define OSPF_LOOPer                     0x7f000000      /* 127.0.0.0 */
+#endif /* HAVE_NSSA */
+
+#define OSPF_AREA_BACKBONE              0x00000000      /* 0.0.0.0 */
+
+/* OSPF Authentication Type. */
+#define OSPF_AUTH_NULL                      0
+#define OSPF_AUTH_SIMPLE                    1
+#define OSPF_AUTH_CRYPTOGRAPHIC             2
+/* For Interface authentication setting default */
+#define OSPF_AUTH_NOTSET                   -1
+/* For the consumption and sanity of the command handler */ 
+/* DO NIOT REMOVE!!! Need to detect whether a value has
+   been given or not in VLink command handlers */
+#define OSPF_AUTH_CMD_NOTSEEN              -2
+
+/* OSPF SPF timer values. */
+#define OSPF_SPF_DELAY_DEFAULT              5
+#define OSPF_SPF_HOLDTIME_DEFAULT          10
+
+/* OSPF interface default values. */
+#define OSPF_OUTPUT_COST_DEFAULT           10
+#define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT  40
+#define OSPF_HELLO_INTERVAL_DEFAULT        10
+#define OSPF_ROUTER_PRIORITY_DEFAULT        1
+#define OSPF_RETRANSMIT_INTERVAL_DEFAULT    5
+#define OSPF_TRANSMIT_DELAY_DEFAULT         1
+#define OSPF_DEFAULT_BANDWIDTH          10000  /* Kbps */
+
+#define OSPF_DEFAULT_REF_BANDWIDTH     100000  /* Kbps */
+
+#define OSPF_POLL_INTERVAL_DEFAULT         60
+#define OSPF_NEIGHBOR_PRIORITY_DEFAULT      0
+
+/* OSPF options. */
+#define OSPF_OPTION_T                    0x01  /* TOS. */
+#define OSPF_OPTION_E                    0x02
+#define OSPF_OPTION_MC                   0x04
+#define OSPF_OPTION_NP                   0x08
+#define OSPF_OPTION_EA                   0x10
+#define OSPF_OPTION_DC                   0x20
+#define OSPF_OPTION_O                    0x40
+
+/* OSPF Database Description flags. */
+#define OSPF_DD_FLAG_MS                  0x01
+#define OSPF_DD_FLAG_M                   0x02
+#define OSPF_DD_FLAG_I                   0x04
+#define OSPF_DD_FLAG_ALL                 0x07
+
+/* Timer value. */
+#define OSPF_ROUTER_ID_UPDATE_DELAY             1
+
+#define OSPF_LS_REFRESH_SHIFT       (60 * 15)
+#define OSPF_LS_REFRESH_JITTER      60
+
+/* OSPF instance structure. */
+struct ospf
+{
+  /* OSPF Router ID. */
+  struct in_addr router_id;            /* Configured automatically. */
+  struct in_addr router_id_static;     /* Configured manually. */
+
+  /* ABR/ASBR internal flags. */
+  u_char flags;
+#define OSPF_FLAG_ABR           0x0001
+#define OSPF_FLAG_ASBR          0x0002
+
+  /* ABR type. */
+  u_char abr_type;
+#define OSPF_ABR_UNKNOWN       0
+#define OSPF_ABR_STAND          1
+#define OSPF_ABR_IBM            2
+#define OSPF_ABR_CISCO          3
+#define OSPF_ABR_SHORTCUT       4
+
+  /* NSSA ABR */
+  u_char anyNSSA;              /* Bump for every NSSA attached. */
+
+  /* Configured variables. */
+  u_char config;
+#define OSPF_RFC1583_COMPATIBLE         (1 << 0)
+#define OSPF_OPAQUE_CAPABLE            (1 << 2)
+
+#ifdef HAVE_OPAQUE_LSA
+  /* Opaque-LSA administrative flags. */
+  u_char opaque;
+#define OPAQUE_OPERATION_READY_BIT     (1 << 0)
+#define OPAQUE_BLOCK_TYPE_09_LSA_BIT   (1 << 1)
+#define OPAQUE_BLOCK_TYPE_10_LSA_BIT   (1 << 2)
+#define OPAQUE_BLOCK_TYPE_11_LSA_BIT   (1 << 3)
+#endif /* HAVE_OPAQUE_LSA */
+
+  int spf_delay;                       /* SPF delay time. */
+  int spf_holdtime;                    /* SPF hold time. */
+  int default_originate;               /* Default information originate. */
+#define DEFAULT_ORIGINATE_NONE         0
+#define DEFAULT_ORIGINATE_ZEBRA                1
+#define DEFAULT_ORIGINATE_ALWAYS       2
+  u_int32_t ref_bandwidth;             /* Reference Bandwidth (Kbps). */
+  struct route_table *networks;         /* OSPF config networks. */
+  list vlinks;                          /* Configured Virtual-Links. */
+  list areas;                           /* OSPF areas. */
+  struct route_table *nbr_nbma;
+  struct ospf_area *backbone;           /* Pointer to the Backbone Area. */
+
+  list iflist;                          /* Zebra derived interfaces. */
+  list oiflist;                         /* ospf interfaces */
+
+  /* LSDB of AS-external-LSAs. */
+  struct ospf_lsdb *lsdb;
+  
+  /* Redistributed external information. */
+  struct route_table *external_info[ZEBRA_ROUTE_MAX + 1];
+#define EXTERNAL_INFO(T)      ospf_top->external_info[T]
+
+  /* Flags. */
+  int external_origin;                 /* AS-external-LSA origin flag. */
+  int ase_calc;                                /* ASE calculation flag. */
+
+#ifdef HAVE_OPAQUE_LSA
+  list opaque_lsa_self;                        /* Type-11 Opaque-LSAs */
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Routing tables. */
+  struct route_table *old_table;        /* Old routing table. */
+  struct route_table *new_table;        /* Current routing table. */
+
+  struct route_table *old_rtrs;         /* Old ABR/ASBR RT. */
+  struct route_table *new_rtrs;         /* New ABR/ASBR RT. */
+
+  struct route_table *new_external_route;   /* New External Route. */
+  struct route_table *old_external_route;   /* Old External Route. */
+  
+  struct route_table *external_lsas;    /* Database of external LSAs,
+                                          prefix is LSA's adv. network*/
+
+  /* Time stamps. */
+  time_t ts_spf;                       /* SPF calculation time stamp. */
+
+  list maxage_lsa;                      /* List of MaxAge LSA for deletion. */
+  int redistribute;                     /* Num of redistributed protocols. */
+
+  /* Threads. */
+  struct thread *t_router_id_update;   /* Router ID update timer. */
+  struct thread *t_router_lsa_update;   /* router-LSA update timer. */
+  struct thread *t_abr_task;            /* ABR task timer. */
+  struct thread *t_asbr_check;          /* ASBR check timer. */
+  struct thread *t_distribute_update;   /* Distirbute list update timer. */
+  struct thread *t_spf_calc;           /* SPF calculation timer. */
+  struct thread *t_ase_calc;           /* ASE calculation timer. */
+  struct thread *t_external_lsa;       /* AS-external-LSA origin timer. */
+#ifdef HAVE_OPAQUE_LSA
+  struct thread *t_opaque_lsa_self;    /* Type-11 Opaque-LSAs origin event. */
+#endif /* HAVE_OPAQUE_LSA */
+  struct thread *t_maxage;              /* MaxAge LSA remover timer. */
+  struct thread *t_maxage_walker;       /* MaxAge LSA checking timer. */
+
+  struct thread *t_write;
+  struct thread *t_read;
+  int fd;
+  list oi_write_q;
+  
+  /* Distribute lists out of other route sources. */
+  struct 
+  {
+    char *name;
+    struct access_list *list;
+  } dlist[ZEBRA_ROUTE_MAX];
+#define DISTRIBUTE_NAME(T)    ospf_top->dlist[T].name
+#define DISTRIBUTE_LIST(T)    ospf_top->dlist[T].list
+
+  /* Redistribute metric info. */
+  struct 
+  {
+    int type;                   /* External metric type (E1 or E2).  */
+    int value;                 /* Value for static metric (24-bit).
+                                  -1 means metric value is not set. */
+  } dmetric [ZEBRA_ROUTE_MAX + 1];
+
+  /* For redistribute route map. */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+  } route_map [ZEBRA_ROUTE_MAX + 1]; /* +1 is for default-information */
+#define ROUTEMAP_NAME(T)   ospf_top->route_map[T].name
+#define ROUTEMAP(T)        ospf_top->route_map[T].map
+  
+  int default_metric;          /* Default metric for redistribute. */
+
+#define OSPF_LSA_REFRESHER_GRANULARITY 10
+#define OSPF_LSA_REFRESHER_SLOTS ((OSPF_LS_REFRESH_TIME + \
+                                  OSPF_LS_REFRESH_SHIFT)/10 + 1)
+  struct
+  {
+    u_int16_t index;
+    list qs[OSPF_LSA_REFRESHER_SLOTS];
+  } lsa_refresh_queue;
+  
+  struct thread *t_lsa_refresher;
+  time_t lsa_refresher_started;
+#define OSPF_LSA_REFRESH_INTERVAL_DEFAULT 10
+  u_int16_t lsa_refresh_interval;
+  
+  /* Distance parameter. */
+  u_char distance_all;
+  u_char distance_intra;
+  u_char distance_inter;
+  u_char distance_external;
+
+  /* Statistics for LSA origination. */
+  u_int32_t lsa_originate_count;
+
+  /* Statistics for LSA used for new instantiation. */
+  u_int32_t rx_lsa_count;
+  struct route_table *distance_table;
+};
+
+/* OSPF area structure. */
+struct ospf_area
+{
+  /* OSPF instance. */
+  struct ospf *top;
+
+  /* Zebra interface list belonging to the area. */
+  list oiflist;
+
+  /* Area ID. */
+  struct in_addr area_id;
+
+  /* Area ID format. */
+  char format;
+#define OSPF_AREA_ID_FORMAT_ADDRESS         1
+#define OSPF_AREA_ID_FORMAT_DECIMAL         2
+
+  /* Address range. */
+  list address_range;
+
+  /* Configured variables. */
+  int external_routing;                 /* ExternalRoutingCapability. */
+#define OSPF_AREA_DEFAULT       0
+#define OSPF_AREA_STUB          1
+#define OSPF_AREA_NSSA          2
+#define OSPF_AREA_TYPE_MAX     3
+  int no_summary;                       /* Don't inject summaries into stub.*/
+  int shortcut_configured;              /* Area configured as shortcut. */
+#define OSPF_SHORTCUT_DEFAULT  0
+#define OSPF_SHORTCUT_ENABLE   1
+#define OSPF_SHORTCUT_DISABLE  2
+  int shortcut_capability;              /* Other ABRs agree on S-bit */
+  u_int32_t default_cost;               /* StubDefaultCost. */
+  int auth_type;                        /* Authentication type. */
+
+  u_char NSSATranslatorRole;          /* NSSA Role during configuration */
+#define OSPF_NSSA_ROLE_NEVER     0
+#define OSPF_NSSA_ROLE_ALWAYS    1
+#define OSPF_NSSA_ROLE_CANDIDATE 2
+  u_char NSSATranslator;              /* NSSA Role after election process */
+
+  u_char transit;                      /* TransitCapability. */
+#define OSPF_TRANSIT_FALSE      0
+#define OSPF_TRANSIT_TRUE       1
+  struct route_table *ranges;          /* Configured Area Ranges. */
+
+  /* Area related LSDBs[Type1-4]. */
+  struct ospf_lsdb *lsdb;
+
+  /* Self-originated LSAs. */
+  struct ospf_lsa *router_lsa_self;
+#ifdef HAVE_OPAQUE_LSA
+  list opaque_lsa_self;                        /* Type-10 Opaque-LSAs */
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Area announce list. */
+  struct 
+  {
+    char *name;
+    struct access_list *list;
+  } export;
+#define EXPORT_NAME(A)  (A)->export.name
+#define EXPORT_LIST(A)  (A)->export.list
+
+  /* Area acceptance list. */
+  struct 
+  {
+    char *name;
+    struct access_list *list;
+  } import;
+#define IMPORT_NAME(A)  (A)->import.name
+#define IMPORT_LIST(A)  (A)->import.list
+
+  /* Type 3 LSA Area prefix-list. */
+  struct 
+  {
+    char *name;
+    struct prefix_list *list;
+  } plist_in;
+#define PREFIX_LIST_IN(A)   (A)->plist_in.list
+#define PREFIX_NAME_IN(A)   (A)->plist_in.name
+
+  struct
+  {
+    char *name;
+    struct prefix_list *list;
+  } plist_out;
+#define PREFIX_LIST_OUT(A)  (A)->plist_out.list
+#define PREFIX_NAME_OUT(A)  (A)->plist_out.name
+
+  /* Shortest Path Tree. */
+  struct vertex *spf;
+
+  /* Threads. */
+  struct thread *t_router_lsa_self;/* Self-originated router-LSA timer. */
+#ifdef HAVE_OPAQUE_LSA
+  struct thread *t_opaque_lsa_self;    /* Type-10 Opaque-LSAs origin. */
+#endif /* HAVE_OPAQUE_LSA */
+
+  /* Statistics field. */
+  u_int32_t spf_calculation;   /* SPF Calculation Count. */
+
+  /* Router count. */
+  u_int32_t abr_count;         /* ABR router in this area. */
+  u_int32_t asbr_count;                /* ASBR router in this area. */
+
+  /* Counters. */
+  u_int32_t act_ints;          /* Active interfaces. */
+  u_int32_t full_nbrs;         /* Fully adjacent neighbors. */
+  u_int32_t full_vls;          /* Fully adjacent virtual neighbors. */
+};
+
+/* OSPF config network structure. */
+struct ospf_network
+{
+  /* Area ID. */
+  struct in_addr area_id;
+  int format;
+};
+
+/* OSPF NBMA neighbor structure. */
+struct ospf_nbr_nbma
+{
+  /* Neighbor IP address. */
+  struct in_addr addr;
+
+  /* OSPF interface. */
+  struct ospf_interface *oi;
+
+  /* OSPF neighbor structure. */
+  struct ospf_neighbor *nbr;
+
+  /* Neighbor priority. */
+  u_char priority;
+
+  /* Poll timer value. */
+  u_int32_t v_poll;
+
+  /* Poll timer thread. */
+  struct thread *t_poll;
+
+  /* State change. */
+  u_int32_t state_change;
+};
+
+/* Macro. */
+#define OSPF_AREA_SAME(X,Y) \
+        (memcmp ((X->area_id), (Y->area_id), IPV4_MAX_BYTELEN) == 0)
+
+#define OSPF_IS_ABR            (ospf_top->flags & OSPF_FLAG_ABR)
+#define OSPF_IS_ASBR           (ospf_top->flags & OSPF_FLAG_ASBR)
+
+#define OSPF_IS_AREA_ID_BACKBONE(I) ((I).s_addr == OSPF_AREA_BACKBONE)
+#define OSPF_IS_AREA_BACKBONE(A) OSPF_IS_AREA_ID_BACKBONE ((A)->area_id)
+
+#ifdef roundup
+#  define ROUNDUP(val, gran)   roundup(val, gran)
+#else /* roundup */
+#  define ROUNDUP(val, gran)   (((val) - 1 | (gran) - 1) + 1)
+#endif /* roundup */
+
+#define LSA_OPTIONS_GET(area) \
+        (((area)->external_routing == OSPF_AREA_DEFAULT) ? OSPF_OPTION_E : 0)
+#ifdef HAVE_NSSA
+#define LSA_NSSA_GET(area) \
+        (((area)->external_routing == OSPF_AREA_NSSA) ? \
+          (area)->NSSATranslator : 0)
+#endif /* HAVE_NSSA */
+
+#define OSPF_TIMER_ON(T,F,V)                                                  \
+    do {                                                                      \
+      if (!(T))                                                               \
+       (T) = thread_add_timer (master, (F), NULL, (V));                      \
+    } while (0)
+
+#define OSPF_AREA_TIMER_ON(T,F,V)                                             \
+    do {                                                                      \
+      if (!(T))                                                               \
+        (T) = thread_add_timer (master, (F), area, (V));                      \
+    } while (0)
+
+#define OSPF_POLL_TIMER_ON(T,F,V)                                             \
+    do {                                                                      \
+      if (!(T))                                                               \
+        (T) = thread_add_timer (master, (F), nbr_nbma, (V));                  \
+    } while (0)
+
+#define OSPF_POLL_TIMER_OFF(X)         OSPF_TIMER_OFF((X))
+
+#define OSPF_TIMER_OFF(X)                                                     \
+    do {                                                                      \
+      if (X)                                                                  \
+        {                                                                     \
+          thread_cancel (X);                                                  \
+          (X) = NULL;                                                         \
+        }                                                                     \
+    } while (0)
+
+#define OSPF_SCHEDULE_MAXAGE(T, F)                                            \
+    do {                                                                      \
+      if (!(T))                                                               \
+        (T) = thread_add_timer (master, (F), 0, 2);                           \
+    } while (0)
+
+/* Messages */
+extern struct message ospf_ism_state_msg[];
+extern struct message ospf_nsm_state_msg[];
+extern struct message ospf_lsa_type_msg[];
+extern struct message ospf_link_state_id_type_msg[];
+extern struct message ospf_redistributed_proto[];
+extern struct message ospf_network_type_msg[];
+extern int ospf_ism_state_msg_max;
+extern int ospf_nsm_state_msg_max;
+extern int ospf_lsa_type_msg_max;
+extern int ospf_link_state_id_type_msg_max;
+extern int ospf_redistributed_proto_max;
+extern int ospf_network_type_msg_max;
+extern struct zclient *zclient;
+extern struct thread_master *master;
+extern struct ospf *ospf_top;
+extern int ospf_zlog;
+
+/* Prototypes. */
+struct ospf *ospf_get ();
+void ospf_finish (struct ospf *);
+int ospf_router_id_update_timer (struct thread *);
+void ospf_router_id_update ();
+int ospf_network_set (struct ospf *, struct prefix_ipv4 *, struct in_addr);
+int ospf_network_unset (struct ospf *, struct prefix_ipv4 *, struct in_addr);
+int ospf_area_stub_set (struct ospf *, struct in_addr);
+int ospf_area_stub_unset (struct ospf *, struct in_addr);
+int ospf_area_no_summary_set (struct ospf *, struct in_addr);
+int ospf_area_no_summary_unset (struct ospf *, struct in_addr);
+int ospf_area_nssa_set (struct ospf *, struct in_addr);
+int ospf_area_nssa_unset (struct ospf *, struct in_addr);
+int ospf_area_nssa_translator_role_set (struct ospf *, struct in_addr, int);
+int ospf_area_export_list_set (struct ospf_area *, char *);
+int ospf_area_export_list_unset (struct ospf_area *);
+int ospf_area_import_list_set (struct ospf_area *, char *);
+int ospf_area_import_list_unset (struct ospf_area *);
+int ospf_area_shortcut_set (struct ospf_area *, int);
+int ospf_area_shortcut_unset (struct ospf_area *);
+int ospf_timers_spf_set (struct ospf *, u_int32_t, u_int32_t);
+int ospf_timers_spf_unset (struct ospf *);
+int ospf_timers_refresh_set (struct ospf *, int);
+int ospf_timers_refresh_unset (struct ospf *);
+int ospf_nbr_nbma_set (struct ospf *, struct in_addr);
+int ospf_nbr_nbma_unset (struct ospf *, struct in_addr);
+int ospf_nbr_nbma_priority_set (struct ospf *, struct in_addr, u_char);
+int ospf_nbr_nbma_priority_unset (struct ospf *, struct in_addr);
+int ospf_nbr_nbma_poll_interval_set (struct ospf *, struct in_addr, int);
+int ospf_nbr_nbma_poll_interval_unset (struct ospf *, struct in_addr);
+void ospf_prefix_list_update (struct prefix_list *);
+void ospf_init ();
+void ospf_if_update ();
+void ospf_ls_upd_queue_empty (struct ospf_interface *);
+void ospf_terminate ();
+void ospf_nbr_nbma_if_update (struct ospf_interface *);
+struct ospf_nbr_nbma *ospf_nbr_nbma_lookup (struct ospf *, struct in_addr);
+struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next (struct in_addr *, int);
+int ospf_oi_count (struct interface *);
+
+struct ospf_area *ospf_area_new (struct in_addr);
+struct ospf_area *ospf_area_get (struct in_addr, int);
+void ospf_area_check_free (struct in_addr);
+struct ospf_area *ospf_area_lookup_by_area_id (struct in_addr);
+void ospf_area_add_if (struct ospf_area *, struct ospf_interface *);
+void ospf_area_del_if (struct ospf_area *, struct ospf_interface *);
+
+void ospf_route_map_init ();
+void ospf_snmp_init ();
+
+#endif /* _ZEBRA_OSPFD_H */
diff --git a/ports/Makefile b/ports/Makefile
new file mode 100644 (file)
index 0000000..d085d06
--- /dev/null
@@ -0,0 +1,58 @@
+# New ports collection makefile for:   zebra
+# Version required:    2.1.5
+# Date created:                28 Feb 1998
+# Whom:                        seirios@matrix.iri.co.jp
+#
+
+#DISTNAME=     zebra-980224
+DISTNAME=      zebra-current
+PKGNAME=       zebra
+CATEGORIES=    net
+MASTER_SITES=  ftp://ftp.zebra.org/pub/zebra/
+
+MAINTAINER=    seirios@matrix.iri.co.jp
+
+WRKSRC=                ${WRKDIR}/zebra-current
+
+#### Under constructing, We cannot support md5
+NO_CHECKSUM=   yes
+
+do-build:
+       @(cd ${WRKSRC}; sh ./configure; make)
+
+post-install:
+       @if [ ! -f ${PREFIX}/etc/rc.d/zebra.sh ]; then \
+               echo "Installing ${PREFIX}/etc/rc.d/zebra.sh startup file."; \
+               echo "#!/bin/sh" > ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "# zebra" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "if [ -x /usr/local/sbin/zebra -a ! -f /var/run/zebra.pid -a -f /usr/local/etc/zebra.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  /usr/local/sbin/zebra -d -f /usr/local/etc/zebra.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  echo -n ' zebra'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "# bgpd" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "if [ -x /usr/local/sbin/bgpd -a ! -f /var/run/bgpd.pid -a -f /usr/local/etc/bgpd.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  /usr/local/sbin/bgpd -d -f /usr/local/etc/bgpd.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  echo -n ' bgpd'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "# ripd" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "if [ -x /usr/local/sbin/ripd -a ! -f /var/run/ripd.pid -a -f /usr/local/etc/ripd.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  /usr/local/sbin/ripd -d -f /usr/local/etc/ripd.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  echo -n ' ripd'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "# ripngd" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "if [ -x /usr/local/sbin/ripngd -a ! -f /var/run/ripd.pid -a -f /usr/local/etc/ripd.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  /usr/local/sbin/ripngd -d -f /usr/local/etc/ripd.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "  echo -n ' ripngd'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
+               chmod 751 ${PREFIX}/etc/rc.d/zebra.sh; \
+       fi
+       @echo "If you will access zebra,bgpd,ripd,ripngd with telnet,";
+       @echo "then you add some line (written under this line) to /etc/services";
+       @echo " zebrasrv      2600/tcp            # zebra service";
+       @echo " zebra         2601/tcp            # zebra vty";
+       @echo " ripd          2602/tcp            # RIPd vty";
+       @echo " ripngd        2603/tcp            # RIPngd vty";
+       @echo " ospfd         2604/tcp            # OSPFd vty";
+       @echo " bgpd          2605/tcp            # BGPd vty";
+
+.include <bsd.port.mk>
diff --git a/ports/README b/ports/README
new file mode 100644 (file)
index 0000000..a650eaa
--- /dev/null
@@ -0,0 +1 @@
+This directory contain files for making FreeBSD package.
diff --git a/ports/files/md5 b/ports/files/md5
new file mode 100644 (file)
index 0000000..520c348
--- /dev/null
@@ -0,0 +1 @@
+MD5 (zebra-980224.tar.gz) = c6887645741200c43341156c168c7034
diff --git a/ports/pkg/COMMENT b/ports/pkg/COMMENT
new file mode 100644 (file)
index 0000000..53c55e3
--- /dev/null
@@ -0,0 +1 @@
+Zebra Routing protocol daemon
diff --git a/ports/pkg/DESCR b/ports/pkg/DESCR
new file mode 100644 (file)
index 0000000..0c8d01b
--- /dev/null
@@ -0,0 +1,75 @@
+=============
+WHAT IS ZEBRA
+=============
+  Zebra is a free software that manages TCP/IP based routing protocol.
+  It takes multi-server and multi-thread approach to resolve the current
+complexity of the Internet.
+
+  Currently zebra is still under development, so If you want to use zebra,
+I strongly recommend you to get the latest version of zebra.
+  Zebra snapshot is released on every monday.
+
+===================
+SUPPORTED Protocols
+===================
+  Zebra supports both IPv4 and IPv6 :-)
+  For supporting IPv4 Routing protocols is here
+       RIP (both version1 and version2)
+               RIPv2 supports both Multicast and Broadcast
+       BGP (only support BGP4)
+
+  For supporting IPv6 Routing protocols is here
+       RIPng
+       BGP4+
+
+===================
+Supported plat-home
+===================
+  Now zebra is testing on 
+  o FreeBSD 2.2.8
+      -- without IPv6 ;-)
+      -- with KAME
+      -- with INRIA IPv6 protocol stack.
+
+  o GNU/Linux 2.2.2
+  o GNU/Linux 2.0.36
+
+===========
+ZEBRA Ports
+===========
+  Each daemon has each own terminal interface.  Also zebra has communication
+port which provides several services to other daemons.  Below is zebra ports
+list.
+
+zebrasrv      2600/tcp           # zebra service
+zebra        2601/tcp            # zebra vty
+ripd         2602/tcp            # RIPd vty
+ripngd       2603/tcp            # RIPngd vty
+ospfd        2604/tcp            # OSPFd vty
+bgpd         2605/tcp            # BGPd vty
+
+I recommend you to add upper list to /etc/services.
+
+====================
+For More Information
+====================
+  Web page is located at:
+       http://www.zebra.org/
+
+  Alpha version source file can be found at:
+       ftp://ftp.zebra.org/pub/zebra/
+
+  Mailing List is here
+       zebra@zebra.org
+       zebra-jp@zebra.org
+
+    If you want to join zebra mailing list, mail to 
+       majordomo@zebra.org
+    and you write
+       subscribe zebra
+         -- if you want to talk with English
+       subscribe zebra-jp
+         -- if you want to talk with Japanese
+    on Mail BODY (Not Subject).
+
+Enjoy.
diff --git a/ports/pkg/PLIST b/ports/pkg/PLIST
new file mode 100644 (file)
index 0000000..ccc69eb
--- /dev/null
@@ -0,0 +1,8 @@
+sbin/zebra
+sbin/bgpd
+sbin/ripd
+etc/bgpd.conf.sample
+etc/ripd.conf.sample
+etc/zebra.conf.sample
+etc/rc.d/zebra.sh
+info/zebra.info
diff --git a/ripd/.cvsignore b/ripd/.cvsignore
new file mode 100644 (file)
index 0000000..1f91515
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile
+*.o
+ripd
+ripd.conf
+tags
+TAGS
+.deps
diff --git a/ripd/ChangeLog b/ripd/ChangeLog
new file mode 100644 (file)
index 0000000..42fced5
--- /dev/null
@@ -0,0 +1,749 @@
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2002-06-30  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ripd.c (rip_output_process): When outgoing interface is same as
+       next hop interface, announce RIPv2 next hop otherwise set next hop
+       to 0.  Revert previous change then take 6WIND way.
+
+2001-09-14  Akihiro Mizutani <mizutani@dml.com>
+
+       * ripd.c: RIP enabled interface's route is advertised by default.
+
+2001-08-28  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * rip_snmp.c (rip_ifaddr_delete): Add route_node_lookup() return
+       value check.
+
+       * rip_interface.c (rip_multicast_leave): Fix bug of multiple IP
+       address on one interface multicast join/leave bug.
+
+2001-08-26  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * rip_interface.c (no_rip_passive_interface): Add NO_STR.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_routemap.c (route_match_ip_address_prefix_list): Add match
+       ip next-hop prefix-list WORD.
+
+2001-02-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (rip_passive_interface_clean): Call
+       rip_passive_interface_apply_all.
+
+2001-02-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_response_process): Multicast address nexthop check
+       is moved from rip_nexthop_check.
+
+2001-02-08  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * rip_interface.c (ipv4_multicast_join): Use
+       setsockopt_multicast_ipv4.
+       (ipv4_multicast_leave): Likewise.
+       (rip_if_ipv4_address_check): Interface which has IPv4 address can
+       be enabled.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (rip_interface_delete): To support pseudo
+       interface do not free interface structure.
+       * ripd.c (rip_output_process): If output interface is in simple
+       password authentication mode, we need space for authentication
+       data.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_nexthop_check): Fix multicast address nexthop check.
+
+       * zebra-0.91 is released.
+
+2001-01-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (show_ip_rip): Show metric infinity route's timeout.
+       (rip_rte_process): If current route is metric infinity, route is
+       replaced with received rte.
+       (rip_redistribute_delete): When redistribute route is deleted,
+       perform poisoned reverse.
+       (rip_redistribute_withdraw): Likewise.
+
+2001-01-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_response_process): RIPv2 routing table entry with
+       non directly reachable nexthop was dropped.  The code is changed
+       to treat it as 0.0.0.0 nexthop.
+       (rip_destination_check): Check net 0 address destination.
+       (rip_nexthop_check): New function for checking nexthop address
+       validity.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_request_process): Triggered update only send changed
+       route.
+
+       * rip_interface.c: Delete RIP_API part until new implementation
+       comes out.
+
+       * rip_snmp.: Likewise.
+
+       * rip_zebra.c: Likewise.
+
+       * ripd.c: Likewise. 
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (rip_if_init): Remove HAVE_IF_PSEUDO part.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.h (RIP_VTYSH_PATH): Change "/tmp/ripd" to "/tmp/.ripd".
+
+2000-12-25  David Lipovkov <davidl@nbase.co.il>
+
+       * ripd.c (rip_rte_process): When a route is in garbage collection
+       process (invalid with metric 16) and a router receives the same
+       route with valid metric then route was not installed into zebra
+       rib, but only into ripd rib. Moreover , it will never get into
+       zebra rib, because ripd wrongly assumes it's already there.
+       (rip_redistribute_add): When doing redistribute into rip other
+       route (e.g. connected) and the same route exists in ripd rib we
+       changed it in place - bug. Now we don't forget to remove old route
+       from zebra.
+       (rip_timeout): When removing routes from zebra I made sure that we
+       remove route with the metric we have in zebra and not the new
+       one. It doesn't make a difference now,but could be significant
+       when multipath support is done.
+
+2000-12-25  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_zebra.c (rip_metric_unset): Fix bug of metric value unset.
+
+2000-11-25  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+       * ripd.c (rip_request_process): Check passive flag of the
+       interface.
+
+2000-11-23  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+       * rip_interface.c (rip_multicast_join): When IP_ADD_MEMBERSHIP
+       failed do not set runnning flag to the interface.
+
+2000-11-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_output_process): Memory leak related classfull
+       network generation is fixed.
+
+2000-11-16  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+       * rip_interface.c (if_check_address): Obsolete pointopoint address
+       check is removed.
+
+2000-11-02  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+       * rip_interface.c (if_check_address): Add pointopoint address
+       check.
+       (rip_interface_up): Add check for passive interface when interface
+       goes up.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+       * rip_snmp.c: rip_oid and ripd_oid are used in smux_open after it
+       is registered.  So those variables must be static.
+
+2000-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c: Change to "no ip rip (send|receive)" command
+       accept version number argument.
+
+2000-10-17  Akihiro Mizutani <mizutani@dml.com>
+
+       * rip_routemap.c (route_set_ip_nexthop_compile): Change "match ip
+       next-hop" from IP address to access-list name.
+
+2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_peer.c: Change ot use linklist.c instaed of newlist.c.
+
+2000-10-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_offset.c: Change to use linklist.c instead of newlist.c.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-09-26  Akihiro Mizutani <mizutani@dml.com>
+
+       * rip_routemap.c (match_ip_nexthop): Add next-hop format check.
+
+2000-09-18  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+       * rip_interface.c (ripd_api_get_if_rx_version): Corrects rip SNMP
+       and rip API functions dealing with rip version.
+
+       * rip_snmp.c (Status_Valid): SNMPv2-TC TEXTUAL-CONVENTION.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_snmp.c (rip2IfLookup): Use rip_ifaddr_lookup_next() instead
+       of rip_if_lookup_next().
+
+       * rip_interface.c (rip_enable_network_lookup): Interface enable
+       check by interface's address with /32 prefix.
+
+       * ripd.c (rip_read): When RIP is configured with authentication
+       and no authentication in incoming packet, drop the packet.
+
+       * rip_interface.c (rip_interface_reset): RIP_AUTH_SIMPLE_PASSWORD
+       is default mode of authentication.
+       (rip_interface_new): Likewise.
+       (no_ip_rip_authentication_mode): Likewise.
+
+       * ripd.c (rip_read): Likewise.
+
+2000-09-10  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_snmp.c: Set ASN_INTEGER v->type where it is needed.
+
+2000-09-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_auth_simple_password): Simple password
+       authentication using key-chain.
+       (rip_write_rte): Likewise.
+
+       * rip_interface.c (ip_rip_authentication_key_chain): Add check for
+       authentication string configuration.
+
+2000-09-08  Akihiro Mizutani <mizutani@dml.com>
+
+       * ripd.c (rip_write_rte): Add check for ri->auth_str.
+
+2000-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd_api.h: New file is added.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_rte_process): rip_route_process() is renamed to
+       rip_rte_process() to clarify meanings of the function.
+       rip_route_process() is newly added to process RIP route selection.
+
+2000-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_incoming_filter): Extract incoming filter code to
+       function from rip_route_process(). Add check for all interface
+       filter.
+       (rip_outgoing_filter): Extract incoming filter code to function
+       from rip_output_process().  Add check for all interface filter.
+
+       * rip_zebra.c (rip_redistribute_clean): Reset redistribute status
+       when "no router rip" is performed.
+
+       * rip_interface.c (rip_interface_clean): Reset interface's RIP
+       enable status.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_route_process): When metric infinity is received the
+       route is removed from service immediately.
+       (rip_timeout): Likewise.
+       (rip_garbage_collect): Do not delete route in garbage collection.
+       (rip_output_process): Check metric_out exceed metric infinity.
+
+       * zebra-0.88 is released.
+
+2000-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_distance_apply): Unlock node when there is matched
+       node.
+
+2000-08-13  Akihiro Mizutani <mizutani@dml.com>
+
+       * rip_routemap.c (match_ip_nexthop): Add check for IP address
+       validness.
+       (no_set_metric): Add new ALIAS.
+
+2000-08-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.h (struct rip ): Add distance.
+
+2000-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_zebra.c (rip_zebra_ipv4_add): Use new Zebra api to register
+       routes.  Pass RIP metric value to zebra.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_main.c (main): Make struct thread thread from global
+       variable to local variable in main.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_packet_dump): Add MD5 authentication dump function.
+       (rip_auth_md5): RIP MD5 authentication packet receive works.
+
+2000-08-02  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_interface.c (rip_if_init): Install interface "pseudo"
+       commands.
+       (rip_interface_delete): Do not call if_delete() when interface is
+       pseudo interface.
+
+2000-07-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (ip_rip_authentication_mode): "ip rip
+       authentication mode (md5|text)" is added.
+       (ip_rip_authentication_key_chain): "ip rip authentication
+       key-chain KEY-CHAIN" is added.
+       (rip_interface_clean): Clean all interface configuration.
+       (rip_interface_reset): Reset all interface configuration.
+       (rip_clean_network): Clean rip_enable_network.
+
+       * ripd.h (struct rip_interface): Add key_chain member.
+
+       * ripd.c: Include md5-gnu.h.
+
+2000-07-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.h (RIP_NO_AUTH): Change RIP_NO_AUTH value from 1 to 0.
+
+       * ripd.c (rip_authentication): Use RIP_AUTH_SIMPLE_PASSWORD
+       instead of raw value 2.
+       (rip_write_rte): Likewise.
+       (rip_write_rte): Check ri->auth_type instead of ri->auth_str.
+
+2000-07-30  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_interface.c (rip_if_down): Do not delete ZEBRA_ROUTE_KERNEL
+       route.
+
+2000-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_update_process): Add "passive-interface" command.
+
+       * ripd.h (struct rip_interface): Add passive member to struct
+       rip_interface.
+
+2000-07-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (rip_if_init): Multiple RIP routes for one
+       prefix change.  The codes are enclosed by #ifdef NEW_RIP_TABLE.
+
+2000-07-24  Akihiro Mizutani <mizutani@dml.com>
+
+       * rip_interface.c (rip_if_init): Use install_default() for
+       INTERFACE_NODE.
+
+2000-07-24  Kunihiro Ishiguro <kunihiro@zebra.org>
+
+       * ripd.c: First update timer will be invoked in two seconds.
+
+2000-07-09  Jochen Friedrich <jochen@scram.de>
+
+       * rip_snmp.c: Local function definitions to static.  Add INTEGER
+       ASN_INTEGER and TIMETICKS ASN_TIMETICKS definition.
+       (rip2PeerLookup): Peer with domain lookup implemented.
+       (rip2PeerTable): Temporary disable RIP2PEERLASTUPDATE value
+       support due to unknown SNMP agent startup time.
+
+2000-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.h: Sweep obsolete definitions.
+
+       * rip_interface.c (rip_split_horizon): Add "ip split-horizon"
+       command.
+
+       * ripd.c (rip_output_process): Remove split_horizon argument.
+       (rip_update_process): Likewise.
+
+       * ripd.h (struct rip_interface): Add split_horizon flag to struct
+       rip_interface.
+
+2000-07-04  Akihiro Mizutani <mizutani@dml.com>
+
+       * ripd.c (rip_version): Change VERSION to <1-2>.
+       Add "no version" command.
+
+2000-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_zebra.c (rip_redistribute_type_metric): "redistribute TYPE
+       metric <0-16>" command is added.
+
+       * rip_routemap.c (route_set_metric): Set metric_set when metric is
+       modified.
+
+       * ripd.h (struct rip_info): To check route-map set metric or not,
+       new member metric_set is added to struct rip_info.
+
+       * ripd.c (rip_route_process): Move metric handling code from
+       rip_response_process() to rip_route_process().
+       (rip_output_process): Set output offset-list metric.
+
+2000-07-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_offset.c (rip_offset_list): New file for offset-list.
+
+2000-07-02  Akihiro Mizutani <mizutani@dml.com>
+
+       * ripd.h (struct rip ): Add default_metric.
+
+       * ripd.c (rip_default_metric): "default-metric <1-16>" command is
+       added.
+       (config_write_rip): Change configuration order.
+       
+       * rip_zebra.c: Fix help strings.
+
+2000-07-02  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_interface.c (rip_if_init): Add IF_DELETE_HOOK.
+
+2000-07-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_output_process): If specified route-map does not
+       exist, it treated as deny all.
+
+2000-06-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_routemap.c (rip_route_map_init): Call rip_route_map_update
+       when route-map is deleted.
+
+2000-06-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_routemap.c (set_metric): For consistency with bgpd's set
+       metric, value range is set to <0-4294967295>.
+       
+2000-06-28  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_routemap.c (rip_route_map_update): Add check for rip is
+       enabled or not for avoid core dump.
+
+       * rip_debug.c (debug_rip_packet_direct): Fix bug of setting
+       rip_debug_packet flag.
+
+2000-06-13  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_interface.c (rip_interface_delete): All work is done in
+       rip_if_down().
+
+2000-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_redistribute_delete): Fix bug of missing
+       route_unlock_node() when redistribute route is not found.
+
+2000-06-05  Akihirof Mizutani <mizutani@dml.com>
+
+       * rip_debug.c (rip_debug_init): Disable show debugging in
+       VIEW_NODE like other protocol daemon.
+
+       * rip_routemap.c: Change command argument to more comprehensive.
+
+       METRIC       -> <0-16>
+       IFNAME       -> WORD
+       IP_ADDR      -> A.B.C.D
+       ACCSESS_LIST -> WORD
+
+2000-06-05  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_interface.c (rip_interface_delete): Delete all routes
+       include static and kernel through the interface , because even if
+       the interface is added again there is no guarantee that it will
+       get the same ifindex as before.
+
+2000-05-31  Akihirof Mizutani <mizutani@dml.com>
+
+       * rip_debug.c: Fix rip debug help string.
+
+2000-04-27  Mirko Karanovic <mkaranov@torsel.alcatel.com>
+
+       * rip_interface.c (rip_interface_down): Remove interface from
+       multicast group when interface goes down.
+
+2000-04-03  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_interface.c (rip_interface_down): Implemented rip functions
+       for interface up/down events: rip_interface_up() and
+       rip_interface_down()
+
+2000-03-16  David Lipovkov <davidl@nbase.co.il>
+
+       * rip_zebra.c (rip_zclient_init): Added rip functions for
+       interface up/down events.
+
+2000-02-15  Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp>
+
+       * ripd.c (rip_write_rte): "set metic" in route-map has no effect
+       for RIPv1 in ripd.  It worked fine for RIPv2.
+
+2000-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (show_ip_protocols_rip): Fix bug of "show ip protocls"
+       mis-display RIP version.
+
+       * ripd.h (struct rip_peer): Add timeout thread to rip_peer
+       structure.
+
+2000-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_peer.c: Add new file for supporting RIP peer.
+
+1999-12-26  David Lipovkov <davidl@nbase.co.il>
+
+       * ripd.c (rip_authentication): RIP authantication string is 16
+       bytes long.
+
+1999-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_read): Add check for minimum packet length.
+       Authentication check is moved from rip_process_response() to
+       rip_read().  Patch from David Lipovkov <davidl@nbase.co.il> is
+       applied then add rte number check by Kunihiro Ishiguro
+       <kunihiro@zebra.org>.
+
+1999-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_response_process): In case of packet is RIPv2 and
+       network is non zero and netmask is zero, apply netmask rule as
+       same as RIPv1.
+
+1999-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_timers): Fix bug of timers basic argument format.
+
+1999-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_snmp.c (rip2IfConfAddress): Forgot to include
+       RIP2IFCONFDOMAIN.
+
+1999-10-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.h (struct rip_peer): New structure added.
+
+1999-10-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_zebra.c (rip_zebra_ipv4_add): Increment
+       rip_global_route_changes when route change occur.
+       (rip_zebra_ipv4_delete): Likewise.
+
+       * ripd.c (rip_request_process): Increment rip_global_queries when
+       reply to the query is sent.
+
+1999-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_debug.c (rip_debug_reset): Reset function added.
+
+       * ripd.c (rip_update_process): Logging bug is fixed. 
+
+1999-10-10  Marc Boucher <marc@mbsi.ca>
+
+       * ripd.c (config_write_rip): Add config_write_distribute() call.
+
+1999-09-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_distribute_update): Fix bug of access-list
+       prefix-list updates.
+
+1999-09-10  VOP <vop@unity.net>
+
+       * rip_zebra.c: Add redistribute route-map feature.
+
+1999-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_response_process): Add check for given prefix is
+       given mask applied one.
+
+1999-09-03  VOP <vop@unity.net>
+
+       * rip_interface.c (rip_interface_multicast_set): Bug fix about
+       setting multicast interface.
+
+1999-09-02  VOP <vop@unity.net>
+
+       * rip_routemap.c: New file added.
+
+1999-09-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (show_ip_protocols_rip): Show next update time.
+       (show_ip_protocols_rip): Show redistribute information.
+
+1999-08-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * RIPv2-MIB.txt: New file added.
+
+       * rip_snmp.c: New file added.
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (ip_rip_authentication_string): RIPv2
+       authentication command is added.
+
+1999-08-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (rip_interface_multicast_set): Process of
+       setting IP_MULTICAST_IF on specific interface.
+
+       * ripd.c (rip_read): Add packet size check.
+
+1999-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_request_process): Fill in RIP_METRIC_INFINITY with
+       network byte order using htonl ().
+       (rip_response_process): Pass host byte order address to IN_CLASSC
+       and IN_CLASSB macro.
+
+1999-08-08  davidm@nbase.co.il (David Mozes)
+
+       * rip_zebra.c (rip_zebra_read_ipv4): Fix split horizon problem.
+
+1999-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_timer_set): Function added.
+
+1999-07-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_debug.c: New file added.
+       rip_debug.h: New file added.
+
+1999-07-01  Rick Payne <rickp@rossfell.co.uk>
+
+       * rip_zebra.c (zebra_init): Install standard commands to
+       ZEBRA_NODE.
+
+1999-06-01  David Luyer <luyer@ucs.uwa.edu.au>
+
+       * ripd.c (rip_process_route): Add support for RIP version 1.
+
+1999-05-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_zebra.c: Change to use lib/zclient.[ch].
+
+1999-05-20  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * ripd.c (rip_add_route): Change the existance route's metric check
+          to the condition specified by RFC2453. 
+       
+1999-05-17  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * ripd.c (rip_process_route): Add the if metric to the route metric.
+
+       * ripd.c (rip_add_route): Deleted add if metric to the route.
+
+1999-05-16  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * rip_interface.c (if_valid_neighbor): New function.
+
+       * ripd.c (rip_process_route): Added check whether the datagram
+       is from a valid neighbor.
+       
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_process_route): Set interface pointer to rinfo.
+
+1999-05-15  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * ripd.c (rip_check_address): Unicast and not net 0 or 127 check
+       added.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+       * rip_main.c (signal_init): SIGTERM call sigint.
+       (sigint): Loggging more better message.
+
+1999-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_add_route): Fix previous route_unlock_node() chenge.
+
+       * rip_main.c (main): Change default zlog output to ZLOG_STDOUT for
+       debugging.
+
+1999-05-09  Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+       * rip_interface.c (rip_request): Fix old semantics for fetching
+       connected address.
+
+       * ripd.c (rip_add_route): Update timer when the route is updated.
+
+1999-05-09  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+       * rip_zebra.c (struct zebra): Add ridist_static, ridist_connect,
+       redist_rip, redist_ripng.  
+
+       * rip_zebra.c (zebra_create): Updated for current zebra method.
+
+       * ripd.c (rip_add_route): Add missing route_unlock_node().
+
+1999-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_add_route): Add metric check.  Reported by Carlos
+       Alberto Barcenilla <barce@frlp.utn.edu.ar>.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * syslog support added
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_announce_func): Apply new lib functions.
+
+1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (config_write_rip): Delete vector v argument.
+       * rip_zebra.c (config_write_zebra): Likewise.
+       * rip_interface.c (interface_config_write): Likewise.
+
+1998-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_announce.c (rip_rib_close): When ripd terminates delete all
+       added route.
+
+1998-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c: return read packet size.
+
+1998-05-18  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * ripd.h: Modify for compile on Solaris.
+
+1998-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c: DEFUN function return CMD_SUCCESS.
+                 change xmalloc to XMALLOC macro.
+       
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_main.c: change CONFDIR to SYSCONFDIR.
+
+1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * .cvsignore: added.
+
+1998-02-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (config_write_interface): correct ADVERTISE spell.
+
+       * rip_main.c (main): add usage() and make cleanup.
+
+1998-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripd.c (rip_version): add rip version command.
+
+1998-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rip_interface.c (zebra_get_interface): added to get
+       interface's information.
+
+       * ChangeLog: create.
diff --git a/ripd/Makefile.am b/ripd/Makefile.am
new file mode 100644 (file)
index 0000000..fd25485
--- /dev/null
@@ -0,0 +1,37 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = librip.a
+sbin_PROGRAMS = ripd
+
+librip_a_SOURCES = \
+       ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \
+       rip_routemap.c rip_peer.c rip_offset.c
+
+noinst_HEADERS = \
+       ripd.h rip_debug.h
+
+ripd_SOURCES = \
+       rip_main.c $(librip_a_SOURCES)
+
+ripd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ripd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
diff --git a/ripd/Makefile.in b/ripd/Makefile.in
new file mode 100644 (file)
index 0000000..fa355ef
--- /dev/null
@@ -0,0 +1,489 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = librip.a
+sbin_PROGRAMS = ripd
+
+librip_a_SOURCES = \
+       ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \
+       rip_routemap.c rip_peer.c rip_offset.c
+
+
+noinst_HEADERS = \
+       ripd.h rip_debug.h
+
+
+ripd_SOURCES = \
+       rip_main.c $(librip_a_SOURCES)
+
+
+ripd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ripd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt
+subdir = ripd
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+librip_a_AR = $(AR) cru
+librip_a_LIBADD =
+am_librip_a_OBJECTS = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \
+       rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \
+       rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT)
+librip_a_OBJECTS = $(am_librip_a_OBJECTS)
+sbin_PROGRAMS = ripd$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \
+       rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \
+       rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT)
+am_ripd_OBJECTS = rip_main.$(OBJEXT) $(am__objects_1)
+ripd_OBJECTS = $(am_ripd_OBJECTS)
+ripd_DEPENDENCIES = ../lib/libzebra.a
+ripd_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/rip_debug.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/rip_interface.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/rip_main.Po ./$(DEPDIR)/rip_offset.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/rip_peer.Po ./$(DEPDIR)/rip_routemap.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/rip_snmp.Po ./$(DEPDIR)/rip_zebra.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ripd.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  ripd/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+librip.a: $(librip_a_OBJECTS) $(librip_a_DEPENDENCIES) 
+       -rm -f librip.a
+       $(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD)
+       $(RANLIB) librip.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sbindir)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+         rm -f $(DESTDIR)$(sbindir)/$$f; \
+       done
+
+clean-sbinPROGRAMS:
+       -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ripd$(EXEEXT): $(ripd_OBJECTS) $(ripd_DEPENDENCIES) 
+       @rm -f ripd$(EXEEXT)
+       $(LINK) $(ripd_LDFLAGS) $(ripd_OBJECTS) $(ripd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_offset.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_peer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripd.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+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 =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-noinstLIBRARIES clean-sbinPROGRAMS ctags 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 pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ripd/RIPv2-MIB.txt b/ripd/RIPv2-MIB.txt
new file mode 100644 (file)
index 0000000..6c92fb5
--- /dev/null
@@ -0,0 +1,530 @@
+   RIPv2-MIB DEFINITIONS ::= BEGIN
+
+   IMPORTS
+       MODULE-IDENTITY, OBJECT-TYPE, Counter32,
+       TimeTicks, IpAddress                     FROM SNMPv2-SMI
+       TEXTUAL-CONVENTION, RowStatus            FROM SNMPv2-TC
+       MODULE-COMPLIANCE, OBJECT-GROUP          FROM SNMPv2-CONF
+       mib-2                                    FROM RFC1213-MIB;
+
+   --  This MIB module uses the extended OBJECT-TYPE macro as
+   --  defined in [9].
+
+   rip2  MODULE-IDENTITY
+           LAST-UPDATED "9407272253Z"      -- Wed Jul 27 22:53:04 PDT 1994
+           ORGANIZATION "IETF RIP-II Working Group"
+           CONTACT-INFO
+          "       Fred Baker
+          Postal: Cisco Systems
+                  519 Lado Drive
+                  Santa Barbara, California 93111
+          Tel:    +1 805 681 0115
+          E-Mail: fbaker@cisco.com
+
+          Postal: Gary Malkin
+                  Xylogics, Inc.
+                  53 Third Avenue
+                  Burlington, MA  01803
+
+          Phone:  (617) 272-8140
+          EMail:  gmalkin@Xylogics.COM"
+      DESCRIPTION
+         "The MIB module to describe the RIP2 Version 2 Protocol"
+     ::= { mib-2 23 }
+
+ --  RIP-2 Management Information Base
+
+ -- the RouteTag type represents the contents of the
+ -- Route Domain field in the packet header or route entry.
+ -- The use of the Route Domain is deprecated.
+
+ RouteTag ::= TEXTUAL-CONVENTION
+     STATUS      current
+     DESCRIPTION
+        "the RouteTag type represents the contents of the Route Domain
+        field in the packet header or route entry"
+    SYNTAX      OCTET STRING (SIZE (2))
+
+--4.1 Global Counters
+
+--      The RIP-2 Globals Group.
+--      Implementation of this group is mandatory for systems
+--      which implement RIP-2.
+
+-- These counters are intended to facilitate debugging quickly
+-- changing routes or failing neighbors
+
+rip2Globals OBJECT IDENTIFIER ::= { rip2 1 }
+
+    rip2GlobalRouteChanges OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of route changes made to the IP Route
+           Database by RIP.  This does not include the refresh
+           of a route's age."
+       ::= { rip2Globals 1 }
+
+    rip2GlobalQueries OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of responses sent to RIP queries
+           from other systems."
+       ::= { rip2Globals 2 }
+
+--4.2 RIP Interface Tables
+
+--  RIP Interfaces Groups
+--  Implementation of these Groups is mandatory for systems
+--  which implement RIP-2.
+
+-- The RIP Interface Status Table.
+
+    rip2IfStatTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF Rip2IfStatEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A list of subnets which require separate
+           status monitoring in RIP."
+       ::= { rip2 2 }
+
+   rip2IfStatEntry OBJECT-TYPE
+       SYNTAX   Rip2IfStatEntry
+       MAX-ACCESS   not-accessible
+       STATUS   current
+       DESCRIPTION
+          "A Single Routing Domain in a single Subnet."
+      INDEX { rip2IfStatAddress }
+      ::= { rip2IfStatTable 1 }
+
+    Rip2IfStatEntry ::=
+        SEQUENCE {
+            rip2IfStatAddress
+                IpAddress,
+            rip2IfStatRcvBadPackets
+                Counter32,
+            rip2IfStatRcvBadRoutes
+                Counter32,
+            rip2IfStatSentUpdates
+                Counter32,
+            rip2IfStatStatus
+                RowStatus
+    }
+
+    rip2IfStatAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of this system on the indicated
+           subnet. For unnumbered interfaces, the value 0.0.0.N,
+           where the least significant 24 bits (N) is the ifIndex
+           for the IP Interface in network byte order."
+       ::= { rip2IfStatEntry 1 }
+
+    rip2IfStatRcvBadPackets OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of RIP response packets received by
+           the RIP process which were subsequently discarded
+           for any reason (e.g. a version 0 packet, or an
+           unknown command type)."
+       ::= { rip2IfStatEntry 2 }
+
+    rip2IfStatRcvBadRoutes OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of routes, in valid RIP packets,
+           which were ignored for any reason (e.g. unknown
+           address family, or invalid metric)."
+       ::= { rip2IfStatEntry 3 }
+
+    rip2IfStatSentUpdates OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of triggered RIP updates actually
+           sent on this interface.  This explicitly does
+           NOT include full updates sent containing new
+           information."
+       ::= { rip2IfStatEntry 4 }
+
+    rip2IfStatStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "Writing invalid has the effect of deleting
+           this interface."
+       ::= { rip2IfStatEntry 5 }
+
+-- The RIP Interface Configuration Table.
+
+    rip2IfConfTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF Rip2IfConfEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A list of subnets which require separate
+           configuration in RIP."
+       ::= { rip2 3 }
+
+   rip2IfConfEntry OBJECT-TYPE
+       SYNTAX   Rip2IfConfEntry
+       MAX-ACCESS   not-accessible
+       STATUS   current
+       DESCRIPTION
+          "A Single Routing Domain in a single Subnet."
+      INDEX { rip2IfConfAddress }
+      ::= { rip2IfConfTable 1 }
+
+    Rip2IfConfEntry ::=
+        SEQUENCE {
+            rip2IfConfAddress
+                IpAddress,
+            rip2IfConfDomain
+                RouteTag,
+            rip2IfConfAuthType
+                INTEGER,
+            rip2IfConfAuthKey
+                OCTET STRING (SIZE(0..16)),
+            rip2IfConfSend
+                INTEGER,
+            rip2IfConfReceive
+                INTEGER,
+            rip2IfConfDefaultMetric
+                INTEGER,
+            rip2IfConfStatus
+                RowStatus,
+            rip2IfConfSrcAddress
+                IpAddress
+    }
+
+    rip2IfConfAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of this system on the indicated
+           subnet.  For unnumbered interfaces, the value 0.0.0.N,
+           where the least significant 24 bits (N) is the ifIndex
+           for the IP Interface in network byte order."
+       ::= { rip2IfConfEntry 1 }
+
+    rip2IfConfDomain OBJECT-TYPE
+        SYNTAX   RouteTag
+        MAX-ACCESS   read-create
+        STATUS   obsolete
+        DESCRIPTION
+           "Value inserted into the Routing Domain field
+           of all RIP packets sent on this interface."
+       DEFVAL { '0000'h }
+       ::= { rip2IfConfEntry 2 }
+
+    rip2IfConfAuthType OBJECT-TYPE
+        SYNTAX   INTEGER {
+                    noAuthentication (1),
+                    simplePassword (2),
+                    md5 (3)
+                 }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The type of Authentication used on this
+           interface."
+       DEFVAL { noAuthentication }
+       ::= { rip2IfConfEntry 3 }
+
+    rip2IfConfAuthKey OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE(0..16))
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The value to be used as the Authentication Key
+           whenever the corresponding instance of
+           rip2IfConfAuthType has a value other than
+           noAuthentication.  A modification of the corresponding
+           instance of rip2IfConfAuthType does not modify
+           the rip2IfConfAuthKey value.  If a string shorter
+           than 16 octets is supplied, it will be left-
+           justified and padded to 16 octets, on the right,
+           with nulls (0x00).
+
+           Reading this object always results in an  OCTET
+           STRING of length zero; authentication may not
+           be bypassed by reading the MIB object."
+       DEFVAL { ''h }
+       ::= { rip2IfConfEntry 4 }
+
+    rip2IfConfSend OBJECT-TYPE
+        SYNTAX   INTEGER {
+                    doNotSend (1),
+                    ripVersion1 (2),
+                    rip1Compatible (3),
+                    ripVersion2 (4),
+                    ripV1Demand (5),
+                    ripV2Demand (6)
+                 }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "What the router sends on this interface.
+           ripVersion1 implies sending RIP updates compliant
+           with  RFC  1058.   rip1Compatible implies
+           broadcasting RIP-2 updates using RFC 1058 route
+           subsumption rules.  ripVersion2 implies
+           multicasting RIP-2 updates.  ripV1Demand indicates
+           the use of Demand RIP on a WAN interface under RIP
+           Version 1 rules.  ripV2Demand indicates the use of
+           Demand RIP on a WAN interface under Version 2 rules."
+       DEFVAL { rip1Compatible }
+       ::= { rip2IfConfEntry 5 }
+
+    rip2IfConfReceive OBJECT-TYPE
+        SYNTAX   INTEGER {
+                    rip1 (1),
+                    rip2 (2),
+                    rip1OrRip2 (3),
+                    doNotRecieve (4)
+                 }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This indicates which version of RIP updates
+           are to be accepted.  Note that rip2 and
+           rip1OrRip2 implies reception of multicast
+           packets."
+       DEFVAL { rip1OrRip2 }
+       ::= { rip2IfConfEntry 6 }
+
+    rip2IfConfDefaultMetric OBJECT-TYPE
+        SYNTAX   INTEGER ( 0..15 )
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable indicates the metric that is to
+           be used for the default route entry in RIP updates
+           originated on this interface.  A value of zero
+           indicates that no default route should be
+           originated; in this case, a default route via
+           another router may be propagated."
+       ::= { rip2IfConfEntry 7 }
+
+    rip2IfConfStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "Writing invalid has  the  effect  of  deleting
+           this interface."
+       ::= { rip2IfConfEntry 8 }
+
+    rip2IfConfSrcAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The IP Address this system will use as a source
+            address on this interface.  If it is a numbered
+            interface, this MUST be the same value as
+            rip2IfConfAddress.  On unnumbered interfaces,
+            it must be the value of rip2IfConfAddress for
+            some interface on the system."
+       ::= { rip2IfConfEntry 9 }
+
+--4.3 Peer Table
+
+--  Peer Table
+
+--      The RIP Peer Group
+--      Implementation of this Group is Optional
+
+--      This group provides information about active peer
+--      relationships intended to assist in debugging.  An
+--      active peer is a router from which a valid RIP
+--      updated has been heard in the last 180 seconds.
+
+    rip2PeerTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF Rip2PeerEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A list of RIP Peers."
+       ::= { rip2 4 }
+
+   rip2PeerEntry OBJECT-TYPE
+       SYNTAX   Rip2PeerEntry
+       MAX-ACCESS   not-accessible
+       STATUS   current
+       DESCRIPTION
+          "Information regarding a single routing peer."
+      INDEX { rip2PeerAddress, rip2PeerDomain }
+      ::= { rip2PeerTable 1 }
+
+    Rip2PeerEntry ::=
+        SEQUENCE {
+            rip2PeerAddress
+                IpAddress,
+            rip2PeerDomain
+                RouteTag,
+            rip2PeerLastUpdate
+                TimeTicks,
+            rip2PeerVersion
+                INTEGER,
+            rip2PeerRcvBadPackets
+                Counter32,
+            rip2PeerRcvBadRoutes
+                Counter32
+            }
+
+    rip2PeerAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address that the peer is using as its source
+            address.  Note that on an unnumbered link, this may
+            not be a member of any subnet on the system."
+       ::= { rip2PeerEntry 1 }
+
+    rip2PeerDomain OBJECT-TYPE
+        SYNTAX   RouteTag
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The value in the Routing Domain field  in  RIP
+           packets received from the peer.  As domain suuport
+           is deprecated, this must be zero."
+       ::= { rip2PeerEntry 2 }
+
+    rip2PeerLastUpdate OBJECT-TYPE
+        SYNTAX   TimeTicks
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The value of sysUpTime when the most recent
+           RIP update was received from this system."
+       ::= { rip2PeerEntry 3 }
+
+    rip2PeerVersion OBJECT-TYPE
+        SYNTAX   INTEGER ( 0..255 )
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The RIP version number in the header of the
+           last RIP packet received."
+       ::= { rip2PeerEntry 4 }
+
+    rip2PeerRcvBadPackets OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of RIP response packets from this
+           peer discarded as invalid."
+       ::= { rip2PeerEntry 5 }
+
+
+    rip2PeerRcvBadRoutes OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of routes from this peer that were
+           ignored because the entry format was invalid."
+       ::= { rip2PeerEntry 6 }
+
+-- conformance information
+
+rip2Conformance OBJECT IDENTIFIER ::= { rip2 5 }
+
+rip2Groups      OBJECT IDENTIFIER ::= { rip2Conformance 1 }
+rip2Compliances OBJECT IDENTIFIER ::= { rip2Conformance 2 }
+
+-- compliance statements
+rip2Compliance MODULE-COMPLIANCE
+    STATUS  current
+    DESCRIPTION
+       "The compliance statement "
+    MODULE  -- this module
+    MANDATORY-GROUPS {
+                 rip2GlobalGroup,
+                 rip2IfStatGroup,
+                 rip2IfConfGroup,
+                 rip2PeerGroup
+        }
+    GROUP       rip2GlobalGroup
+    DESCRIPTION
+       "This group defines global controls for RIP-II systems."
+    GROUP       rip2IfStatGroup
+    DESCRIPTION
+       "This group defines interface statistics for RIP-II systems."
+    GROUP       rip2IfConfGroup
+    DESCRIPTION
+       "This group defines interface configuration for RIP-II systems."
+    GROUP       rip2PeerGroup
+    DESCRIPTION
+       "This group defines peer information for RIP-II systems."
+    ::= { rip2Compliances 1 }
+
+-- units of conformance
+
+rip2GlobalGroup    OBJECT-GROUP
+    OBJECTS {
+                rip2GlobalRouteChanges,
+                rip2GlobalQueries
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines global controls for RIP-II systems."
+    ::= { rip2Groups 1 }
+rip2IfStatGroup    OBJECT-GROUP
+    OBJECTS {
+            rip2IfStatAddress,
+            rip2IfStatRcvBadPackets,
+            rip2IfStatRcvBadRoutes,
+            rip2IfStatSentUpdates,
+            rip2IfStatStatus
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines interface statistics for RIP-II systems."
+    ::= { rip2Groups 2 }
+rip2IfConfGroup    OBJECT-GROUP
+    OBJECTS {
+            rip2IfConfAddress,
+            rip2IfConfAuthType,
+            rip2IfConfAuthKey,
+            rip2IfConfSend,
+            rip2IfConfReceive,
+            rip2IfConfDefaultMetric,
+            rip2IfConfStatus,
+            rip2IfConfSrcAddress
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines interface configuration for RIP-II systems."
+    ::= { rip2Groups 3 }
+rip2PeerGroup    OBJECT-GROUP
+    OBJECTS {
+            rip2PeerAddress,
+            rip2PeerDomain,
+            rip2PeerLastUpdate,
+            rip2PeerVersion,
+            rip2PeerRcvBadPackets,
+            rip2PeerRcvBadRoutes
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines peer information for RIP-II systems."
+    ::= { rip2Groups 4 }
+END
diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c
new file mode 100644 (file)
index 0000000..4f09200
--- /dev/null
@@ -0,0 +1,290 @@
+/* RIP debug routines
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+#include "command.h"
+#include "ripd/rip_debug.h"
+
+/* For debug statement. */
+unsigned long rip_debug_event = 0;
+unsigned long rip_debug_packet = 0;
+unsigned long rip_debug_zebra = 0;
+\f
+DEFUN (show_debugging_rip,
+       show_debugging_rip_cmd,
+       "show debugging rip",
+       SHOW_STR
+       DEBUG_STR
+       RIP_STR)
+{
+  vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+  if (IS_RIP_DEBUG_EVENT)
+    vty_out (vty, "  RIP event debugging is on%s", VTY_NEWLINE);
+
+  if (IS_RIP_DEBUG_PACKET)
+    {
+      if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV)
+       {
+         vty_out (vty, "  RIP packet%s debugging is on%s",
+                  IS_RIP_DEBUG_DETAIL ? " detail" : "",
+                  VTY_NEWLINE);
+       }
+      else
+       {
+         if (IS_RIP_DEBUG_SEND)
+           vty_out (vty, "  RIP packet send%s debugging is on%s",
+                    IS_RIP_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, "  RIP packet receive%s debugging is on%s",
+                    IS_RIP_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+       }
+    }
+
+  if (IS_RIP_DEBUG_ZEBRA)
+    vty_out (vty, "  RIP zebra debugging is on%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_events,
+       debug_rip_events_cmd,
+       "debug rip events",
+       DEBUG_STR
+       RIP_STR
+       "RIP events\n")
+{
+  rip_debug_event = RIP_DEBUG_EVENT;
+  return CMD_WARNING;
+}
+
+DEFUN (debug_rip_packet,
+       debug_rip_packet_cmd,
+       "debug rip packet",
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n")
+{
+  rip_debug_packet = RIP_DEBUG_PACKET;
+  rip_debug_packet |= RIP_DEBUG_SEND;
+  rip_debug_packet |= RIP_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_packet_direct,
+       debug_rip_packet_direct_cmd,
+       "debug rip packet (recv|send)",
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n"
+       "RIP receive packet\n"
+       "RIP send packet\n")
+{
+  rip_debug_packet |= RIP_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_RECV;
+  rip_debug_packet &= ~RIP_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_packet_detail,
+       debug_rip_packet_detail_cmd,
+       "debug rip packet (recv|send) detail",
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n"
+       "RIP receive packet\n"
+       "RIP send packet\n"
+       "Detailed information display\n")
+{
+  rip_debug_packet |= RIP_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_RECV;
+  rip_debug_packet |= RIP_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_zebra,
+       debug_rip_zebra_cmd,
+       "debug rip zebra",
+       DEBUG_STR
+       RIP_STR
+       "RIP and ZEBRA communication\n")
+{
+  rip_debug_zebra = RIP_DEBUG_ZEBRA;
+  return CMD_WARNING;
+}
+
+DEFUN (no_debug_rip_events,
+       no_debug_rip_events_cmd,
+       "no debug rip events",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP events\n")
+{
+  rip_debug_event = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_rip_packet,
+       no_debug_rip_packet_cmd,
+       "no debug rip packet",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n")
+{
+  rip_debug_packet = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_rip_packet_direct,
+       no_debug_rip_packet_direct_cmd,
+       "no debug rip packet (recv|send)",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n"
+       "RIP option set for receive packet\n"
+       "RIP option set for send packet\n")
+{
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    {
+      if (IS_RIP_DEBUG_RECV)
+       rip_debug_packet &= ~RIP_DEBUG_SEND;
+      else
+       rip_debug_packet = 0;
+    }
+  else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    {
+      if (IS_RIP_DEBUG_SEND)
+       rip_debug_packet &= ~RIP_DEBUG_RECV;
+      else
+       rip_debug_packet = 0;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_rip_zebra,
+       no_debug_rip_zebra_cmd,
+       "no debug rip zebra",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP and ZEBRA communication\n")
+{
+  rip_debug_zebra = 0;
+  return CMD_WARNING;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  "",                          /* Debug node has no interface. */
+  1
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+  int write = 0;
+
+  if (IS_RIP_DEBUG_EVENT)
+    {
+      vty_out (vty, "debug rip events%s", VTY_NEWLINE);
+      write++;
+    }
+  if (IS_RIP_DEBUG_PACKET)
+    {
+      if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV)
+       {
+         vty_out (vty, "debug rip packet%s%s",
+                  IS_RIP_DEBUG_DETAIL ? " detail" : "",
+                  VTY_NEWLINE);
+         write++;
+       }
+      else
+       {
+         if (IS_RIP_DEBUG_SEND)
+           vty_out (vty, "debug rip packet send%s%s",
+                    IS_RIP_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, "debug rip packet recv%s%s",
+                    IS_RIP_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         write++;
+       }
+    }
+  if (IS_RIP_DEBUG_ZEBRA)
+    {
+      vty_out (vty, "debug rip zebra%s", VTY_NEWLINE);
+      write++;
+    }
+  return write;
+}
+
+void
+rip_debug_reset ()
+{
+  rip_debug_event = 0;
+  rip_debug_packet = 0;
+  rip_debug_zebra = 0;
+}
+
+void
+rip_debug_init ()
+{
+  rip_debug_event = 0;
+  rip_debug_packet = 0;
+  rip_debug_zebra = 0;
+
+  install_node (&debug_node, config_write_debug);
+
+  install_element (ENABLE_NODE, &show_debugging_rip_cmd);
+  install_element (ENABLE_NODE, &debug_rip_events_cmd);
+  install_element (ENABLE_NODE, &debug_rip_packet_cmd);
+  install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd);
+  install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd);
+  install_element (ENABLE_NODE, &debug_rip_zebra_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_events_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_packet_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd);
+
+  install_element (CONFIG_NODE, &debug_rip_events_cmd);
+  install_element (CONFIG_NODE, &debug_rip_packet_cmd);
+  install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd);
+  install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd);
+  install_element (CONFIG_NODE, &debug_rip_zebra_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_events_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_packet_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd);
+}
diff --git a/ripd/rip_debug.h b/ripd/rip_debug.h
new file mode 100644 (file)
index 0000000..3b44d0c
--- /dev/null
@@ -0,0 +1,54 @@
+/* RIP debug routines
+ * Copyright (C) 1999 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.  
+ */
+
+#ifndef _ZEBRA_RIP_DEBUG_H
+#define _ZEBRA_RIP_DEBUG_H
+
+/* RIP debug event flags. */
+#define RIP_DEBUG_EVENT   0x01
+
+/* RIP debug packet flags. */
+#define RIP_DEBUG_PACKET  0x01
+#define RIP_DEBUG_SEND    0x20
+#define RIP_DEBUG_RECV    0x40
+#define RIP_DEBUG_DETAIL  0x80
+
+/* RIP debug zebra flags. */
+#define RIP_DEBUG_ZEBRA   0x01
+
+/* Debug related macro. */
+#define IS_RIP_DEBUG_EVENT  (rip_debug_event & RIP_DEBUG_EVENT)
+
+#define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET)
+#define IS_RIP_DEBUG_SEND   (rip_debug_packet & RIP_DEBUG_SEND)
+#define IS_RIP_DEBUG_RECV   (rip_debug_packet & RIP_DEBUG_RECV)
+#define IS_RIP_DEBUG_DETAIL (rip_debug_packet & RIP_DEBUG_DETAIL)
+
+#define IS_RIP_DEBUG_ZEBRA  (rip_debug_zebra & RIP_DEBUG_ZEBRA)
+
+extern unsigned long rip_debug_event;
+extern unsigned long rip_debug_packet;
+extern unsigned long rip_debug_zebra;
+
+void rip_debug_init ();
+void rip_debug_reset ();
+
+#endif /* _ZEBRA_RIP_DEBUG_H */
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
new file mode 100644 (file)
index 0000000..06d4416
--- /dev/null
@@ -0,0 +1,2001 @@
+/* Interface related function for RIP.
+ * Copyright (C) 1997, 98 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.  
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "memory.h"
+#include "network.h"
+#include "table.h"
+#include "log.h"
+#include "stream.h"
+#include "thread.h"
+#include "zclient.h"
+#include "filter.h"
+#include "sockopt.h"
+
+#include "zebra/connected.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+void rip_enable_apply (struct interface *);
+void rip_passive_interface_apply (struct interface *);
+int rip_if_down(struct interface *ifp);
+
+struct message ri_version_msg[] = 
+{
+  {RI_RIP_VERSION_1,       "1"},
+  {RI_RIP_VERSION_2,       "2"},
+  {RI_RIP_VERSION_1_AND_2, "1 2"},
+  {0,                      NULL}
+};
+
+/* RIP enabled network vector. */
+vector rip_enable_interface;
+
+/* RIP enabled interface table. */
+struct route_table *rip_enable_network;
+
+/* Vector to store passive-interface name. */
+vector Vrip_passive_interface;
+\f
+/* Join to the RIP version 2 multicast group. */
+int
+ipv4_multicast_join (int sock, 
+                    struct in_addr group, 
+                    struct in_addr ifa,
+                    unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (sock, 
+                                  IP_ADD_MEMBERSHIP, 
+                                  ifa, 
+                                  group.s_addr, 
+                                  ifindex); 
+
+  if (ret < 0) 
+    zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s",
+         strerror (errno));
+
+  return ret;
+}
+
+/* Leave from the RIP version 2 multicast group. */
+int
+ipv4_multicast_leave (int sock, 
+                     struct in_addr group, 
+                     struct in_addr ifa,
+                     unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (sock, 
+                                  IP_DROP_MEMBERSHIP, 
+                                  ifa, 
+                                  group.s_addr, 
+                                  ifindex);
+
+  if (ret < 0) 
+    zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP");
+
+  return ret;
+}
+\f
+/* Allocate new RIP's interface configuration. */
+struct rip_interface *
+rip_interface_new ()
+{
+  struct rip_interface *ri;
+
+  ri = XMALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface));
+  memset (ri, 0, sizeof (struct rip_interface));
+
+  /* Default authentication type is simple password for Cisco
+     compatibility. */
+  /* ri->auth_type = RIP_NO_AUTH; */
+  ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+  /* Set default split-horizon behavior.  If the interface is Frame
+     Relay or SMDS is enabled, the default value for split-horizon is
+     off.  But currently Zebra does detect Frame Relay or SMDS
+     interface.  So all interface is set to split horizon.  */
+  ri->split_horizon_default = 1;
+  ri->split_horizon = ri->split_horizon_default;
+
+  return ri;
+}
+
+void
+rip_interface_multicast_set (int sock, struct interface *ifp)
+{
+  int ret;
+  listnode node;
+  struct servent *sp;
+  struct sockaddr_in from;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      struct prefix_ipv4 *p;
+      struct connected *connected;
+      struct in_addr addr;
+
+      connected = getdata (node);
+      p = (struct prefix_ipv4 *) connected->address;
+
+      if (p->family == AF_INET)
+       {
+         addr = p->prefix;
+
+         if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
+                                        addr, 0, ifp->ifindex) < 0) 
+           {
+             zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
+             return;
+           }
+
+         /* Bind myself. */
+         memset (&from, 0, sizeof (struct sockaddr_in));
+
+         /* Set RIP port. */
+         sp = getservbyname ("router", "udp");
+         if (sp) 
+           from.sin_port = sp->s_port;
+         else 
+           from.sin_port = htons (RIP_PORT_DEFAULT);
+
+         /* Address shoud be any address. */
+         from.sin_family = AF_INET;
+         from.sin_addr = addr;
+#ifdef HAVE_SIN_LEN
+         from.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+         ret = bind (sock, (struct sockaddr *) & from, 
+                     sizeof (struct sockaddr_in));
+         if (ret < 0)
+           {
+             zlog_warn ("Can't bind socket: %s", strerror (errno));
+             return;
+           }
+
+         return;
+
+       }
+    }
+}
+
+/* Send RIP request packet to specified interface. */
+void
+rip_request_interface_send (struct interface *ifp, u_char version)
+{
+  struct sockaddr_in to;
+
+  /* RIPv2 support multicast. */
+  if (version == RIPv2 && if_is_multicast (ifp))
+    {
+      
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("multicast request on %s", ifp->name);
+
+      rip_request_send (NULL, ifp, version);
+      return;
+    }
+
+  /* RIPv1 and non multicast interface. */
+  if (if_is_pointopoint (ifp) || if_is_broadcast (ifp))
+    {
+      listnode cnode;
+
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("broadcast request to %s", ifp->name);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         struct prefix_ipv4 *p;
+         struct connected *connected;
+
+         connected = getdata (cnode);
+         p = (struct prefix_ipv4 *) connected->destination;
+
+         if (p->family == AF_INET)
+           {
+             memset (&to, 0, sizeof (struct sockaddr_in));
+             to.sin_port = htons (RIP_PORT_DEFAULT);
+             to.sin_addr = p->prefix;
+
+#if 0
+             if (IS_RIP_DEBUG_EVENT)
+               zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr));
+#endif /* 0 */
+             
+             rip_request_send (&to, ifp, version);
+           }
+       }
+    }
+}
+
+/* This will be executed when interface goes up. */
+void
+rip_request_interface (struct interface *ifp)
+{
+  struct rip_interface *ri;
+
+  /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
+  if (if_is_loopback (ifp))
+    return;
+
+  /* If interface is down, don't send RIP packet. */
+  if (! if_is_up (ifp))
+    return;
+
+  /* Fetch RIP interface information. */
+  ri = ifp->info;
+
+
+  /* If there is no version configuration in the interface,
+     use rip's version setting. */
+  if (ri->ri_send == RI_RIP_UNSPEC)
+    {
+      if (rip->version == RIPv1)
+       rip_request_interface_send (ifp, RIPv1);
+      else
+       rip_request_interface_send (ifp, RIPv2);
+    }
+  /* If interface has RIP version configuration use it. */
+  else
+    {
+      if (ri->ri_send & RIPv1)
+       rip_request_interface_send (ifp, RIPv1);
+      if (ri->ri_send & RIPv2)
+       rip_request_interface_send (ifp, RIPv2);
+    }
+}
+
+/* Send RIP request to the neighbor. */
+void
+rip_request_neighbor (struct in_addr addr)
+{
+  struct sockaddr_in to;
+
+  memset (&to, 0, sizeof (struct sockaddr_in));
+  to.sin_port = htons (RIP_PORT_DEFAULT);
+  to.sin_addr = addr;
+
+  rip_request_send (&to, NULL, rip->version);
+}
+
+/* Request routes at all interfaces. */
+void
+rip_request_neighbor_all ()
+{
+  struct route_node *rp;
+
+  if (! rip)
+    return;
+
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("request to the all neighbor");
+
+  /* Send request to all neighbor. */
+  for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
+    if (rp->info)
+      rip_request_neighbor (rp->p.u.prefix4);
+}
+
+/* Multicast packet receive socket. */
+int
+rip_multicast_join (struct interface *ifp, int sock)
+{
+  listnode cnode;
+
+  if (if_is_up (ifp) && if_is_multicast (ifp))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("multicast join at %s", ifp->name);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         struct prefix_ipv4 *p;
+         struct connected *connected;
+         struct in_addr group;
+             
+         connected = getdata (cnode);
+         p = (struct prefix_ipv4 *) connected->address;
+      
+         if (p->family != AF_INET)
+           continue;
+      
+         group.s_addr = htonl (INADDR_RIP_GROUP);
+         if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0)
+           return -1;
+         else
+           return 0;
+       }
+    }
+  return 0;
+}
+
+/* Leave from multicast group. */
+void
+rip_multicast_leave (struct interface *ifp, int sock)
+{
+  listnode cnode;
+
+  if (if_is_up (ifp) && if_is_multicast (ifp))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("multicast leave from %s", ifp->name);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         struct prefix_ipv4 *p;
+         struct connected *connected;
+         struct in_addr group;
+             
+         connected = getdata (cnode);
+         p = (struct prefix_ipv4 *) connected->address;
+      
+         if (p->family != AF_INET)
+           continue;
+      
+         group.s_addr = htonl (INADDR_RIP_GROUP);
+          if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0)
+           return;
+        }
+    }
+}
+
+/* Is there and address on interface that I could use ? */
+int
+rip_if_ipv4_address_check (struct interface *ifp)
+{
+  struct listnode *nn;
+  struct connected *connected;
+  int count = 0;
+
+  for (nn = listhead (ifp->connected); nn; nextnode (nn))
+    if ((connected = getdata (nn)) != NULL)
+      {
+       struct prefix *p;
+
+       p = connected->address;
+
+       if (p->family == AF_INET)
+          {
+           count++;
+         }
+      }
+                                               
+  return count;
+}
+                                               
+                                               
+                                               
+
+/* Does this address belongs to me ? */
+int
+if_check_address (struct in_addr addr)
+{
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      listnode cnode;
+      struct interface *ifp;
+
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         struct connected *connected;
+         struct prefix_ipv4 *p;
+
+         connected = getdata (cnode);
+         p = (struct prefix_ipv4 *) connected->address;
+
+         if (p->family != AF_INET)
+           continue;
+
+         if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0)
+           return 1;
+       }
+    }
+  return 0;
+}
+
+/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */
+int
+if_valid_neighbor (struct in_addr addr)
+{
+  listnode node;
+  struct connected *connected = NULL;
+  struct prefix_ipv4 *p;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      listnode cnode;
+      struct interface *ifp;
+
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         struct prefix *pxn = NULL; /* Prefix of the neighbor */
+         struct prefix *pxc = NULL; /* Prefix of the connected network */
+
+         connected = getdata (cnode);
+
+         if (if_is_pointopoint (ifp))
+           {
+             p = (struct prefix_ipv4 *) connected->address;
+
+             if (p && p->family == AF_INET)
+               {
+                 if (IPV4_ADDR_SAME (&p->prefix, &addr))
+                   return 1;
+
+                 p = (struct prefix_ipv4 *) connected->destination;
+                 if (p && IPV4_ADDR_SAME (&p->prefix, &addr))
+                   return 1;
+               }
+           }
+         else
+           {
+             p = (struct prefix_ipv4 *) connected->address;
+
+             if (p->family != AF_INET)
+               continue;
+
+             pxn = prefix_new();
+             pxn->family = AF_INET;
+             pxn->prefixlen = 32;
+             pxn->u.prefix4 = addr;
+             
+             pxc = prefix_new();
+             prefix_copy(pxc, (struct prefix *) p);
+             apply_mask(pxc);
+         
+             if (prefix_match (pxc, pxn)) 
+               {
+                 prefix_free (pxn);
+                 prefix_free (pxc);
+                 return 1;
+               }
+             prefix_free(pxc);
+             prefix_free(pxn);
+           }
+       }
+    }
+  return 0;
+}
+
+/* Inteface link down message processing. */
+int
+rip_interface_down (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+  struct stream *s;
+
+  s = zclient->ibuf;  
+
+  /* zebra_interface_state_read() updates interface structure in
+     iflist. */
+  ifp = zebra_interface_state_read(s);
+
+  if (ifp == NULL)
+    return 0;
+
+  rip_if_down(ifp);
+  if (IS_RIP_DEBUG_ZEBRA)
+    zlog_info ("interface %s index %d flags %ld metric %d mtu %d is down",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  return 0;
+}
+
+/* Inteface link up message processing */
+int
+rip_interface_up (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  /* zebra_interface_state_read () updates interface structure in
+     iflist. */
+  ifp = zebra_interface_state_read (zclient->ibuf);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (IS_RIP_DEBUG_ZEBRA)
+    zlog_info ("interface %s index %d flags %ld metric %d mtu %d is up",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  /* Check if this interface is RIP enabled or not.*/
+  rip_enable_apply (ifp);
+  /* Check for a passive interface */
+  rip_passive_interface_apply (ifp);
+
+  /* Apply distribute list to the all interface. */
+  rip_distribute_update_interface (ifp);
+
+  return 0;
+}
+
+/* Inteface addition message from zebra. */
+int
+rip_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+
+  if (IS_RIP_DEBUG_ZEBRA)
+    zlog_info ("interface add %s index %d flags %ld metric %d mtu %d",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  /* Check if this interface is RIP enabled or not.*/
+  rip_enable_apply (ifp);
+
+  /* Apply distribute list to the all interface. */
+  rip_distribute_update_interface (ifp);
+
+  /* rip_request_neighbor_all (); */
+
+  return 0;
+}
+
+int
+rip_interface_delete (int command, struct zclient *zclient,
+                     zebra_size_t length)
+{
+  struct interface *ifp;
+  struct stream *s;
+
+
+  s = zclient->ibuf;  
+  /* zebra_interface_state_read() updates interface structure in iflist */
+  ifp = zebra_interface_state_read(s);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (if_is_up (ifp)) {
+    rip_if_down(ifp);
+  } 
+  
+  zlog_info("interface delete %s index %d flags %ld metric %d mtu %d",
+           ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);  
+  
+  /* To support pseudo interface do not free interface structure.  */
+  /* if_delete(ifp); */
+
+  return 0;
+}
+
+void
+rip_interface_clean ()
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      ri->enable_network = 0;
+      ri->enable_interface = 0;
+      ri->running = 0;
+
+      if (ri->t_wakeup)
+       {
+         thread_cancel (ri->t_wakeup);
+         ri->t_wakeup = NULL;
+       }
+    }
+}
+
+void
+rip_interface_reset ()
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      ri->enable_network = 0;
+      ri->enable_interface = 0;
+      ri->running = 0;
+
+      ri->ri_send = RI_RIP_UNSPEC;
+      ri->ri_receive = RI_RIP_UNSPEC;
+
+      /* ri->auth_type = RIP_NO_AUTH; */
+      ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+      if (ri->auth_str)
+       {
+         free (ri->auth_str);
+         ri->auth_str = NULL;
+       }
+      if (ri->key_chain)
+       {
+         free (ri->key_chain);
+         ri->key_chain = NULL;
+       }
+
+      ri->split_horizon = 0;
+      ri->split_horizon_default = 0;
+
+      ri->list[RIP_FILTER_IN] = NULL;
+      ri->list[RIP_FILTER_OUT] = NULL;
+
+      ri->prefix[RIP_FILTER_IN] = NULL;
+      ri->prefix[RIP_FILTER_OUT] = NULL;
+      
+      if (ri->t_wakeup)
+       {
+         thread_cancel (ri->t_wakeup);
+         ri->t_wakeup = NULL;
+       }
+
+      ri->recv_badpackets = 0;
+      ri->recv_badroutes = 0;
+      ri->sent_updates = 0;
+
+      ri->passive = 0;
+    }
+}
+
+int
+rip_if_down(struct interface *ifp)
+{
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri = NULL;
+  if (rip)
+    {
+      for (rp = route_top (rip->table); rp; rp = route_next (rp))
+       if ((rinfo = rp->info) != NULL)
+         {
+           /* Routes got through this interface. */
+           if (rinfo->ifindex == ifp->ifindex &&
+               rinfo->type == ZEBRA_ROUTE_RIP &&
+               rinfo->sub_type == RIP_ROUTE_RTE)
+             {
+               rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &rp->p,
+                                      &rinfo->nexthop,
+                                      rinfo->ifindex);
+
+               rip_redistribute_delete (rinfo->type,rinfo->sub_type,
+                                        (struct prefix_ipv4 *)&rp->p,
+                                        rinfo->ifindex);
+             }
+           else
+             {
+               /* All redistributed routes but static and system */
+               if ((rinfo->ifindex == ifp->ifindex) &&
+                   (rinfo->type != ZEBRA_ROUTE_STATIC) &&
+                   (rinfo->type != ZEBRA_ROUTE_SYSTEM))
+                 rip_redistribute_delete (rinfo->type,rinfo->sub_type,
+                                          (struct prefix_ipv4 *)&rp->p,
+                                          rinfo->ifindex);
+             }
+         }
+    }
+           
+  ri = ifp->info;
+  
+  if (ri->running)
+   {
+     if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("turn off %s", ifp->name);
+
+     /* Leave from multicast group. */
+     rip_multicast_leave (ifp, rip->sock);
+
+     ri->running = 0;
+   }
+
+  return 0;
+}
+
+/* Needed for stop RIP process. */
+void
+rip_if_down_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_if_down (ifp);
+    }
+}
+
+int
+rip_interface_address_add (int command, struct zclient *zclient,
+                          zebra_size_t length)
+{
+  struct connected *ifc;
+  struct prefix *p;
+
+  ifc = zebra_interface_address_add_read (zclient->ibuf);
+
+  if (ifc == NULL)
+    return 0;
+
+  p = ifc->address;
+
+  if (p->family == AF_INET)
+    {
+      if (IS_RIP_DEBUG_ZEBRA)
+       zlog_info ("connected address %s/%d is added", 
+                  inet_ntoa (p->u.prefix4), p->prefixlen);
+      
+      /* Check is this interface is RIP enabled or not.*/
+      rip_enable_apply (ifc->ifp);
+
+#ifdef HAVE_SNMP
+      rip_ifaddr_add (ifc->ifp, ifc);
+#endif /* HAVE_SNMP */
+    }
+
+  return 0;
+}
+
+int
+rip_interface_address_delete (int command, struct zclient *zclient,
+                             zebra_size_t length)
+{
+  struct connected *ifc;
+  struct prefix *p;
+
+  ifc = zebra_interface_address_delete_read (zclient->ibuf);
+  
+  if (ifc)
+    {
+      p = ifc->address;
+      if (p->family == AF_INET)
+       {
+         if (IS_RIP_DEBUG_ZEBRA)
+
+           zlog_info ("connected address %s/%d is deleted",
+                      inet_ntoa (p->u.prefix4), p->prefixlen);
+
+#ifdef HAVE_SNMP
+         rip_ifaddr_delete (ifc->ifp, ifc);
+#endif /* HAVE_SNMP */
+
+         /* Check if this interface is RIP enabled or not.*/
+         rip_enable_apply (ifc->ifp);
+       }
+
+      connected_free (ifc);
+
+    }
+
+  return 0;
+}
+\f
+/* Check interface is enabled by network statement. */
+int
+rip_enable_network_lookup (struct interface *ifp)
+{
+  struct listnode *nn;
+  struct connected *connected;
+  struct prefix_ipv4 address;
+
+  for (nn = listhead (ifp->connected); nn; nextnode (nn))
+    if ((connected = getdata (nn)) != NULL)
+      {
+       struct prefix *p; 
+       struct route_node *node;
+
+       p = connected->address;
+
+       if (p->family == AF_INET)
+         {
+           address.family = AF_INET;
+           address.prefix = p->u.prefix4;
+           address.prefixlen = IPV4_MAX_BITLEN;
+           
+           node = route_node_match (rip_enable_network,
+                                    (struct prefix *)&address);
+           if (node)
+             {
+               route_unlock_node (node);
+               return 1;
+             }
+         }
+      }
+  return -1;
+}
+
+/* Add RIP enable network. */
+int
+rip_enable_network_add (struct prefix *p)
+{
+  struct route_node *node;
+
+  node = route_node_get (rip_enable_network, p);
+
+  if (node->info)
+    {
+      route_unlock_node (node);
+      return -1;
+    }
+  else
+    node->info = "enabled";
+
+  return 1;
+}
+
+/* Delete RIP enable network. */
+int
+rip_enable_network_delete (struct prefix *p)
+{
+  struct route_node *node;
+
+  node = route_node_lookup (rip_enable_network, p);
+  if (node)
+    {
+      node->info = NULL;
+
+      /* Unlock info lock. */
+      route_unlock_node (node);
+
+      /* Unlock lookup lock. */
+      route_unlock_node (node);
+
+      return 1;
+    }
+  return -1;
+}
+
+/* Check interface is enabled by ifname statement. */
+int
+rip_enable_if_lookup (char *ifname)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (rip_enable_interface); i++)
+    if ((str = vector_slot (rip_enable_interface, i)) != NULL)
+      if (strcmp (str, ifname) == 0)
+       return i;
+  return -1;
+}
+
+/* Add interface to rip_enable_if. */
+int
+rip_enable_if_add (char *ifname)
+{
+  int ret;
+
+  ret = rip_enable_if_lookup (ifname);
+  if (ret >= 0)
+    return -1;
+
+  vector_set (rip_enable_interface, strdup (ifname));
+
+  return 1;
+}
+
+/* Delete interface from rip_enable_if. */
+int
+rip_enable_if_delete (char *ifname)
+{
+  int index;
+  char *str;
+
+  index = rip_enable_if_lookup (ifname);
+  if (index < 0)
+    return -1;
+
+  str = vector_slot (rip_enable_interface, index);
+  free (str);
+  vector_unset (rip_enable_interface, index);
+
+  return 1;
+}
+
+/* Join to multicast group and send request to the interface. */
+int
+rip_interface_wakeup (struct thread *t)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  /* Get interface. */
+  ifp = THREAD_ARG (t);
+
+  ri = ifp->info;
+  ri->t_wakeup = NULL;
+
+  /* Join to multicast group. */
+  if (rip_multicast_join (ifp, rip->sock) < 0)
+    {
+      zlog_err ("multicast join failed, interface %s not running", ifp->name);
+      return 0;
+    }
+
+  /* Set running flag. */
+  ri->running = 1;
+
+  /* Send RIP request to the interface. */
+  rip_request_interface (ifp);
+
+  return 0;
+}
+
+int rip_redistribute_check (int);
+
+void
+rip_connect_set (struct interface *ifp, int set)
+{
+  struct listnode *nn;
+  struct connected *connected;
+  struct prefix_ipv4 address;
+
+  for (nn = listhead (ifp->connected); nn; nextnode (nn))
+    if ((connected = getdata (nn)) != NULL)
+      {
+       struct prefix *p; 
+       p = connected->address;
+
+       if (p->family != AF_INET)
+         continue;
+
+       address.family = AF_INET;
+       address.prefix = p->u.prefix4;
+       address.prefixlen = p->prefixlen;
+       apply_mask_ipv4 (&address);
+
+       if (set)
+         rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
+                               &address, connected->ifp->ifindex, NULL);
+       else
+         {
+           rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
+                                    &address, connected->ifp->ifindex);
+           if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT))
+             rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE,
+                                   &address, connected->ifp->ifindex, NULL);
+         }
+      }
+}
+
+/* Update interface status. */
+void
+rip_enable_apply (struct interface *ifp)
+{
+  int ret;
+  struct rip_interface *ri = NULL;
+
+  /* Check interface. */
+  if (if_is_loopback (ifp))
+    return;
+
+  if (! if_is_up (ifp))
+    return;
+
+  ri = ifp->info;
+
+  /* Check network configuration. */
+  ret = rip_enable_network_lookup (ifp);
+
+  /* If the interface is matched. */
+  if (ret > 0)
+    ri->enable_network = 1;
+  else
+    ri->enable_network = 0;
+
+  /* Check interface name configuration. */
+  ret = rip_enable_if_lookup (ifp->name);
+  if (ret >= 0)
+    ri->enable_interface = 1;
+  else
+    ri->enable_interface = 0;
+
+  /* any interface MUST have an IPv4 address */
+  if ( ! rip_if_ipv4_address_check (ifp) )
+    {
+      ri->enable_network = 0;
+      ri->enable_interface = 0;
+    }
+
+  /* Update running status of the interface. */
+  if (ri->enable_network || ri->enable_interface)
+    {
+      if (! ri->running)
+       {
+         if (IS_RIP_DEBUG_EVENT)
+           zlog_info ("turn on %s", ifp->name);
+
+         /* Add interface wake up thread. */
+         if (! ri->t_wakeup)
+           ri->t_wakeup = thread_add_timer (master, rip_interface_wakeup,
+                                            ifp, 1);
+          rip_connect_set (ifp, 1);
+       }
+    }
+  else
+    {
+      if (ri->running)
+       {
+         if (IS_RIP_DEBUG_EVENT)
+           zlog_info ("turn off %s", ifp->name);
+
+         /* Might as well clean up the route table as well */ 
+         rip_if_down(ifp);
+
+         ri->running = 0;
+          rip_connect_set (ifp, 0);
+       }
+    }
+}
+
+/* Apply network configuration to all interface. */
+void
+rip_enable_apply_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  /* Check each interface. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_enable_apply (ifp);
+    }
+}
+
+int
+rip_neighbor_lookup (struct sockaddr_in *from)
+{
+  struct prefix_ipv4 p;
+  struct route_node *node;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = from->sin_addr;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  node = route_node_lookup (rip->neighbor, (struct prefix *) &p);
+  if (node)
+    {
+      route_unlock_node (node);
+      return 1;
+    }
+  return 0;
+}
+
+/* Add new RIP neighbor to the neighbor tree. */
+int
+rip_neighbor_add (struct prefix_ipv4 *p)
+{
+  struct route_node *node;
+
+  node = route_node_get (rip->neighbor, (struct prefix *) p);
+
+  if (node->info)
+    return -1;
+
+  node->info = rip->neighbor;
+
+  return 0;
+}
+
+/* Delete RIP neighbor from the neighbor tree. */
+int
+rip_neighbor_delete (struct prefix_ipv4 *p)
+{
+  struct route_node *node;
+
+  /* Lock for look up. */
+  node = route_node_lookup (rip->neighbor, (struct prefix *) p);
+  if (! node)
+    return -1;
+  
+  node->info = NULL;
+
+  /* Unlock lookup lock. */
+  route_unlock_node (node);
+
+  /* Unlock real neighbor information lock. */
+  route_unlock_node (node);
+
+  return 0;
+}
+
+/* Clear all network and neighbor configuration. */
+void
+rip_clean_network ()
+{
+  int i;
+  char *str;
+  struct route_node *rn;
+
+  /* rip_enable_network. */
+  for (rn = route_top (rip_enable_network); rn; rn = route_next (rn))
+    if (rn->info)
+      {
+       rn->info = NULL;
+       route_unlock_node (rn);
+      }
+
+  /* rip_enable_interface. */
+  for (i = 0; i < vector_max (rip_enable_interface); i++)
+    if ((str = vector_slot (rip_enable_interface, i)) != NULL)
+      {
+       free (str);
+       vector_slot (rip_enable_interface, i) = NULL;
+      }
+}
+\f
+/* Utility function for looking up passive interface settings. */
+int
+rip_passive_interface_lookup (char *ifname)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (Vrip_passive_interface); i++)
+    if ((str = vector_slot (Vrip_passive_interface, i)) != NULL)
+      if (strcmp (str, ifname) == 0)
+       return i;
+  return -1;
+}
+
+void
+rip_passive_interface_apply (struct interface *ifp)
+{
+  int ret;
+  struct rip_interface *ri;
+
+  ri = ifp->info;
+
+  ret = rip_passive_interface_lookup (ifp->name);
+  if (ret < 0)
+    ri->passive = 0;
+  else
+    ri->passive = 1;
+}
+
+void
+rip_passive_interface_apply_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_passive_interface_apply (ifp);
+    }
+}
+
+/* Passive interface. */
+int
+rip_passive_interface_set (struct vty *vty, char *ifname)
+{
+  if (rip_passive_interface_lookup (ifname) >= 0)
+    return CMD_WARNING;
+
+  vector_set (Vrip_passive_interface, strdup (ifname));
+
+  rip_passive_interface_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_passive_interface_unset (struct vty *vty, char *ifname)
+{
+  int i;
+  char *str;
+
+  i = rip_passive_interface_lookup (ifname);
+  if (i < 0)
+    return CMD_WARNING;
+
+  str = vector_slot (Vrip_passive_interface, i);
+  free (str);
+  vector_unset (Vrip_passive_interface, i);
+
+  rip_passive_interface_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* Free all configured RIP passive-interface settings. */
+void
+rip_passive_interface_clean ()
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (Vrip_passive_interface); i++)
+    if ((str = vector_slot (Vrip_passive_interface, i)) != NULL)
+      {
+       free (str);
+       vector_slot (Vrip_passive_interface, i) = NULL;
+      }
+  rip_passive_interface_apply_all ();
+}
+\f
+/* RIP enable network or interface configuration. */
+DEFUN (rip_network,
+       rip_network_cmd,
+       "network (A.B.C.D/M|WORD)",
+       "Enable routing on an IP network\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Interface name\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret)
+    ret = rip_enable_network_add ((struct prefix *) &p);
+  else
+    ret = rip_enable_if_add (argv[0]);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "There is a same network configuration %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_enable_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* RIP enable network or interface configuration. */
+DEFUN (no_rip_network,
+       no_rip_network_cmd,
+       "no network (A.B.C.D/M|WORD)",
+       NO_STR
+       "Enable routing on an IP network\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Interface name\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret)
+    ret = rip_enable_network_delete ((struct prefix *) &p);
+  else
+    ret = rip_enable_if_delete (argv[0]);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't find network configuration %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_enable_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* RIP neighbor configuration set. */
+DEFUN (rip_neighbor,
+       rip_neighbor_cmd,
+       "neighbor A.B.C.D",
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret <= 0)
+    {
+      vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_neighbor_add (&p);
+  
+  return CMD_SUCCESS;
+}
+
+/* RIP neighbor configuration unset. */
+DEFUN (no_rip_neighbor,
+       no_rip_neighbor_cmd,
+       "no neighbor A.B.C.D",
+       NO_STR
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret <= 0)
+    {
+      vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_neighbor_delete (&p);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_receive_version,
+       ip_rip_receive_version_cmd,
+       "ip rip receive version (1|2)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1. */
+  if (atoi (argv[0]) == 1)
+    {
+      ri->ri_receive = RI_RIP_VERSION_1;
+      return CMD_SUCCESS;
+    }
+  if (atoi (argv[0]) == 2)
+    {
+      ri->ri_receive = RI_RIP_VERSION_2;
+      return CMD_SUCCESS;
+    }
+  return CMD_WARNING;
+}
+
+DEFUN (ip_rip_receive_version_1,
+       ip_rip_receive_version_1_cmd,
+       "ip rip receive version 1 2",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_receive = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_receive_version_2,
+       ip_rip_receive_version_2_cmd,
+       "ip rip receive version 2 1",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 2\n"
+       "RIP version 1\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_receive = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_receive_version,
+       no_ip_rip_receive_version_cmd,
+       "no ip rip receive version",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  ri->ri_receive = RI_RIP_UNSPEC;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_receive_version,
+       no_ip_rip_receive_version_num_cmd,
+       "no ip rip receive version (1|2)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "Version 1\n"
+       "Version 2\n")
+
+DEFUN (ip_rip_send_version,
+       ip_rip_send_version_cmd,
+       "ip rip send version (1|2)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1. */
+  if (atoi (argv[0]) == 1)
+    {
+      ri->ri_send = RI_RIP_VERSION_1;
+      return CMD_SUCCESS;
+    }
+  if (atoi (argv[0]) == 2)
+    {
+      ri->ri_send = RI_RIP_VERSION_2;
+      return CMD_SUCCESS;
+    }
+  return CMD_WARNING;
+}
+
+DEFUN (ip_rip_send_version_1,
+       ip_rip_send_version_1_cmd,
+       "ip rip send version 1 2",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_send = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_send_version_2,
+       ip_rip_send_version_2_cmd,
+       "ip rip send version 2 1",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 2\n"
+       "RIP version 1\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_send = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_send_version,
+       no_ip_rip_send_version_cmd,
+       "no ip rip send version",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  ri->ri_send = RI_RIP_UNSPEC;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_send_version,
+       no_ip_rip_send_version_num_cmd,
+       "no ip rip send version (1|2)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "Version 1\n"
+       "Version 2\n")
+
+DEFUN (ip_rip_authentication_mode,
+       ip_rip_authentication_mode_cmd,
+       "ip rip authentication mode (md5|text)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  if (strncmp ("md5", argv[0], strlen (argv[0])) == 0)
+    ri->auth_type = RIP_AUTH_MD5;
+  else if (strncmp ("text", argv[0], strlen (argv[0])) == 0)
+    ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+  else
+    {
+      vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_mode,
+       no_ip_rip_authentication_mode_cmd,
+       "no ip rip authentication mode",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* ri->auth_type = RIP_NO_AUTH; */
+  ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_mode,
+       no_ip_rip_authentication_mode_type_cmd,
+       "no ip rip authentication mode (md5|text)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n")
+
+DEFUN (ip_rip_authentication_string,
+       ip_rip_authentication_string_cmd,
+       "ip rip authentication string LINE",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n"
+       "Authentication string\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  if (strlen (argv[0]) > 16)
+    {
+      vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ri->key_chain)
+    {
+      vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ri->auth_str)
+    free (ri->auth_str);
+
+  ri->auth_str = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_string,
+       no_ip_rip_authentication_string_cmd,
+       "no ip rip authentication string",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  if (ri->auth_str)
+    free (ri->auth_str);
+
+  ri->auth_str = NULL;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_string,
+       no_ip_rip_authentication_string2_cmd,
+       "no ip rip authentication string LINE",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n"
+       "Authentication string\n")
+
+DEFUN (ip_rip_authentication_key_chain,
+       ip_rip_authentication_key_chain_cmd,
+       "ip rip authentication key-chain LINE",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *) vty->index;
+  ri = ifp->info;
+
+  if (ri->auth_str)
+    {
+      vty_out (vty, "%% authentication string configuration exists%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ri->key_chain)
+    free (ri->key_chain);
+
+  ri->key_chain = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_key_chain,
+       no_ip_rip_authentication_key_chain_cmd,
+       "no ip rip authentication key-chain",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *) vty->index;
+  ri = ifp->info;
+
+  if (ri->key_chain)
+    free (ri->key_chain);
+
+  ri->key_chain = NULL;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_key_chain,
+       no_ip_rip_authentication_key_chain2_cmd,
+       "no ip rip authentication key-chain LINE",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+
+DEFUN (rip_split_horizon,
+       rip_split_horizon_cmd,
+       "ip split-horizon",
+       IP_STR
+       "Perform split horizon\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = vty->index;
+  ri = ifp->info;
+
+  ri->split_horizon = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_split_horizon,
+       no_rip_split_horizon_cmd,
+       "no ip split-horizon",
+       NO_STR
+       IP_STR
+       "Perform split horizon\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = vty->index;
+  ri = ifp->info;
+
+  ri->split_horizon = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_passive_interface,
+       rip_passive_interface_cmd,
+       "passive-interface IFNAME",
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+{
+  return rip_passive_interface_set (vty, argv[0]);
+}
+
+DEFUN (no_rip_passive_interface,
+       no_rip_passive_interface_cmd,
+       "no passive-interface IFNAME",
+       NO_STR
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+{
+  return rip_passive_interface_unset (vty, argv[0]);
+}
+\f
+/* Write rip configuration of each interface. */
+int
+rip_interface_config_write (struct vty *vty)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      struct rip_interface *ri;
+
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      vty_out (vty, "interface %s%s", ifp->name,
+              VTY_NEWLINE);
+
+      if (ifp->desc)
+       vty_out (vty, " description %s%s", ifp->desc,
+                VTY_NEWLINE);
+
+      /* Split horizon. */
+      if (ri->split_horizon != ri->split_horizon_default)
+       {
+         if (ri->split_horizon)
+           vty_out (vty, " ip split-horizon%s", VTY_NEWLINE);
+         else
+           vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE);
+       }
+
+      /* RIP version setting. */
+      if (ri->ri_send != RI_RIP_UNSPEC)
+       vty_out (vty, " ip rip send version %s%s",
+                lookup (ri_version_msg, ri->ri_send),
+                VTY_NEWLINE);
+
+      if (ri->ri_receive != RI_RIP_UNSPEC)
+       vty_out (vty, " ip rip receive version %s%s",
+                lookup (ri_version_msg, ri->ri_receive),
+                VTY_NEWLINE);
+
+      /* RIP authentication. */
+#if 0 
+      /* RIP_AUTH_SIMPLE_PASSWORD becomes default mode. */
+      if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+       vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE);
+#endif /* 0 */
+      if (ri->auth_type == RIP_AUTH_MD5)
+       vty_out (vty, " ip rip authentication mode md5%s", VTY_NEWLINE);
+
+      if (ri->auth_str)
+       vty_out (vty, " ip rip authentication string %s%s",
+                ri->auth_str, VTY_NEWLINE);
+
+      if (ri->key_chain)
+       vty_out (vty, " ip rip authentication key-chain %s%s",
+                ri->key_chain, VTY_NEWLINE);
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+int
+config_write_rip_network (struct vty *vty, int config_mode)
+{
+  int i;
+  char *ifname;
+  struct route_node *node;
+
+  /* Network type RIP enable interface statement. */
+  for (node = route_top (rip_enable_network); node; node = route_next (node))
+    if (node->info)
+      vty_out (vty, "%s%s/%d%s", 
+              config_mode ? " network " : "    ",
+              inet_ntoa (node->p.u.prefix4),
+              node->p.prefixlen,
+              VTY_NEWLINE);
+
+  /* Interface name RIP enable statement. */
+  for (i = 0; i < vector_max (rip_enable_interface); i++)
+    if ((ifname = vector_slot (rip_enable_interface, i)) != NULL)
+      vty_out (vty, "%s%s%s",
+              config_mode ? " network " : "    ",
+              ifname,
+              VTY_NEWLINE);
+
+  /* RIP neighbors listing. */
+  for (node = route_top (rip->neighbor); node; node = route_next (node))
+    if (node->info)
+      vty_out (vty, "%s%s%s", 
+              config_mode ? " neighbor " : "    ",
+              inet_ntoa (node->p.u.prefix4),
+              VTY_NEWLINE);
+
+  /* RIP passive interface listing. */
+  if (config_mode)
+    for (i = 0; i < vector_max (Vrip_passive_interface); i++)
+      if ((ifname = vector_slot (Vrip_passive_interface, i)) != NULL)
+       vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
+
+  return 0;
+}
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+  1,
+};
+
+/* Called when interface structure allocated. */
+int
+rip_interface_new_hook (struct interface *ifp)
+{
+  ifp->info = rip_interface_new ();
+  return 0;
+}
+
+/* Called when interface structure deleted. */
+int
+rip_interface_delete_hook (struct interface *ifp)
+{
+  XFREE (MTYPE_RIP_INTERFACE, ifp->info);
+  return 0;
+}
+
+/* Allocate and initialize interface vector. */
+void
+rip_if_init ()
+{
+  /* Default initial size of interface vector. */
+  if_init();
+  if_add_hook (IF_NEW_HOOK, rip_interface_new_hook);
+  if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook);
+  
+  /* RIP network init. */
+  rip_enable_interface = vector_init (1);
+  rip_enable_network = route_table_init ();
+
+  /* RIP passive interface. */
+  Vrip_passive_interface = vector_init (1);
+
+  /* Install interface node. */
+  install_node (&interface_node, rip_interface_config_write);
+
+  /* Install commands. */
+  install_element (CONFIG_NODE, &interface_cmd);
+  install_default (INTERFACE_NODE);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+  install_element (RIP_NODE, &rip_network_cmd);
+  install_element (RIP_NODE, &no_rip_network_cmd);
+  install_element (RIP_NODE, &rip_neighbor_cmd);
+  install_element (RIP_NODE, &no_rip_neighbor_cmd);
+
+  install_element (RIP_NODE, &rip_passive_interface_cmd);
+  install_element (RIP_NODE, &no_rip_passive_interface_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_send_version_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd);
+
+  install_element (INTERFACE_NODE, &rip_split_horizon_cmd);
+  install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd);
+}
diff --git a/ripd/rip_main.c b/ripd/rip_main.c
new file mode 100644 (file)
index 0000000..1070fb4
--- /dev/null
@@ -0,0 +1,270 @@
+/* RIPd main routine.
+ * Copyright (C) 1997, 98 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.  
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "filter.h"
+#include "keychain.h"
+#include "log.h"
+
+#include "ripd/ripd.h"
+
+/* ripd options. */
+static struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "help",        no_argument,       NULL, 'h'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "retain",      no_argument,       NULL, 'r'},
+  { "version",     no_argument,       NULL, 'v'},
+  { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = RIPD_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG;
+char *config_file = NULL;
+
+/* ripd program name */
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* RIP VTY bind address. */
+char *vty_addr = NULL;
+
+/* RIP VTY connection port. */
+int vty_port = RIP_VTY_PORT;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_RIPD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\
+Daemon which manages RIP version 1 and 2.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-r, --retain       When program terminates, retain added route by ripd.\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+
+  exit (status);
+}
+\f
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog_info ("SIGHUP received");
+  rip_clean ();
+  rip_reset ();
+  zlog_info ("ripd restarting!");
+
+  /* Reload config file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Create VTY's socket */
+  vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH);
+
+  /* Try to return to normal operation. */
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog (NULL, LOG_INFO, "Terminating on signal");
+
+  if (! retain_mode)
+    rip_clean ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+  signal_set (SIGUSR1, sigusr1);
+}
+\f
+/* Main routine of ripd. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  int daemon_mode = 0;
+  char *progname;
+  struct thread thread;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* Get program name. */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  /* First of all we need logging init. */
+  zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP,
+                          LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  /* Command line option parse. */
+  while (1) 
+    {
+      int opt;
+
+      opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0);
+    
+      if (opt == EOF)
+       break;
+
+      switch (opt) 
+       {
+       case 0:
+         break;
+       case 'd':
+         daemon_mode = 1;
+         break;
+       case 'f':
+         config_file = optarg;
+         break;
+       case 'A':
+         vty_addr = optarg;
+         break;
+        case 'i':
+          pid_file = optarg;
+          break;
+       case 'P':
+         vty_port = atoi (optarg);
+         break;
+       case 'r':
+         retain_mode = 1;
+         break;
+       case 'v':
+         print_version (progname);
+         exit (0);
+         break;
+       case 'h':
+         usage (progname, 0);
+         break;
+       default:
+         usage (progname, 1);
+         break;
+       }
+    }
+
+  /* Prepare master thread. */
+  master = thread_master_create ();
+
+  /* Library initialization. */
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  memory_init ();
+  keychain_init ();
+
+  /* RIP related initialization. */
+  rip_init ();
+  rip_if_init ();
+  rip_zclient_init ();
+  rip_peer_init ();
+
+  /* Sort all installed commands. */
+  sort_node ();
+
+  /* Get configuration file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Change to the daemon program. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Pid file create. */
+  pid_output (pid_file);
+
+  /* Create VTY's socket */
+  vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH);
+
+  /* Execute each thread. */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached. */
+  exit (0);
+}
diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c
new file mode 100644 (file)
index 0000000..0d47348
--- /dev/null
@@ -0,0 +1,414 @@
+/* RIP offset-list
+ * Copyright (C) 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.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "filter.h"
+#include "command.h"
+#include "linklist.h"
+#include "memory.h"
+
+#define RIP_OFFSET_LIST_IN  0
+#define RIP_OFFSET_LIST_OUT 1
+#define RIP_OFFSET_LIST_MAX 2
+
+struct rip_offset_list
+{
+  char *ifname;
+
+  struct 
+  {
+    char *alist_name;
+    /* struct access_list *alist; */
+    int metric;
+  } direct[RIP_OFFSET_LIST_MAX];
+};
+
+static struct list *rip_offset_list_master;
+
+int
+strcmp_safe (char *s1, char *s2)
+{
+  if (s1 == NULL && s2 == NULL)
+    return 0;
+  if (s1 == NULL)
+    return -1;
+  if (s2 == NULL)
+    return 1;
+  return strcmp (s1, s2);
+}
+
+struct rip_offset_list *
+rip_offset_list_new ()
+{
+  struct rip_offset_list *new;
+
+  new = XMALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list));
+  memset (new, 0, sizeof (struct rip_offset_list));
+  return new;
+}
+
+void
+rip_offset_list_free (struct rip_offset_list *offset)
+{
+  XFREE (MTYPE_RIP_OFFSET_LIST, offset);
+}
+
+struct rip_offset_list *
+rip_offset_list_lookup (char *ifname)
+{
+  struct rip_offset_list *offset;
+  struct listnode *nn;
+
+  LIST_LOOP (rip_offset_list_master, offset, nn)
+    {
+      if (strcmp_safe (offset->ifname, ifname) == 0)
+       return offset;
+    }
+  return NULL;
+}
+
+struct rip_offset_list *
+rip_offset_list_get (char *ifname)
+{
+  struct rip_offset_list *offset;
+  
+  offset = rip_offset_list_lookup (ifname);
+  if (offset)
+    return offset;
+
+  offset = rip_offset_list_new ();
+  if (ifname)
+    offset->ifname = strdup (ifname);
+  listnode_add_sort (rip_offset_list_master, offset);
+
+  return offset;
+}
+
+int
+rip_offset_list_set (struct vty *vty, char *alist, char *direct_str,
+                    char *metric_str, char *ifname)
+{
+  int direct;
+  int metric;
+  struct rip_offset_list *offset;
+
+  /* Check direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = RIP_OFFSET_LIST_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = RIP_OFFSET_LIST_OUT;
+  else
+    {
+      vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check metric. */
+  metric = atoi (metric_str);
+  if (metric < 0 || metric > 16)
+    {
+      vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get offset-list structure with interface name. */
+  offset = rip_offset_list_get (ifname);
+
+  if (offset->direct[direct].alist_name)
+    free (offset->direct[direct].alist_name);
+  offset->direct[direct].alist_name = strdup (alist);
+  offset->direct[direct].metric = metric;
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_offset_list_unset (struct vty *vty, char *alist, char *direct_str,
+                      char *metric_str, char *ifname)
+{
+  int direct;
+  int metric;
+  struct rip_offset_list *offset;
+
+  /* Check direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = RIP_OFFSET_LIST_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = RIP_OFFSET_LIST_OUT;
+  else
+    {
+      vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check metric. */
+  metric = atoi (metric_str);
+  if (metric < 0 || metric > 16)
+    {
+      vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get offset-list structure with interface name. */
+  offset = rip_offset_list_lookup (ifname);
+
+  if (offset)
+    {
+      if (offset->direct[direct].alist_name)
+       free (offset->direct[direct].alist_name);
+      offset->direct[direct].alist_name = NULL;
+
+      if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL &&
+         offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL)
+       {
+         listnode_delete (rip_offset_list_master, offset);
+         if (offset->ifname)
+           free (offset->ifname);
+         rip_offset_list_free (offset);
+       }
+    }
+  else
+    {
+      vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+#define OFFSET_LIST_IN_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
+#define OFFSET_LIST_IN_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_IN].metric)
+
+#define OFFSET_LIST_OUT_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name)
+#define OFFSET_LIST_OUT_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_OUT].metric)
+
+/* If metric is modifed return 1. */
+int
+rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp,
+                         u_int32_t *metric)
+{
+  struct rip_offset_list *offset;
+  struct access_list *alist;
+
+  /* Look up offset-list with interface name. */
+  offset = rip_offset_list_lookup (ifp->name);
+  if (offset && OFFSET_LIST_IN_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
+
+      if (alist 
+         && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+       {
+         *metric += OFFSET_LIST_IN_METRIC (offset);
+         return 1;
+       }
+      return 0;
+    }
+  /* Look up offset-list without interface name. */
+  offset = rip_offset_list_lookup (NULL);
+  if (offset && OFFSET_LIST_IN_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
+
+      if (alist 
+         && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+       {
+         *metric += OFFSET_LIST_IN_METRIC (offset);
+         return 1;
+       }
+      return 0;
+    }
+  return 0;
+}
+
+/* If metric is modifed return 1. */
+int
+rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp,
+                         u_int32_t *metric)
+{
+  struct rip_offset_list *offset;
+  struct access_list *alist;
+
+  /* Look up offset-list with interface name. */
+  offset = rip_offset_list_lookup (ifp->name);
+  if (offset && OFFSET_LIST_OUT_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
+
+      if (alist 
+         && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+       {
+         *metric += OFFSET_LIST_OUT_METRIC (offset);
+         return 1;
+       }
+      return 0;
+    }
+
+  /* Look up offset-list without interface name. */
+  offset = rip_offset_list_lookup (NULL);
+  if (offset && OFFSET_LIST_OUT_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
+
+      if (alist 
+         && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+       {
+         *metric += OFFSET_LIST_OUT_METRIC (offset);
+         return 1;
+       }
+      return 0;
+    }
+  return 0;
+}
+
+DEFUN (rip_offset_list,
+       rip_offset_list_cmd,
+       "offset-list WORD (in|out) <0-16>",
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n")
+{
+  return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (rip_offset_list_ifname,
+       rip_offset_list_ifname_cmd,
+       "offset-list WORD (in|out) <0-16> IFNAME",
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n"
+       "Interface to match\n")
+{
+  return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_rip_offset_list,
+       no_rip_offset_list_cmd,
+       "no offset-list WORD (in|out) <0-16>",
+       NO_STR
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n")
+{
+  return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_rip_offset_list_ifname,
+       no_rip_offset_list_ifname_cmd,
+       "no offset-list WORD (in|out) <0-16> IFNAME",
+       NO_STR
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n"
+       "Interface to match\n")
+{
+  return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+int
+offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2)
+{
+  return strcmp_safe (o1->ifname, o2->ifname);
+}
+
+void
+offset_list_del (struct rip_offset_list *offset)
+{
+  if (OFFSET_LIST_IN_NAME (offset))
+    free (OFFSET_LIST_IN_NAME (offset));
+  if (OFFSET_LIST_OUT_NAME (offset))
+    free (OFFSET_LIST_OUT_NAME (offset));
+  if (offset->ifname)
+    free (offset->ifname);
+  rip_offset_list_free (offset);
+}
+
+void
+rip_offset_init ()
+{
+  rip_offset_list_master = list_new ();
+  rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+  rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
+
+  install_element (RIP_NODE, &rip_offset_list_cmd);
+  install_element (RIP_NODE, &rip_offset_list_ifname_cmd);
+  install_element (RIP_NODE, &no_rip_offset_list_cmd);
+  install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd);
+}
+
+void
+rip_offset_clean ()
+{
+  list_delete (rip_offset_list_master);
+
+  rip_offset_list_master = list_new ();
+  rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+  rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
+}
+
+int
+config_write_rip_offset_list (struct vty *vty)
+{
+  struct listnode *nn;
+  struct rip_offset_list *offset;
+
+  LIST_LOOP (rip_offset_list_master, offset, nn)
+    {
+      if (! offset->ifname)
+       {
+         if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
+           vty_out (vty, " offset-list %s in %d%s",
+                    offset->direct[RIP_OFFSET_LIST_IN].alist_name,
+                    offset->direct[RIP_OFFSET_LIST_IN].metric,
+                    VTY_NEWLINE);
+         if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
+           vty_out (vty, " offset-list %s out %d%s",
+                    offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
+                    offset->direct[RIP_OFFSET_LIST_OUT].metric,
+                    VTY_NEWLINE);
+       }
+      else
+       {
+         if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
+           vty_out (vty, " offset-list %s in %d %s%s",
+                    offset->direct[RIP_OFFSET_LIST_IN].alist_name,
+                    offset->direct[RIP_OFFSET_LIST_IN].metric,
+                    offset->ifname, VTY_NEWLINE);
+         if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
+           vty_out (vty, " offset-list %s out %d %s%s",
+                    offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
+                    offset->direct[RIP_OFFSET_LIST_OUT].metric,
+                    offset->ifname, VTY_NEWLINE);
+       }
+    }
+
+  return 0;
+}
diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c
new file mode 100644 (file)
index 0000000..20c2da7
--- /dev/null
@@ -0,0 +1,211 @@
+/* RIP peer support
+ * Copyright (C) 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.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "linklist.h"
+#include "thread.h"
+#include "memory.h"
+
+#include "ripd/ripd.h"
+
+/* Linked list of RIP peer. */
+struct list *peer_list;
+\f
+struct rip_peer *
+rip_peer_new ()
+{
+  struct rip_peer *new;
+
+  new = XMALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer));
+  memset (new, 0, sizeof (struct rip_peer));
+  return new;
+}
+
+void
+rip_peer_free (struct rip_peer *peer)
+{
+  XFREE (MTYPE_RIP_PEER, peer);
+}
+
+struct rip_peer *
+rip_peer_lookup (struct in_addr *addr)
+{
+  struct rip_peer *peer;
+  struct listnode *nn;
+
+  LIST_LOOP (peer_list, peer, nn)
+    {
+      if (IPV4_ADDR_SAME (&peer->addr, addr))
+       return peer;
+    }
+  return NULL;
+}
+
+struct rip_peer *
+rip_peer_lookup_next (struct in_addr *addr)
+{
+  struct rip_peer *peer;
+  struct listnode *nn;
+
+  LIST_LOOP (peer_list, peer, nn)
+    {
+      if (htonl (peer->addr.s_addr) > htonl (addr->s_addr))
+       return peer;
+    }
+  return NULL;
+}
+
+/* RIP peer is timeout. */
+int
+rip_peer_timeout (struct thread *t)
+{
+  struct rip_peer *peer;
+
+  peer = THREAD_ARG (t);
+  listnode_delete (peer_list, peer);
+  rip_peer_free (peer);
+
+  return 0;
+}
+
+/* Get RIP peer.  At the same time update timeout thread. */
+struct rip_peer *
+rip_peer_get (struct in_addr *addr)
+{
+  struct rip_peer *peer;
+
+  peer = rip_peer_lookup (addr);
+
+  if (peer)
+    {
+      if (peer->t_timeout)
+       thread_cancel (peer->t_timeout);
+    }
+  else
+    {
+      peer = rip_peer_new ();
+      peer->addr = *addr;
+      listnode_add_sort (peer_list, peer);
+    }
+
+  /* Update timeout thread. */
+  peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer,
+                                     RIP_PEER_TIMER_DEFAULT);
+
+  /* Last update time set. */
+  time (&peer->uptime);
+  
+  return peer;
+}
+
+void
+rip_peer_update (struct sockaddr_in *from, u_char version)
+{
+  struct rip_peer *peer;
+  peer = rip_peer_get (&from->sin_addr);
+  peer->version = version;
+}
+
+void
+rip_peer_bad_route (struct sockaddr_in *from)
+{
+  struct rip_peer *peer;
+  peer = rip_peer_get (&from->sin_addr);
+  peer->recv_badroutes++;
+}
+
+void
+rip_peer_bad_packet (struct sockaddr_in *from)
+{
+  struct rip_peer *peer;
+  peer = rip_peer_get (&from->sin_addr);
+  peer->recv_badpackets++;
+}
+
+/* Display peer uptime. */
+char *
+rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len)
+{
+  time_t uptime;
+  struct tm *tm;
+
+  /* If there is no connection has been done before print `never'. */
+  if (peer->uptime == 0)
+    {
+      snprintf (buf, len, "never   ");
+      return buf;
+    }
+
+  /* Get current time. */
+  uptime = time (NULL);
+  uptime -= peer->uptime;
+  tm = gmtime (&uptime);
+
+  /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+  if (uptime < ONE_DAY_SECOND)
+    snprintf (buf, len, "%02d:%02d:%02d", 
+             tm->tm_hour, tm->tm_min, tm->tm_sec);
+  else if (uptime < ONE_WEEK_SECOND)
+    snprintf (buf, len, "%dd%02dh%02dm", 
+             tm->tm_yday, tm->tm_hour, tm->tm_min);
+  else
+    snprintf (buf, len, "%02dw%dd%02dh", 
+             tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+  return buf;
+}
+
+void
+rip_peer_display (struct vty *vty)
+{
+  struct rip_peer *peer;
+  struct listnode *nn;
+#define RIP_UPTIME_LEN 25
+  char timebuf[RIP_UPTIME_LEN];
+
+  LIST_LOOP (peer_list, peer, nn)
+    {
+      vty_out (vty, "    %-16s %9d %9d %9d   %s%s", inet_ntoa (peer->addr),
+              peer->recv_badpackets, peer->recv_badroutes,
+              ZEBRA_RIP_DISTANCE_DEFAULT,
+              rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN),
+              VTY_NEWLINE);
+    }
+}
+
+int
+rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2)
+{
+  return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr);
+}
+
+void
+rip_peer_init ()
+{
+  peer_list = list_new ();
+  peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp;
+}
diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c
new file mode 100644 (file)
index 0000000..791de41
--- /dev/null
@@ -0,0 +1,898 @@
+/* RIPv2 routemap.
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+#include "filter.h"
+#include "log.h"
+#include "sockunion.h"         /* for inet_aton () */
+#include "plist.h"
+
+#include "ripd/ripd.h"
+
+/* Add rip route map rule. */
+int
+rip_route_match_add (struct vty *vty, struct route_map_index *index,
+                    char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+rip_route_match_delete (struct vty *vty, struct route_map_index *index,
+                       char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Add rip route map rule. */
+int
+rip_route_set_add (struct vty *vty, struct route_map_index *index,
+                  char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+rip_route_set_delete (struct vty *vty, struct route_map_index *index,
+                     char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+void
+rip_route_map_update ()
+{
+  int i;
+
+  if (rip) 
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
+       {
+         if (rip->route_map[i].name)
+           rip->route_map[i].map = 
+             route_map_lookup_by_name (rip->route_map[i].name);
+       }
+    }
+}
+\f
+/* `match metric METRIC' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix, 
+                   route_map_object_t type, void *object)
+{
+  u_int32_t *metric;
+  struct rip_info *rinfo;
+
+  if (type == RMAP_RIP)
+    {
+      metric = rule;
+      rinfo = object;
+    
+      if (rinfo->metric == *metric)
+       return RMAP_MATCH;
+      else
+       return RMAP_NOMATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is METRIC value */
+void *
+route_match_metric_compile (char *arg)
+{
+  u_int32_t *metric;
+
+  metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *metric = atoi (arg);
+
+  if(*metric > 0)
+    return metric;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+  return NULL;
+}
+
+/* Free route map's compiled `match metric' value. */
+void
+route_match_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+  "metric",
+  route_match_metric,
+  route_match_metric_compile,
+  route_match_metric_free
+};
+
+/* `match interface IFNAME' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+                      route_map_object_t type, void *object)
+{
+  struct rip_info *rinfo;
+  struct interface *ifp;
+  char *ifname;
+
+  if (type == RMAP_RIP)
+    {
+      ifname = rule;
+      ifp = if_lookup_by_name(ifname);
+
+      if (!ifp)
+       return RMAP_NOMATCH;
+
+      rinfo = object;
+
+      if (rinfo->ifindex_out == ifp->ifindex)
+       return RMAP_MATCH;
+      else
+       return RMAP_NOMATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match interface' match statement. `arg' is IFNAME value */
+/* XXX I don`t know if I need to check does interface exist? */
+void *
+route_match_interface_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `match interface' value. */
+void
+route_match_interface_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for interface matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+  "interface",
+  route_match_interface,
+  route_match_interface_compile,
+  route_match_interface_free
+};
+
+/* `match ip next-hop IP_ACCESS_LIST' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_next_hop (void *rule, struct prefix *prefix,
+                       route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  struct rip_info *rinfo;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_RIP)
+    {
+      rinfo = object;
+      p.family = AF_INET;
+      p.prefix = rinfo->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+       return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, &p) == FILTER_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement.  `arg' should be
+   access-list name. */
+void *
+route_match_ip_next_hop_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `. */
+void
+route_match_ip_next_hop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+{
+  "ip next-hop",
+  route_match_ip_next_hop,
+  route_match_ip_next_hop_compile,
+  route_match_ip_next_hop_free
+};
+\f
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+  struct rip_info *rinfo;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_RIP)
+    {
+      rinfo = object;
+      p.family = AF_INET;
+      p.prefix = rinfo->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_next_hop_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+  "ip next-hop prefix-list",
+  route_match_ip_next_hop_prefix_list,
+  route_match_ip_next_hop_prefix_list_compile,
+  route_match_ip_next_hop_prefix_list_free
+};
+\f
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+   zero. */
+route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix, 
+                       route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+
+  if (type == RMAP_RIP)
+    {
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+       return RMAP_NOMATCH;
+    
+      return (access_list_apply (alist, prefix) == FILTER_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement.  `arg' should be
+   access-list name. */
+void *
+route_match_ip_address_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_address_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+  "ip address",
+  route_match_ip_address,
+  route_match_ip_address_compile,
+  route_match_ip_address_free
+};
+\f
+/* `match ip address prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, 
+                                   route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+
+  if (type == RMAP_RIP)
+    {
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+       return RMAP_NOMATCH;
+    
+      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+             RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_address_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+  "ip address prefix-list",
+  route_match_ip_address_prefix_list,
+  route_match_ip_address_prefix_list_compile,
+  route_match_ip_address_prefix_list_free
+};
+\f
+/* `set metric METRIC' */
+
+/* Set metric to attribute. */
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix, 
+                 route_map_object_t type, void *object)
+{
+  u_int32_t *metric;
+  struct rip_info *rinfo;
+
+  if (type == RMAP_RIP)
+    {
+      /* Fetch routemap's rule information. */
+      metric = rule;
+      rinfo = object;
+    
+      /* Set metric out value. */
+      rinfo->metric_out = *metric;
+      rinfo->metric_set = 1;
+    }
+  return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+void *
+route_set_metric_compile (char *arg)
+{
+  u_int32_t *metric;
+
+  metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *metric = atoi (arg);
+
+  return metric;
+
+#if 0
+  /* To make it consistent to other daemon, metric check is commented
+     out.*/
+  if (*metric >= 0 && *metric <= 16)
+    return metric;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+  return NULL;
+#endif /* 0 */
+}
+
+/* Free route map's compiled `set metric' value. */
+void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_cmd = 
+{
+  "metric",
+  route_set_metric,
+  route_set_metric_compile,
+  route_set_metric_free,
+};
+
+/* `set ip next-hop IP_ADDRESS' */
+
+/* Set nexthop to object.  ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ip_nexthop (void *rule, struct prefix *prefix, 
+                     route_map_object_t type, void *object)
+{
+  struct in_addr *address;
+  struct rip_info *rinfo;
+
+  if(type == RMAP_RIP)
+    {
+      /* Fetch routemap's rule information. */
+      address = rule;
+      rinfo = object;
+    
+      /* Set next hop value. */ 
+      rinfo->nexthop_out = *address;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function.  Given string is converted
+   to struct in_addr structure. */
+void *
+route_set_ip_nexthop_compile (char *arg)
+{
+  int ret;
+  struct in_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+  ret = inet_aton (arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_ip_nexthop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ip_nexthop_cmd =
+{
+  "ip next-hop",
+  route_set_ip_nexthop,
+  route_set_ip_nexthop_compile,
+  route_set_ip_nexthop_free
+};
+\f
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+
+DEFUN (match_metric, 
+       match_metric_cmd,
+       "match metric <0-4294967295>",
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+{
+  return rip_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+       no_match_metric_cmd,
+       "no match metric",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "metric", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+       no_match_metric_val_cmd,
+       "no match metric <0-4294967295>",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+
+DEFUN (match_interface,
+       match_interface_cmd,
+       "match interface WORD",
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+{
+  return rip_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+       no_match_interface_cmd,
+       "no match interface",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "interface", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+       no_match_interface_val_cmd,
+       "no match interface WORD",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+
+DEFUN (match_ip_next_hop,
+       match_ip_next_hop_cmd,
+       "match ip next-hop WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop,
+       no_match_ip_next_hop_cmd,
+       "no match ip next-hop",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+       no_match_ip_next_hop_val_cmd,
+       "no match ip next-hop WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+       match_ip_next_hop_prefix_list_cmd,
+       "match ip next-hop prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_cmd,
+       "no match ip next-hop prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_val_cmd,
+       "no match ip next-hop prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_ip_address, 
+       match_ip_address_cmd,
+       "match ip address WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address, 
+       no_match_ip_address_cmd,
+       "no match ip address",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip address", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address, 
+       no_match_ip_address_val_cmd,
+       "no match ip address WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list name\n")
+
+DEFUN (match_ip_address_prefix_list, 
+       match_ip_address_prefix_list_cmd,
+       "match ip address prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_cmd,
+       "no match ip address prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_val_cmd,
+       "no match ip address prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+/* set functions */
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+{
+  return rip_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n")
+{
+  if (argc == 0)
+    return rip_route_set_delete (vty, vty->index, "metric", NULL);
+
+  return rip_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+       no_set_metric_val_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+
+DEFUN (set_ip_nexthop,
+       set_ip_nexthop_cmd,
+       "set ip next-hop A.B.C.D",
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+{
+  union sockunion su;
+  int ret;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return rip_route_set_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_set_ip_nexthop,
+       no_set_ip_nexthop_cmd,
+       "no set ip next-hop",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n")
+{
+  if (argc == 0)
+    return rip_route_set_delete (vty, vty->index, "ip next-hop", NULL);
+  
+  return rip_route_set_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_set_ip_nexthop,
+       no_set_ip_nexthop_val_cmd,
+       "no set ip next-hop A.B.C.D",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+void
+rip_route_map_reset ()
+{
+  ;
+}
+
+/* Route-map init */
+void
+rip_route_map_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+  route_map_add_hook (rip_route_map_update);
+  route_map_delete_hook (rip_route_map_update);
+
+  route_map_install_match (&route_match_metric_cmd);
+  route_map_install_match (&route_match_interface_cmd);
+  route_map_install_match (&route_match_ip_next_hop_cmd);
+  route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+  route_map_install_match (&route_match_ip_address_cmd);
+  route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+
+  route_map_install_set (&route_set_metric_cmd);
+  route_map_install_set (&route_set_ip_nexthop_cmd);
+
+  install_element (RMAP_NODE, &match_metric_cmd);
+  install_element (RMAP_NODE, &no_match_metric_cmd);
+  install_element (RMAP_NODE, &no_match_metric_val_cmd);
+  install_element (RMAP_NODE, &match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+  install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_val_cmd);
+  install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+}
diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c
new file mode 100644 (file)
index 0000000..dc2b621
--- /dev/null
@@ -0,0 +1,577 @@
+/* RIP SNMP support
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "table.h"
+#include "smux.h"
+
+#include "ripd/ripd.h"
+\f
+/* RIPv2-MIB. */
+#define RIPV2MIB 1,3,6,1,2,1,23
+
+/* Zebra enterprise RIP MIB.  This variable is used for register
+   RIPv2-MIB to SNMP agent under SMUX protocol.  */
+#define RIPDOID 1,3,6,1,4,1,3317,1,2,3
+
+/* RIPv2-MIB rip2Globals values. */
+#define RIP2GLOBALROUTECHANGES  1
+#define RIP2GLOBALQUERIES       2
+
+/* RIPv2-MIB rip2IfStatEntry. */
+#define RIP2IFSTATENTRY         1
+
+/* RIPv2-MIB rip2IfStatTable. */
+#define RIP2IFSTATADDRESS       1
+#define RIP2IFSTATRCVBADPACKETS 2
+#define RIP2IFSTATRCVBADROUTES  3
+#define RIP2IFSTATSENTUPDATES   4
+#define RIP2IFSTATSTATUS        5
+
+/* RIPv2-MIB rip2IfConfTable. */
+#define RIP2IFCONFADDRESS       1
+#define RIP2IFCONFDOMAIN        2
+#define RIP2IFCONFAUTHTYPE      3
+#define RIP2IFCONFAUTHKEY       4
+#define RIP2IFCONFSEND          5
+#define RIP2IFCONFRECEIVE       6
+#define RIP2IFCONFDEFAULTMETRIC 7
+#define RIP2IFCONFSTATUS        8
+#define RIP2IFCONFSRCADDRESS    9
+
+/* RIPv2-MIB rip2PeerTable. */
+#define RIP2PEERADDRESS         1
+#define RIP2PEERDOMAIN          2
+#define RIP2PEERLASTUPDATE      3
+#define RIP2PEERVERSION         4
+#define RIP2PEERRCVBADPACKETS   5
+#define RIP2PEERRCVBADROUTES    6
+
+/* SNMP value hack. */
+#define COUNTER     ASN_COUNTER
+#define INTEGER     ASN_INTEGER
+#define TIMETICKS   ASN_TIMETICKS
+#define IPADDRESS   ASN_IPADDRESS
+#define STRING      ASN_OCTET_STR
+\f
+/* Define SNMP local variables. */
+SNMP_LOCAL_VARIABLES
+
+/* RIP-MIB instances. */
+oid rip_oid [] = { RIPV2MIB };
+oid ripd_oid [] = { RIPDOID };
+
+/* Interface cache table sorted by interface's address. */
+struct route_table *rip_ifaddr_table;
+
+/* Hook functions. */
+static u_char *rip2Globals ();
+static u_char *rip2IfStatEntry ();
+static u_char *rip2IfConfAddress ();
+static u_char *rip2PeerTable ();
+
+struct variable rip_variables[] = 
+{
+  /* RIP Global Counters. */
+  {RIP2GLOBALROUTECHANGES,    COUNTER, RONLY, rip2Globals,
+   2, {1, 1}},
+  {RIP2GLOBALQUERIES,         COUNTER, RONLY, rip2Globals,
+   2, {1, 2}},
+  /* RIP Interface Tables. */
+  {RIP2IFSTATADDRESS,         IPADDRESS, RONLY, rip2IfStatEntry,
+   3, {2, 1, 1}},
+  {RIP2IFSTATRCVBADPACKETS,   COUNTER, RONLY, rip2IfStatEntry,
+   3, {2, 1, 2}},
+  {RIP2IFSTATRCVBADROUTES,    COUNTER, RONLY, rip2IfStatEntry,
+   3, {2, 1, 3}},
+  {RIP2IFSTATSENTUPDATES,     COUNTER, RONLY, rip2IfStatEntry,
+   3, {2, 1, 4}},
+  {RIP2IFSTATSTATUS,          COUNTER, RWRITE, rip2IfStatEntry,
+   3, {2, 1, 5}},
+  {RIP2IFCONFADDRESS,         IPADDRESS, RONLY, rip2IfConfAddress,
+   /* RIP Interface Configuration Table. */
+   3, {3, 1, 1}},
+  {RIP2IFCONFDOMAIN,          STRING, RONLY, rip2IfConfAddress,
+   3, {3, 1, 2}},
+  {RIP2IFCONFAUTHTYPE,        COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 3}},
+  {RIP2IFCONFAUTHKEY,         STRING, RONLY, rip2IfConfAddress,
+   3, {3, 1, 4}},
+  {RIP2IFCONFSEND,            COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 5}},
+  {RIP2IFCONFRECEIVE,         COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 6}},
+  {RIP2IFCONFDEFAULTMETRIC,   COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 7}},
+  {RIP2IFCONFSTATUS,          COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 8}},
+  {RIP2IFCONFSRCADDRESS,      IPADDRESS, RONLY, rip2IfConfAddress,
+   3, {3, 1, 9}},
+  {RIP2PEERADDRESS,           IPADDRESS, RONLY, rip2PeerTable,
+   /* RIP Peer Table. */
+   3, {4, 1, 1}},
+  {RIP2PEERDOMAIN,            INTEGER, RONLY, rip2PeerTable,
+   3, {4, 1, 2}},
+  {RIP2PEERLASTUPDATE,        TIMETICKS, RONLY, rip2PeerTable,
+   3, {4, 1, 3}},
+  {RIP2PEERVERSION,           INTEGER, RONLY, rip2PeerTable,
+   3, {4, 1, 4}},
+  {RIP2PEERRCVBADPACKETS,     COUNTER, RONLY, rip2PeerTable,
+   3, {4, 1, 5}},
+  {RIP2PEERRCVBADROUTES,      COUNTER, RONLY, rip2PeerTable,
+   3, {4, 1, 6}}
+};
+\f
+static u_char *
+rip2Globals (struct variable *v, oid name[], size_t *length,
+            int exact, size_t *var_len, WriteMethod **write_method)
+{
+  if (smux_header_generic(v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Retrun global counter. */
+  switch (v->magic)
+    {
+    case RIP2GLOBALROUTECHANGES:
+      return SNMP_INTEGER (rip_global_route_changes);
+      break;
+    case RIP2GLOBALQUERIES:
+      return SNMP_INTEGER (rip_global_queries);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+void
+rip_ifaddr_add (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix *p;
+  struct route_node *rn;
+
+  p = ifc->address;
+
+  if (p->family != AF_INET)
+    return;
+
+  rn = route_node_get (rip_ifaddr_table, p);
+  rn->info = ifp;
+}
+
+void
+rip_ifaddr_delete (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix *p;
+  struct route_node *rn;
+  struct interface *i;
+
+  p = ifc->address;
+
+  if (p->family != AF_INET)
+    return;
+
+  rn = route_node_lookup (rip_ifaddr_table, p);
+  if (! rn)
+    return;
+  i = rn->info;
+  if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ))
+    {
+      rn->info = NULL;
+      route_unlock_node (rn);
+      route_unlock_node (rn);
+    }
+}
+
+struct interface *
+rip_ifaddr_lookup_next (struct in_addr *addr)
+{
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  struct interface *ifp;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.prefix = *addr;
+
+  rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p);
+
+  for (rn = route_next (rn); rn; rn = route_next (rn))
+    if (rn->info)
+      break;
+
+  if (rn && rn->info)
+    {
+      ifp = rn->info;
+      *addr = rn->p.u.prefix4;
+      route_unlock_node (rn);
+      return ifp;
+    }
+  return NULL;
+}
+
+static struct interface *
+rip2IfLookup (struct variable *v, oid name[], size_t *length, 
+             struct in_addr *addr, int exact)
+{
+  int len;
+  struct interface *ifp;
+  
+  if (exact)
+    {
+      /* Check the length. */
+      if (*length - v->namelen != sizeof (struct in_addr))
+       return NULL;
+
+      oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
+
+      return if_lookup_exact_address (*addr);
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4) len = 4;
+
+      oid2in_addr (name + v->namelen, len, addr);
+
+      ifp = rip_ifaddr_lookup_next (addr);
+
+      if (ifp == NULL)
+       return NULL;
+
+      oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
+
+      *length = v->namelen + sizeof (struct in_addr);
+
+      return ifp;
+    }
+  return NULL;
+}
+
+static struct rip_peer *
+rip2PeerLookup (struct variable *v, oid name[], size_t *length, 
+               struct in_addr *addr, int exact)
+{
+  int len;
+  struct rip_peer *peer;
+  
+  if (exact)
+    {
+      /* Check the length. */
+      if (*length - v->namelen != sizeof (struct in_addr) + 1)
+       return NULL;
+
+      oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
+
+      peer = rip_peer_lookup (addr);
+
+      if (peer->domain == name[v->namelen + sizeof (struct in_addr)])
+       return peer;
+
+      return NULL;
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4) len = 4;
+
+      oid2in_addr (name + v->namelen, len, addr);
+
+      len = *length - v->namelen;
+      peer = rip_peer_lookup (addr);
+      if (peer)
+       {
+         if ((len < sizeof (struct in_addr) + 1) ||
+             (peer->domain > name[v->namelen + sizeof (struct in_addr)]))
+           {
+             oid_copy_addr (name + v->namelen, &peer->addr,
+                            sizeof (struct in_addr));
+             name[v->namelen + sizeof (struct in_addr)] = peer->domain;
+             *length = sizeof (struct in_addr) + v->namelen + 1;
+             return peer;
+           }
+        } 
+      peer = rip_peer_lookup_next (addr);
+
+      if (! peer)
+       return NULL;
+
+      oid_copy_addr (name + v->namelen, &peer->addr,
+                    sizeof (struct in_addr));
+      name[v->namelen + sizeof (struct in_addr)] = peer->domain;
+      *length = sizeof (struct in_addr) + v->namelen + 1;
+
+      return peer;
+    }
+  return NULL;
+}
+
+static u_char *
+rip2IfStatEntry (struct variable *v, oid name[], size_t *length,
+                int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+  static struct in_addr addr;
+  static long valid = SNMP_VALID;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+  
+  /* Lookup interface. */
+  ifp = rip2IfLookup (v, name, length, &addr, exact);
+  if (! ifp)
+    return NULL;
+
+  /* Fetch rip_interface information. */
+  ri = ifp->info;
+
+  switch (v->magic)
+    {
+    case RIP2IFSTATADDRESS:
+      return SNMP_IPADDRESS (addr);
+      break;
+    case RIP2IFSTATRCVBADPACKETS:
+      *var_len = sizeof (long);
+      return (u_char *) &ri->recv_badpackets;
+
+    case RIP2IFSTATRCVBADROUTES:
+      *var_len = sizeof (long);
+      return (u_char *) &ri->recv_badroutes;
+
+    case RIP2IFSTATSENTUPDATES:
+      *var_len = sizeof (long);
+      return (u_char *) &ri->sent_updates;
+
+    case RIP2IFSTATSTATUS:
+      *var_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &valid;
+
+    default:
+      return NULL;
+
+    }
+  return NULL;
+}
+
+static long
+rip2IfConfSend (struct rip_interface *ri)
+{
+#define doNotSend       1
+#define ripVersion1     2
+#define rip1Compatible  3
+#define ripVersion2     4
+#define ripV1Demand     5
+#define ripV2Demand     6
+
+  if (! ri->running)
+    return doNotSend;
+    
+  if (ri->ri_send & RIPv2)
+    return ripVersion2;
+  else if (ri->ri_send & RIPv1)
+    return ripVersion1;
+  else if (rip)
+    {
+      if (rip->version == RIPv2)
+       return ripVersion2;
+      else if (rip->version == RIPv1)
+       return ripVersion1;
+    }
+  return doNotSend;
+}
+
+static long
+rip2IfConfReceive (struct rip_interface *ri)
+{
+#define rip1            1
+#define rip2            2
+#define rip1OrRip2      3
+#define doNotReceive    4
+
+  if (! ri->running)
+    return doNotReceive;
+
+  if (ri->ri_receive == RI_RIP_VERSION_1_AND_2)
+    return rip1OrRip2;
+  else if (ri->ri_receive & RIPv2)
+    return ripVersion2;
+  else if (ri->ri_receive & RIPv1)
+    return ripVersion1;
+  else
+    return doNotReceive;
+}
+
+static u_char *
+rip2IfConfAddress (struct variable *v, oid name[], size_t *length,
+                  int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static struct in_addr addr;
+  static long valid = SNMP_INVALID;
+  static long domain = 0;
+  static long config = 0;
+  static u_int auth = 0;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+  
+  /* Lookup interface. */
+  ifp = rip2IfLookup (v, name, length, &addr, exact);
+  if (! ifp)
+    return NULL;
+
+  /* Fetch rip_interface information. */
+  ri = ifp->info;
+
+  switch (v->magic)
+    {
+    case RIP2IFCONFADDRESS:
+      *val_len = sizeof (struct in_addr);
+      return (u_char *) &addr;
+
+    case RIP2IFCONFDOMAIN:
+      *val_len = 2;
+      return (u_char *) &domain;
+
+    case RIP2IFCONFAUTHTYPE:
+      auth = ri->auth_type;
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *)&auth;
+
+    case RIP2IFCONFAUTHKEY:
+      *val_len = 0;
+      return (u_char *) &domain;
+    case RIP2IFCONFSEND:
+      config = rip2IfConfSend (ri);
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &config;
+    case RIP2IFCONFRECEIVE:
+      config = rip2IfConfReceive (ri);
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &config;
+
+    case RIP2IFCONFDEFAULTMETRIC:
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &ifp->metric;
+    case RIP2IFCONFSTATUS:
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &valid;
+    case RIP2IFCONFSRCADDRESS:
+      *val_len = sizeof (struct in_addr);
+      return (u_char *) &addr;
+
+    default:
+      return NULL;
+
+    }
+  return NULL;
+}
+
+static u_char *
+rip2PeerTable (struct variable *v, oid name[], size_t *length,
+              int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static struct in_addr addr;
+  static int version;
+  /* static time_t uptime; */
+
+  struct rip_peer *peer;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+  
+  /* Lookup interface. */
+  peer = rip2PeerLookup (v, name, length, &addr, exact);
+  if (! peer)
+    return NULL;
+
+  switch (v->magic)
+    {
+    case RIP2PEERADDRESS:
+      *val_len = sizeof (struct in_addr);
+      return (u_char *) &peer->addr;
+
+    case RIP2PEERDOMAIN:
+      *val_len = sizeof (int);
+      return (u_char *) &peer->domain;
+
+    case RIP2PEERLASTUPDATE:
+#if 0 
+      /* We don't know the SNMP agent startup time. We have two choices here:
+       * - assume ripd startup time equals SNMP agent startup time
+       * - don't support this variable, at all
+       * Currently, we do the latter...
+       */
+      *val_len = sizeof (time_t);
+      uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */
+      return (u_char *) &uptime;
+#else
+      return (u_char *) NULL;
+#endif
+
+    case RIP2PEERVERSION:
+      *val_len = sizeof (int);
+      version = peer->version;
+      return (u_char *) &version;
+
+    case RIP2PEERRCVBADPACKETS:
+      *val_len = sizeof (int);
+      return (u_char *) &peer->recv_badpackets;
+
+    case RIP2PEERRCVBADROUTES:
+      *val_len = sizeof (int);
+      return (u_char *) &peer->recv_badroutes;
+
+    default:
+      return NULL;
+
+    }
+  return NULL;
+}
+
+/* Register RIPv2-MIB. */
+void
+rip_snmp_init ()
+{
+  rip_ifaddr_table = route_table_init ();
+
+  smux_init (ripd_oid, sizeof (ripd_oid) / sizeof (oid));
+  REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
+  smux_start ();
+}
+#endif /* HAVE_SNMP */
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
new file mode 100644 (file)
index 0000000..b6caf3b
--- /dev/null
@@ -0,0 +1,691 @@
+/* RIPd and zebra interface.
+ * Copyright (C) 1997, 1999 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.  
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "routemap.h"
+#include "zclient.h"
+#include "log.h"
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+/* All information about zebra. */
+struct zclient *zclient = NULL;
+
+/* Callback prototypes for zebra client service. */
+int rip_interface_add (int, struct zclient *, zebra_size_t);
+int rip_interface_delete (int, struct zclient *, zebra_size_t);
+int rip_interface_address_add (int, struct zclient *, zebra_size_t);
+int rip_interface_address_delete (int, struct zclient *, zebra_size_t);
+int rip_interface_up (int, struct zclient *, zebra_size_t);
+int rip_interface_down (int, struct zclient *, zebra_size_t);
+\f
+/* RIPd to zebra command interface. */
+void
+rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, 
+                   u_int32_t metric, u_char distance)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_RIP])
+    {
+      api.type = ZEBRA_ROUTE_RIP;
+      api.flags = 0;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      api.ifindex_num = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = metric;
+
+      if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT)
+       {
+         SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+         api.distance = distance;
+       }
+
+      zapi_ipv4_add (zclient, p, &api);
+
+      rip_global_route_changes++;
+    }
+}
+
+void
+rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, 
+                      u_int32_t metric)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_RIP])
+    {
+      api.type = ZEBRA_ROUTE_RIP;
+      api.flags = 0;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      api.ifindex_num = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = metric;
+
+      zapi_ipv4_delete (zclient, p, &api);
+
+      rip_global_route_changes++;
+    }
+}
+
+/* Zebra route add and delete treatment. */
+int
+rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv4 api;
+  unsigned long ifindex;
+  struct in_addr nexthop;
+  struct prefix_ipv4 p;
+  
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop.s_addr = 0;
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop.s_addr = stream_get_ipv4 (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+
+  /* Then fetch IPv4 prefixes. */
+  if (command == ZEBRA_IPV4_ROUTE_ADD)
+    rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop);
+  else 
+    rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex);
+
+  return 0;
+}
+
+void
+rip_zclient_reset ()
+{
+  zclient_reset (zclient);
+}
+
+/* RIP route-map set for redistribution */
+void
+rip_routemap_set (int type, char *name)
+{
+  if (rip->route_map[type].name)
+    free(rip->route_map[type].name);
+
+  rip->route_map[type].name = strdup (name);
+  rip->route_map[type].map = route_map_lookup_by_name (name);
+}
+
+void
+rip_redistribute_metric_set (int type, int metric)
+{
+  rip->route_map[type].metric_config = 1;
+  rip->route_map[type].metric = metric;
+}
+
+int
+rip_metric_unset (int type,int metric)
+{
+#define DONT_CARE_METRIC_RIP 17  
+  if (metric != DONT_CARE_METRIC_RIP &&
+      rip->route_map[type].metric != metric)
+    return 1;
+  rip->route_map[type].metric_config = 0;
+  rip->route_map[type].metric = 0;
+  return 0;
+}
+
+/* RIP route-map unset for redistribution */
+int
+rip_routemap_unset (int type,char *name)
+{
+  if (! rip->route_map[type].name ||
+      (name != NULL && strcmp(rip->route_map[type].name,name)))
+    return 1;
+
+  free (rip->route_map[type].name);
+  rip->route_map[type].name = NULL;
+  rip->route_map[type].map = NULL;
+
+  return 0;
+}
+\f
+/* Redistribution types */
+static struct {
+  int type;
+  int str_min_len;
+  char *str;
+} redist_type[] = {
+  {ZEBRA_ROUTE_KERNEL,  1, "kernel"},
+  {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+  {ZEBRA_ROUTE_STATIC,  1, "static"},
+  {ZEBRA_ROUTE_OSPF,    1, "ospf"},
+  {ZEBRA_ROUTE_BGP,     1, "bgp"},
+  {0, 0, NULL}
+};
+
+DEFUN (router_zebra,
+       router_zebra_cmd,
+       "router zebra",
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  vty->node = ZEBRA_NODE;
+  zclient->enable = 1;
+  zclient_start (zclient);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+       no_router_zebra_cmd,
+       "no router zebra",
+       NO_STR
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  zclient->enable = 0;
+  zclient_stop (zclient);
+  return CMD_SUCCESS;
+}
+
+int
+rip_redistribute_set (int type)
+{
+  if (zclient->redist[type])
+    return CMD_SUCCESS;
+
+  zclient->redist[type] = 1;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_redistribute_unset (int type)
+{
+  if (! zclient->redist[type])
+    return CMD_SUCCESS;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+
+  /* Remove the routes from RIP table. */
+  rip_redistribute_withdraw (type);
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_redistribute_check (int type)
+{
+  return (zclient->redist[type]);
+}
+
+void
+rip_redistribute_clean ()
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++)
+    {
+      if (zclient->redist[redist_type[i].type])
+       {
+         if (zclient->sock > 0)
+           zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE,
+                                    zclient->sock, redist_type[i].type);
+
+         zclient->redist[redist_type[i].type] = 0;
+
+         /* Remove the routes from RIP table. */
+         rip_redistribute_withdraw (redist_type[i].type);
+       }
+    }
+}
+
+DEFUN (rip_redistribute_rip,
+       rip_redistribute_rip_cmd,
+       "redistribute rip",
+       "Redistribute information from another routing protocol\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  zclient->redist[ZEBRA_ROUTE_RIP] = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_redistribute_rip,
+       no_rip_redistribute_rip_cmd,
+       "no redistribute rip",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  zclient->redist[ZEBRA_ROUTE_RIP] = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_redistribute_type,
+       rip_redistribute_type_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp)",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int i;
+
+  for(i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp (redist_type[i].str, argv[0], 
+                  redist_type[i].str_min_len) == 0) 
+       {
+         zclient_redistribute_set (zclient, redist_type[i].type);
+         return CMD_SUCCESS;
+       }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type,
+       no_rip_redistribute_type_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp)",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+                 redist_type[i].str_min_len) == 0) 
+       {
+         rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP);
+         rip_routemap_unset (redist_type[i].type,NULL);
+         rip_redistribute_unset (redist_type[i].type);
+         return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (rip_redistribute_type_routemap,
+       rip_redistribute_type_routemap_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) {
+    if (strncmp(redist_type[i].str, argv[0],
+               redist_type[i].str_min_len) == 0) 
+      {
+       rip_routemap_set (redist_type[i].type, argv[1]);
+       zclient_redistribute_set (zclient, redist_type[i].type);
+       return CMD_SUCCESS;
+      }
+  }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type_routemap,
+       no_rip_redistribute_type_routemap_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+                 redist_type[i].str_min_len) == 0) 
+       {
+         if (rip_routemap_unset (redist_type[i].type,argv[1]))
+           return CMD_WARNING;
+         rip_redistribute_unset (redist_type[i].type);
+         return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (rip_redistribute_type_metric,
+       rip_redistribute_type_metric_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  int i;
+  int metric;
+
+  metric = atoi (argv[1]);
+
+  for (i = 0; redist_type[i].str; i++) {
+    if (strncmp(redist_type[i].str, argv[0],
+               redist_type[i].str_min_len) == 0) 
+      {
+       rip_redistribute_metric_set (redist_type[i].type, metric);
+       zclient_redistribute_set (zclient, redist_type[i].type);
+       return CMD_SUCCESS;
+      }
+  }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type_metric,
+       no_rip_redistribute_type_metric_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+                 redist_type[i].str_min_len) == 0) 
+       {
+         if (rip_metric_unset (redist_type[i].type, atoi(argv[1])))
+           return CMD_WARNING;
+         rip_redistribute_unset (redist_type[i].type);
+         return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type_metric_routemap,
+       no_rip_redistribute_type_metric_routemap_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+                 redist_type[i].str_min_len) == 0) 
+       {
+         if (rip_metric_unset (redist_type[i].type, atoi(argv[1])))
+           return CMD_WARNING;
+         if (rip_routemap_unset (redist_type[i].type, argv[2]))
+           {
+             rip_redistribute_metric_set(redist_type[i].type, atoi(argv[1]));   
+             return CMD_WARNING;
+           }
+         rip_redistribute_unset (redist_type[i].type);
+         return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+         VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+\f
+/* Default information originate. */
+
+DEFUN (rip_default_information_originate,
+       rip_default_information_originate_cmd,
+       "default-information originate",
+       "Control distribution of default route\n"
+       "Distribute a default route\n")
+{
+  struct prefix_ipv4 p;
+
+  if (! rip->default_information)
+    {
+      memset (&p, 0, sizeof (struct prefix_ipv4));
+      p.family = AF_INET;
+
+      rip->default_information = 1;
+  
+      rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_default_information_originate,
+       no_rip_default_information_originate_cmd,
+       "no default-information originate",
+       NO_STR
+       "Control distribution of default route\n"
+       "Distribute a default route\n")
+{
+  struct prefix_ipv4 p;
+
+  if (rip->default_information)
+    {
+      memset (&p, 0, sizeof (struct prefix_ipv4));
+      p.family = AF_INET;
+
+      rip->default_information = 0;
+  
+      rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+    }
+
+  return CMD_SUCCESS;
+}
+\f
+/* RIP configuration write function. */
+int
+config_write_zebra (struct vty *vty)
+{
+  if (! zclient->enable)
+    {
+      vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+      return 1;
+    }
+  else if (! zclient->redist[ZEBRA_ROUTE_RIP])
+    {
+      vty_out (vty, "router zebra%s", VTY_NEWLINE);
+      vty_out (vty, " no redistribute rip%s", VTY_NEWLINE);
+      return 1;
+    }
+  return 0;
+}
+
+int
+config_write_rip_redistribute (struct vty *vty, int config_mode)
+{
+  int i;
+  char *str[] = { "system", "kernel", "connected", "static", "rip",
+                 "ripng", "ospf", "ospf6", "bgp"};
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    if (i != zclient->redist_default && zclient->redist[i])
+      {
+       if (config_mode)
+         {
+           if (rip->route_map[i].metric_config)
+             {
+               if (rip->route_map[i].name)
+                 vty_out (vty, " redistribute %s metric %d route-map %s%s",
+                          str[i], rip->route_map[i].metric,
+                          rip->route_map[i].name,
+                          VTY_NEWLINE);
+               else
+                 vty_out (vty, " redistribute %s metric %d%s",
+                          str[i], rip->route_map[i].metric,
+                          VTY_NEWLINE);
+             }
+           else
+             {
+               if (rip->route_map[i].name)
+                 vty_out (vty, " redistribute %s route-map %s%s",
+                          str[i], rip->route_map[i].name,
+                          VTY_NEWLINE);
+               else
+                 vty_out (vty, " redistribute %s%s", str[i],
+                          VTY_NEWLINE);
+             }
+         }
+       else
+         vty_out (vty, " %s", str[i]);
+      }
+  return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-router)# ",
+};
+
+void
+rip_zclient_init ()
+{
+  /* Set default value to the zebra client structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_RIP);
+  zclient->interface_add = rip_interface_add;
+  zclient->interface_delete = rip_interface_delete;
+  zclient->interface_address_add = rip_interface_address_add;
+  zclient->interface_address_delete = rip_interface_address_delete;
+  zclient->ipv4_route_add = rip_zebra_read_ipv4;
+  zclient->ipv4_route_delete = rip_zebra_read_ipv4;
+  zclient->interface_up = rip_interface_up;
+  zclient->interface_down = rip_interface_down;
+  
+  /* Install zebra node. */
+  install_node (&zebra_node, config_write_zebra);
+
+  /* Install command elements to zebra node. */ 
+  install_element (CONFIG_NODE, &router_zebra_cmd);
+  install_element (CONFIG_NODE, &no_router_zebra_cmd);
+  install_default (ZEBRA_NODE);
+  install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd);
+  install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd);
+
+  /* Install command elements to rip node. */
+  install_element (RIP_NODE, &rip_redistribute_type_cmd);
+  install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd);
+  install_element (RIP_NODE, &rip_redistribute_type_metric_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd);
+  install_element (RIP_NODE, &rip_default_information_originate_cmd);
+  install_element (RIP_NODE, &no_rip_default_information_originate_cmd);
+}
diff --git a/ripd/ripd.c b/ripd/ripd.c
new file mode 100644 (file)
index 0000000..c017fe5
--- /dev/null
@@ -0,0 +1,3536 @@
+/* RIP version 1 and 2.
+ * Copyright (C) 1997, 98, 99 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.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "stream.h"
+#include "filter.h"
+#include "sockunion.h"
+#include "routemap.h"
+#include "plist.h"
+#include "distribute.h"
+#include "md5-gnu.h"
+#include "keychain.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+/* RIP Structure. */
+struct rip *rip = NULL;
+
+/* RIP neighbor address table. */
+struct route_table *rip_neighbor_table;
+
+/* RIP route changes. */
+long rip_global_route_changes = 0;
+
+/* RIP queries. */
+long rip_global_queries = 0;
+\f
+/* Prototypes. */
+void rip_event (enum rip_event, int);
+
+void rip_output_process (struct interface *, struct sockaddr_in *, 
+                        int, u_char);
+
+/* RIP output routes type. */
+enum
+{
+  rip_all_route,
+  rip_changed_route
+};
+\f
+/* RIP command strings. */
+struct message rip_msg[] = 
+{
+  {RIP_REQUEST,    "REQUEST"},
+  {RIP_RESPONSE,   "RESPONSE"},
+  {RIP_TRACEON,    "TRACEON"},
+  {RIP_TRACEOFF,   "TRACEOFF"},
+  {RIP_POLL,       "POLL"},
+  {RIP_POLL_ENTRY, "POLL ENTRY"},
+  {0,              NULL}
+};
+
+/* Each route type's strings and default preference. */
+struct
+{  
+  int key;
+  char *str;
+  char *str_long;
+} route_info[] =
+{
+  { ZEBRA_ROUTE_SYSTEM,  "X", "system"},
+  { ZEBRA_ROUTE_KERNEL,  "K", "kernel"},
+  { ZEBRA_ROUTE_CONNECT, "C", "connected"},
+  { ZEBRA_ROUTE_STATIC,  "S", "static"},
+  { ZEBRA_ROUTE_RIP,     "R", "rip"},
+  { ZEBRA_ROUTE_RIPNG,   "R", "ripng"},
+  { ZEBRA_ROUTE_OSPF,    "O", "ospf"},
+  { ZEBRA_ROUTE_OSPF6,   "O", "ospf6"},
+  { ZEBRA_ROUTE_BGP,     "B", "bgp"}
+};
+\f
+/* Utility function to set boradcast option to the socket. */
+int
+sockopt_broadcast (int sock)
+{
+  int ret;
+  int on = 1;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
+  if (ret < 0)
+    {
+      zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
+      return -1;
+    }
+  return 0;
+}
+
+int
+rip_route_rte (struct rip_info *rinfo)
+{
+  return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
+}
+
+struct rip_info *
+rip_info_new ()
+{
+  struct rip_info *new;
+
+  new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
+  memset (new, 0, sizeof (struct rip_info));
+  return new;
+}
+
+void
+rip_info_free (struct rip_info *rinfo)
+{
+  XFREE (MTYPE_RIP_INFO, rinfo);
+}
+
+/* RIP route garbage collect timer. */
+int
+rip_garbage_collect (struct thread *t)
+{
+  struct rip_info *rinfo;
+  struct route_node *rp;
+
+  rinfo = THREAD_ARG (t);
+  rinfo->t_garbage_collect = NULL;
+
+  /* Off timeout timer. */
+  RIP_TIMER_OFF (rinfo->t_timeout);
+  
+  /* Get route_node pointer. */
+  rp = rinfo->rp;
+
+  /* Unlock route_node. */
+  rp->info = NULL;
+  route_unlock_node (rp);
+
+  /* Free RIP routing information. */
+  rip_info_free (rinfo);
+
+  return 0;
+}
+
+/* Timeout RIP routes. */
+int
+rip_timeout (struct thread *t)
+{
+  struct rip_info *rinfo;
+  struct route_node *rn;
+
+  rinfo = THREAD_ARG (t);
+  rinfo->t_timeout = NULL;
+
+  rn = rinfo->rp;
+
+  /* - The garbage-collection timer is set for 120 seconds. */
+  RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, 
+               rip->garbage_time);
+
+  rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
+                        rinfo->metric);
+  /* - The metric for the route is set to 16 (infinity).  This causes
+     the route to be removed from service. */
+  rinfo->metric = RIP_METRIC_INFINITY;
+  rinfo->flags &= ~RIP_RTF_FIB;
+
+  /* - The route change flag is to indicate that this entry has been
+     changed. */
+  rinfo->flags |= RIP_RTF_CHANGED;
+
+  /* - The output process is signalled to trigger a response. */
+  rip_event (RIP_TRIGGERED_UPDATE, 0);
+
+  return 0;
+}
+
+void
+rip_timeout_update (struct rip_info *rinfo)
+{
+  if (rinfo->metric != RIP_METRIC_INFINITY)
+    {
+      RIP_TIMER_OFF (rinfo->t_timeout);
+      RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
+    }
+}
+
+int
+rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
+{
+  struct distribute *dist;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  /* Input distribute-list filtering. */
+  if (ri->list[RIP_FILTER_IN])
+    {
+      if (access_list_apply (ri->list[RIP_FILTER_IN], 
+                            (struct prefix *) p) == FILTER_DENY)
+       {
+         if (IS_RIP_DEBUG_PACKET)
+           zlog_info ("%s/%d filtered by distribute in",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         return -1;
+       }
+    }
+  if (ri->prefix[RIP_FILTER_IN])
+    {
+      if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], 
+                            (struct prefix *) p) == PREFIX_DENY)
+       {
+         if (IS_RIP_DEBUG_PACKET)
+           zlog_info ("%s/%d filtered by prefix-list in",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         return -1;
+       }
+    }
+
+  /* All interface filter check. */
+  dist = distribute_lookup (NULL);
+  if (dist)
+    {
+      if (dist->list[DISTRIBUTE_IN])
+       {
+         alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
+           
+         if (alist)
+           {
+             if (access_list_apply (alist,
+                                    (struct prefix *) p) == FILTER_DENY)
+               {
+                 if (IS_RIP_DEBUG_PACKET)
+                   zlog_info ("%s/%d filtered by distribute in",
+                              inet_ntoa (p->prefix), p->prefixlen);
+                 return -1;
+               }
+           }
+       }
+      if (dist->prefix[DISTRIBUTE_IN])
+       {
+         plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
+         
+         if (plist)
+           {
+             if (prefix_list_apply (plist,
+                                    (struct prefix *) p) == PREFIX_DENY)
+               {
+                 if (IS_RIP_DEBUG_PACKET)
+                   zlog_info ("%s/%d filtered by prefix-list in",
+                              inet_ntoa (p->prefix), p->prefixlen);
+                 return -1;
+               }
+           }
+       }
+    }
+  return 0;
+}
+
+int
+rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
+{
+  struct distribute *dist;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  if (ri->list[RIP_FILTER_OUT])
+    {
+      if (access_list_apply (ri->list[RIP_FILTER_OUT],
+                            (struct prefix *) p) == FILTER_DENY)
+       {
+         if (IS_RIP_DEBUG_PACKET)
+           zlog_info ("%s/%d is filtered by distribute out",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         return -1;
+       }
+    }
+  if (ri->prefix[RIP_FILTER_OUT])
+    {
+      if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
+                            (struct prefix *) p) == PREFIX_DENY)
+       {
+         if (IS_RIP_DEBUG_PACKET)
+           zlog_info ("%s/%d is filtered by prefix-list out",
+                      inet_ntoa (p->prefix), p->prefixlen);
+         return -1;
+       }
+    }
+
+  /* All interface filter check. */
+  dist = distribute_lookup (NULL);
+  if (dist)
+    {
+      if (dist->list[DISTRIBUTE_OUT])
+       {
+         alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
+           
+         if (alist)
+           {
+             if (access_list_apply (alist,
+                                    (struct prefix *) p) == FILTER_DENY)
+               {
+                 if (IS_RIP_DEBUG_PACKET)
+                   zlog_info ("%s/%d filtered by distribute out",
+                              inet_ntoa (p->prefix), p->prefixlen);
+                 return -1;
+               }
+           }
+       }
+      if (dist->prefix[DISTRIBUTE_OUT])
+       {
+         plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
+         
+         if (plist)
+           {
+             if (prefix_list_apply (plist,
+                                    (struct prefix *) p) == PREFIX_DENY)
+               {
+                 if (IS_RIP_DEBUG_PACKET)
+                   zlog_info ("%s/%d filtered by prefix-list out",
+                              inet_ntoa (p->prefix), p->prefixlen);
+                 return -1;
+               }
+           }
+       }
+    }
+  return 0;
+}
+
+/* Check nexthop address validity. */
+static int
+rip_nexthop_check (struct in_addr *addr)
+{
+  listnode node;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+
+  /* If nexthop address matches local configured address then it is
+     invalid nexthop. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {           
+         ifc = getdata (cnode);
+         p = ifc->address;
+
+         if (p->family == AF_INET
+             && IPV4_ADDR_SAME (&p->u.prefix4, addr))
+           return -1;
+       }
+    }
+  return 0;
+}
+
+/* RIP add route to routing table. */
+void
+rip_rte_process (struct rte *rte, struct sockaddr_in *from,
+                struct interface *ifp)
+
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri;
+  struct in_addr *nexthop;
+  u_char oldmetric;
+  int same = 0;
+
+  /* Make prefix structure. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = rte->prefix;
+  p.prefixlen = ip_masklen (rte->mask);
+
+  /* Make sure mask is applied. */
+  apply_mask_ipv4 (&p);
+
+  /* Apply input filters. */
+  ri = ifp->info;
+
+  ret = rip_incoming_filter (&p, ri);
+  if (ret < 0)
+    return;
+
+  /* Once the entry has been validated, update the metric by
+     adding the cost of the network on wich the message
+     arrived. If the result is greater than infinity, use infinity
+     (RFC2453 Sec. 3.9.2) */
+  /* Zebra ripd can handle offset-list in. */
+  ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
+
+  /* If offset-list does not modify the metric use interface's
+     metric. */
+  if (! ret)
+    rte->metric += ifp->metric;
+
+  if (rte->metric > RIP_METRIC_INFINITY)
+    rte->metric = RIP_METRIC_INFINITY;
+
+  /* Set nexthop pointer. */
+  if (rte->nexthop.s_addr == 0)
+    nexthop = &from->sin_addr;
+  else
+    nexthop = &rte->nexthop;
+
+  /* Check nexthop address. */
+  if (rip_nexthop_check (nexthop) < 0)
+    {
+      if (IS_RIP_DEBUG_PACKET)
+       zlog_info ("Nexthop address %s is invalid", inet_ntoa (*nexthop));
+      return;
+    }
+
+  /* Get index for the prefix. */
+  rp = route_node_get (rip->table, (struct prefix *) &p);
+
+  /* Check to see whether there is already RIP route on the table. */
+  rinfo = rp->info;
+
+  if (rinfo)
+    {
+      /* Redistributed route check. */
+      if (rinfo->type != ZEBRA_ROUTE_RIP
+         && rinfo->metric != RIP_METRIC_INFINITY)
+       return;
+
+      /* Local static route. */
+      if (rinfo->type == ZEBRA_ROUTE_RIP
+         && rinfo->sub_type == RIP_ROUTE_STATIC
+         && rinfo->metric != RIP_METRIC_INFINITY)
+       return;
+    }
+  
+  if (! rinfo)
+    {
+      /* Now, check to see whether there is already an explicit route
+        for the destination prefix.  If there is no such route, add
+        this route to the routing table, unless the metric is
+        infinity (there is no point in adding a route which
+        unusable). */
+      if (rte->metric != RIP_METRIC_INFINITY)
+       {
+         rinfo = rip_info_new ();
+         
+         /* - Setting the destination prefix and length to those in
+            the RTE. */
+         rinfo->rp = rp;
+
+         /* - Setting the metric to the newly calculated metric (as
+            described above). */
+         rinfo->metric = rte->metric;
+         rinfo->tag = ntohs (rte->tag);
+
+         /* - Set the next hop address to be the address of the router
+            from which the datagram came or the next hop address
+            specified by a next hop RTE. */
+         IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
+         IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
+         rinfo->ifindex = ifp->ifindex;
+
+         /* - Initialize the timeout for the route.  If the
+            garbage-collection timer is running for this route, stop it
+            (see section 2.3 for a discussion of the timers). */
+         rip_timeout_update (rinfo);
+
+         /* - Set the route change flag. */
+         rinfo->flags |= RIP_RTF_CHANGED;
+
+         /* - Signal the output process to trigger an update (see section
+            2.5). */
+         rip_event (RIP_TRIGGERED_UPDATE, 0);
+
+         /* Finally, route goes into the kernel. */
+         rinfo->type = ZEBRA_ROUTE_RIP;
+         rinfo->sub_type = RIP_ROUTE_RTE;
+
+         /* Set distance value. */
+         rinfo->distance = rip_distance_apply (rinfo);
+
+         rp->info = rinfo;
+         rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
+                             rinfo->distance);
+         rinfo->flags |= RIP_RTF_FIB;
+       }
+    }
+  else
+    {
+      /* Route is there but we are not sure the route is RIP or not. */
+      rinfo = rp->info;
+         
+      /* If there is an existing route, compare the next hop address
+        to the address of the router from which the datagram came.
+        If this datagram is from the same router as the existing
+        route, reinitialize the timeout.  */
+      same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr);
+
+      if (same)
+       rip_timeout_update (rinfo);
+
+      /* Next, compare the metrics.  If the datagram is from the same
+        router as the existing route, and the new metric is different
+        than the old one; or, if the new metric is lower than the old
+        one; do the following actions: */
+      if ((same && rinfo->metric != rte->metric) ||
+         rte->metric < rinfo->metric)
+       {
+         /* - Adopt the route from the datagram.  That is, put the
+            new metric in, and adjust the next hop address (if
+            necessary). */
+         oldmetric = rinfo->metric;
+         rinfo->metric = rte->metric;
+         rinfo->tag = ntohs (rte->tag);
+         IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
+         rinfo->ifindex = ifp->ifindex;
+         rinfo->distance = rip_distance_apply (rinfo);
+
+         /* Should a new route to this network be established
+            while the garbage-collection timer is running, the
+            new route will replace the one that is about to be
+            deleted.  In this case the garbage-collection timer
+            must be cleared. */
+
+         if (oldmetric == RIP_METRIC_INFINITY &&
+             rinfo->metric < RIP_METRIC_INFINITY)
+           {
+             rinfo->type = ZEBRA_ROUTE_RIP;
+             rinfo->sub_type = RIP_ROUTE_RTE;
+
+             RIP_TIMER_OFF (rinfo->t_garbage_collect);
+
+             if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
+               IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
+
+             rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
+                                 rinfo->distance);
+             rinfo->flags |= RIP_RTF_FIB;
+           }
+
+         /* Update nexthop and/or metric value.  */
+         if (oldmetric != RIP_METRIC_INFINITY)
+           {
+             rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
+             rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
+                                 rinfo->distance);
+             rinfo->flags |= RIP_RTF_FIB;
+
+             if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
+               IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
+           }
+
+         /* - Set the route change flag and signal the output process
+            to trigger an update. */
+         rinfo->flags |= RIP_RTF_CHANGED;
+         rip_event (RIP_TRIGGERED_UPDATE, 0);
+
+         /* - If the new metric is infinity, start the deletion
+            process (described above); */
+         if (rinfo->metric == RIP_METRIC_INFINITY)
+           {
+             /* If the new metric is infinity, the deletion process
+                begins for the route, which is no longer used for
+                routing packets.  Note that the deletion process is
+                started only when the metric is first set to
+                infinity.  If the metric was already infinity, then a
+                new deletion process is not started. */
+             if (oldmetric != RIP_METRIC_INFINITY)
+               {
+                 /* - The garbage-collection timer is set for 120 seconds. */
+                 RIP_TIMER_ON (rinfo->t_garbage_collect, 
+                               rip_garbage_collect, rip->garbage_time);
+                 RIP_TIMER_OFF (rinfo->t_timeout);
+
+                 /* - The metric for the route is set to 16
+                    (infinity).  This causes the route to be removed
+                    from service.*/
+                 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
+                 rinfo->flags &= ~RIP_RTF_FIB;
+
+                 /* - The route change flag is to indicate that this
+                    entry has been changed. */
+                 /* - The output process is signalled to trigger a
+                     response. */
+                 ;  /* Above processes are already done previously. */
+               }
+           }
+         else
+           {
+             /* otherwise, re-initialize the timeout. */
+             rip_timeout_update (rinfo);
+           }
+       }
+      /* Unlock tempolary lock of the route. */
+      route_unlock_node (rp);
+    }
+}
+
+/* Dump RIP packet */
+void
+rip_packet_dump (struct rip_packet *packet, int size, char *sndrcv)
+{
+  caddr_t lim;
+  struct rte *rte;
+  char *command_str;
+  char pbuf[BUFSIZ], nbuf[BUFSIZ];
+  u_char netmask = 0;
+  u_char *p;
+
+  /* Set command string. */
+  if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
+    command_str = lookup (rip_msg, packet->command);
+  else
+    command_str = "unknown";
+
+  /* Dump packet header. */
+  zlog_info ("%s %s version %d packet size %d",
+            sndrcv, command_str, packet->version, size);
+
+  /* Dump each routing table entry. */
+  rte = packet->rte;
+  
+  for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
+    {
+      if (packet->version == RIPv2)
+       {
+         netmask = ip_masklen (rte->mask);
+
+         if (ntohs (rte->family) == 0xffff)
+            {
+             if (ntohs (rte->tag) == RIP_AUTH_SIMPLE_PASSWORD)
+               {
+                 p = (u_char *)&rte->prefix;
+
+                 zlog_info ("  family 0x%X type %d auth string: %s",
+                            ntohs (rte->family), ntohs (rte->tag), p);
+               }
+             else if (ntohs (rte->tag) == RIP_AUTH_MD5)
+               {
+                 struct rip_md5_info *md5;
+
+                 md5 = (struct rip_md5_info *) &packet->rte;
+
+                 zlog_info ("  family 0x%X type %d (MD5 authentication)",
+                            ntohs (md5->family), ntohs (md5->type));
+                 zlog_info ("    RIP-2 packet len %d Key ID %d"
+                            " Auth Data len %d", ntohs (md5->packet_len),
+                            md5->keyid, md5->auth_len);
+                 zlog_info ("    Sequence Number %ld", (u_long)ntohl (md5->sequence));
+               }
+             else if (ntohs (rte->tag) == RIP_AUTH_DATA)
+               {
+                 p = (u_char *)&rte->prefix;
+
+                 zlog_info ("  family 0x%X type %d (MD5 data)",
+                            ntohs (rte->family), ntohs (rte->tag));
+                 zlog_info ("    MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
+                            "%02X%02X%02X%02X%02X%02X%02X",
+                            p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],
+                            p[9],p[10],p[11],p[12],p[13],p[14],p[15]);
+               }
+             else
+               {
+                 zlog_info ("  family 0x%X type %d (Unknown auth type)",
+                            ntohs (rte->family), ntohs (rte->tag));
+               }
+            }
+         else
+           zlog_info ("  %s/%d -> %s family %d tag %d metric %ld",
+                      inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),netmask,
+                      inet_ntop (AF_INET, &rte->nexthop, nbuf, BUFSIZ),
+                      ntohs (rte->family), ntohs (rte->tag), 
+                      (u_long)ntohl (rte->metric));
+       }
+      else
+       {
+         zlog_info ("  %s family %d tag %d metric %ld", 
+                    inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
+                    ntohs (rte->family), ntohs (rte->tag),
+                    (u_long)ntohl (rte->metric));
+       }
+    }
+}
+
+/* Check if the destination address is valid (unicast; not net 0
+   or 127) (RFC2453 Section 3.9.2 - Page 26).  But we don't
+   check net 0 because we accept default route. */
+int
+rip_destination_check (struct in_addr addr)
+{
+  u_int32_t destination;
+
+  /* Convert to host byte order. */
+  destination = ntohl (addr.s_addr);
+
+  if (IPV4_NET127 (destination))
+    return 0;
+
+  /* Net 0 may match to the default route. */
+  if (IPV4_NET0 (destination) && destination != 0)
+    return 0;
+
+  /* Unicast address must belong to class A, B, C. */
+  if (IN_CLASSA (destination))
+    return 1;
+  if (IN_CLASSB (destination))
+    return 1;
+  if (IN_CLASSC (destination))
+    return 1;
+
+  return 0;
+}
+
+/* RIP version 2 authentication. */
+int
+rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
+                         struct interface *ifp)
+{
+  struct rip_interface *ri;
+  char *auth_str;
+
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("RIPv2 simple password authentication from %s",
+              inet_ntoa (from->sin_addr));
+
+  ri = ifp->info;
+
+  if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
+      || ntohs (rte->tag) != RIP_AUTH_SIMPLE_PASSWORD)
+    return 0;
+
+  /* Simple password authentication. */
+  if (ri->auth_str)
+    {
+      auth_str = (char *) &rte->prefix;
+         
+      if (strncmp (auth_str, ri->auth_str, 16) == 0)
+       return 1;
+    }
+  if (ri->key_chain)
+    {
+      struct keychain *keychain;
+      struct key *key;
+
+      keychain = keychain_lookup (ri->key_chain);
+      if (keychain == NULL)
+       return 0;
+
+      key = key_match_for_accept (keychain, (char *) &rte->prefix);
+      if (key)
+       return 1;
+    }
+  return 0;
+}
+
+/* RIP version 2 authentication with MD5. */
+int
+rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
+             struct interface *ifp)
+{
+  struct rip_interface *ri;
+  struct rip_md5_info *md5;
+  struct rip_md5_data *md5data;
+  struct keychain *keychain;
+  struct key *key;
+  struct md5_ctx ctx;
+  u_char pdigest[RIP_AUTH_MD5_SIZE];
+  u_char digest[RIP_AUTH_MD5_SIZE];
+  u_int16_t packet_len;
+  char *auth_str = NULL;
+  
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("RIPv2 MD5 authentication from %s", inet_ntoa (from->sin_addr));
+
+  ri = ifp->info;
+  md5 = (struct rip_md5_info *) &packet->rte;
+
+  /* Check auth type. */
+  if (ri->auth_type != RIP_AUTH_MD5 || ntohs (md5->type) != RIP_AUTH_MD5)
+    return 0;
+
+  if (md5->auth_len != RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE)
+    return 0;
+
+  if (ri->key_chain)
+    {
+      keychain = keychain_lookup (ri->key_chain);
+      if (keychain == NULL)
+       return 0;
+
+      key = key_lookup_for_accept (keychain, md5->keyid);
+      if (key == NULL)
+       return 0;
+
+      auth_str = key->string;
+    }
+
+  if (ri->auth_str)
+    auth_str = ri->auth_str;
+
+  if (! auth_str)
+    return 0;
+
+  /* MD5 digest authentication. */
+  packet_len = ntohs (md5->packet_len);
+  md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len);
+
+  /* Save digest to pdigest. */
+  memcpy (pdigest, md5data->digest, RIP_AUTH_MD5_SIZE);
+
+  /* Overwrite digest by my secret. */
+  memset (md5data->digest, 0, RIP_AUTH_MD5_SIZE);
+  strncpy (md5data->digest, auth_str, RIP_AUTH_MD5_SIZE);
+
+  md5_init_ctx (&ctx);
+  md5_process_bytes (packet, packet_len + md5->auth_len, &ctx);
+  md5_finish_ctx (&ctx, digest);
+
+  if (memcmp (pdigest, digest, RIP_AUTH_MD5_SIZE) == 0)
+    return packet_len;
+  else
+    return 0;
+}
+
+void
+rip_auth_md5_set (struct stream *s, struct interface *ifp)
+{
+  struct rip_interface *ri;
+  struct keychain *keychain = NULL;
+  struct key *key = NULL;
+  unsigned long len;
+  struct md5_ctx ctx;
+  unsigned char secret[RIP_AUTH_MD5_SIZE];
+  unsigned char digest[RIP_AUTH_MD5_SIZE];
+  char *auth_str = NULL;
+
+  ri = ifp->info;
+
+  /* Make it sure this interface is configured as MD5
+     authentication. */
+  if (ri->auth_type != RIP_AUTH_MD5)
+    return;
+
+  /* Lookup key chain. */
+  if (ri->key_chain)
+    {
+      keychain = keychain_lookup (ri->key_chain);
+      if (keychain == NULL)
+       return;
+
+      /* Lookup key. */
+      key = key_lookup_for_send (keychain);
+      if (key == NULL)
+       return;
+
+      auth_str = key->string;
+    }
+
+  if (ri->auth_str)
+    auth_str = ri->auth_str;
+
+  if (! auth_str)
+    return;
+
+  /* Get packet length. */
+  len = s->putp;
+
+  /* Check packet length. */
+  if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
+    {
+      zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
+      return;
+    }
+
+  /* Move RTE. */
+  memmove (s->data + RIP_HEADER_SIZE + RIP_RTE_SIZE,
+          s->data + RIP_HEADER_SIZE,
+          len - RIP_HEADER_SIZE);
+  
+  /* Set pointer to authentication header. */
+  stream_set_putp (s, RIP_HEADER_SIZE);
+  len += RIP_RTE_SIZE;
+
+  /* MD5 authentication. */
+  stream_putw (s, 0xffff);
+  stream_putw (s, RIP_AUTH_MD5);
+
+  /* RIP-2 Packet length.  Actual value is filled in
+     rip_auth_md5_set(). */
+  stream_putw (s, len);
+
+  /* Key ID. */
+  if (key)
+    stream_putc (s, key->index % 256);
+  else
+    stream_putc (s, 1);
+
+  /* Auth Data Len.  Set 16 for MD5 authentication
+     data. */
+  stream_putc (s, RIP_AUTH_MD5_SIZE + RIP_HEADER_SIZE);
+
+  /* Sequence Number (non-decreasing). */
+  /* RFC2080: The value used in the sequence number is
+     arbitrary, but two suggestions are the time of the
+     message's creation or a simple message counter. */
+  stream_putl (s, time (NULL));
+             
+  /* Reserved field must be zero. */
+  stream_putl (s, 0);
+  stream_putl (s, 0);
+
+  /* Set pointer to authentication data. */
+  stream_set_putp (s, len);
+
+  /* Set authentication data. */
+  stream_putw (s, 0xffff);
+  stream_putw (s, 0x01);
+
+  /* Generate a digest for the RIP packet. */
+  memset (secret, 0, RIP_AUTH_MD5_SIZE);
+  strncpy (secret, auth_str, RIP_AUTH_MD5_SIZE);
+  md5_init_ctx (&ctx);
+  md5_process_bytes (s->data, s->endp, &ctx);
+  md5_process_bytes (secret, RIP_AUTH_MD5_SIZE, &ctx);
+  md5_finish_ctx (&ctx, digest);
+
+  /* Copy the digest to the packet. */
+  stream_write (s, digest, RIP_AUTH_MD5_SIZE);
+}
+
+/* RIP routing information. */
+void
+rip_response_process (struct rip_packet *packet, int size, 
+                     struct sockaddr_in *from, struct interface *ifp)
+{
+  caddr_t lim;
+  struct rte *rte;
+      
+  /* The Response must be ignored if it is not from the RIP
+     port. (RFC2453 - Sec. 3.9.2)*/
+  if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) 
+    {
+      zlog_info ("response doesn't come from RIP port: %d",
+                from->sin_port);
+      rip_peer_bad_packet (from);
+      return;
+    }
+
+  /* The datagram's IPv4 source address should be checked to see
+     whether the datagram is from a valid neighbor; the source of the
+     datagram must be on a directly connected network  */
+  if (! if_valid_neighbor (from->sin_addr)) 
+    {
+      zlog_info ("This datagram doesn't came from a valid neighbor: %s",
+                inet_ntoa (from->sin_addr));
+      rip_peer_bad_packet (from);
+      return;
+    }
+
+  /* It is also worth checking to see whether the response is from one
+     of the router's own addresses. */
+
+  ; /* Alredy done in rip_read () */
+
+  /* Update RIP peer. */
+  rip_peer_update (from, packet->version);
+
+  /* Set RTE pointer. */
+  rte = packet->rte;
+
+  for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
+    {
+      /* RIPv2 authentication check. */
+      /* If the Address Family Identifier of the first (and only the
+        first) entry in the message is 0xFFFF, then the remainder of
+        the entry contains the authentication. */
+      /* If the packet gets here it means authentication enabled */
+      /* Check is done in rip_read(). So, just skipping it */
+      if (packet->version == RIPv2 &&
+         rte == packet->rte &&
+         rte->family == 0xffff)
+       continue;
+
+      if (ntohs (rte->family) != AF_INET)
+       {
+         /* Address family check.  RIP only supports AF_INET. */
+         zlog_info ("Unsupported family %d from %s.",
+                    ntohs (rte->family), inet_ntoa (from->sin_addr));
+         continue;
+       }
+
+      /* - is the destination address valid (e.g., unicast; not net 0
+         or 127) */
+      if (! rip_destination_check (rte->prefix))
+        {
+         zlog_info ("Network is net 0 or net 127 or it is not unicast network");
+         rip_peer_bad_route (from);
+         continue;
+       } 
+
+      /* Convert metric value to host byte order. */
+      rte->metric = ntohl (rte->metric);
+
+      /* - is the metric valid (i.e., between 1 and 16, inclusive) */
+      if (! (rte->metric >= 1 && rte->metric <= 16))
+       {
+         zlog_info ("Route's metric is not in the 1-16 range.");
+         rip_peer_bad_route (from);
+         continue;
+       }
+
+      /* RIPv1 does not have nexthop value. */
+      if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
+       {
+         zlog_info ("RIPv1 packet with nexthop value %s",
+                    inet_ntoa (rte->nexthop));
+         rip_peer_bad_route (from);
+         continue;
+       }
+
+      /* That is, if the provided information is ignored, a possibly
+        sub-optimal, but absolutely valid, route may be taken.  If
+        the received Next Hop is not directly reachable, it should be
+        treated as 0.0.0.0. */
+      if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
+       {
+         u_int32_t addrval;
+
+         /* Multicast address check. */
+         addrval = ntohl (rte->nexthop.s_addr);
+         if (IN_CLASSD (addrval))
+           {
+             zlog_info ("Nexthop %s is multicast address, skip this rte",
+                        inet_ntoa (rte->nexthop));
+             continue;
+           }
+
+         if (! if_lookup_address (rte->nexthop))
+           {
+             struct route_node *rn;
+             struct rip_info *rinfo;
+
+             rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
+
+             if (rn)
+               {
+                 rinfo = rn->info;
+
+                 if (rinfo->type == ZEBRA_ROUTE_RIP
+                     && rinfo->sub_type == RIP_ROUTE_RTE)
+                   {
+                     if (IS_RIP_DEBUG_EVENT)
+                       zlog_info ("Next hop %s is on RIP network.  Set nexthop to the packet's originator", inet_ntoa (rte->nexthop));
+                     rte->nexthop = rinfo->from;
+                   }
+                 else
+                   {
+                     if (IS_RIP_DEBUG_EVENT)
+                       zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
+                     rte->nexthop.s_addr = 0;
+                   }
+
+                 route_unlock_node (rn);
+               }
+             else
+               {
+                 if (IS_RIP_DEBUG_EVENT)
+                   zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
+                 rte->nexthop.s_addr = 0;
+               }
+
+           }
+       }
+
+     /* For RIPv1, there won't be a valid netmask.  
+
+       This is a best guess at the masks.  If everyone was using old
+       Ciscos before the 'ip subnet zero' option, it would be almost
+       right too :-)
+      
+       Cisco summarize ripv1 advertisments to the classful boundary
+       (/16 for class B's) except when the RIP packet does to inside
+       the classful network in question.  */
+
+      if ((packet->version == RIPv1 && rte->prefix.s_addr != 0) 
+         || (packet->version == RIPv2 
+             && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
+       {
+         u_int32_t destination;
+
+         destination = ntohl (rte->prefix.s_addr);
+
+         if (destination & 0xff) 
+           {
+             masklen2ip (32, &rte->mask);
+           }
+         else if ((destination & 0xff00) || IN_CLASSC (destination)) 
+           {
+             masklen2ip (24, &rte->mask);
+           }
+         else if ((destination & 0xff0000) || IN_CLASSB (destination)) 
+           {
+             masklen2ip (16, &rte->mask);
+           }
+         else 
+           {
+             masklen2ip (8, &rte->mask);
+           }
+       }
+
+      /* In case of RIPv2, if prefix in RTE is not netmask applied one
+         ignore the entry.  */
+      if ((packet->version == RIPv2) 
+         && (rte->mask.s_addr != 0) 
+         && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
+       {
+         zlog_warn ("RIPv2 address %s is not mask /%d applied one",
+                    inet_ntoa (rte->prefix), ip_masklen (rte->mask));
+         rip_peer_bad_route (from);
+         continue;
+       }
+
+      /* Default route's netmask is ignored. */
+      if (packet->version == RIPv2
+         && (rte->prefix.s_addr == 0)
+         && (rte->mask.s_addr != 0))
+       {
+         if (IS_RIP_DEBUG_EVENT)
+           zlog_info ("Default route with non-zero netmask.  Set zero to netmask");
+         rte->mask.s_addr = 0;
+       }
+         
+      /* Routing table updates. */
+      rip_rte_process (rte, from, ifp);
+    }
+}
+
+/* RIP packet send to destination address. */
+int
+rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to, 
+                struct interface *ifp)
+{
+  int ret;
+  struct sockaddr_in sin;
+  int sock;
+
+  /* Make destination address. */
+  memset (&sin, 0, sizeof (struct sockaddr_in));
+  sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+  /* When destination is specified, use it's port and address. */
+  if (to)
+    {
+      sock = rip->sock;
+
+      sin.sin_port = to->sin_port;
+      sin.sin_addr = to->sin_addr;
+    }
+  else
+    {
+      sock = socket (AF_INET, SOCK_DGRAM, 0);
+      
+      sockopt_broadcast (sock);
+      sockopt_reuseaddr (sock);
+      sockopt_reuseport (sock);
+
+      sin.sin_port = htons (RIP_PORT_DEFAULT);
+      sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
+
+      /* Set multicast interface. */
+      rip_interface_multicast_set (sock, ifp);
+    }
+
+  ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin,
+               sizeof (struct sockaddr_in));
+
+  if (IS_RIP_DEBUG_EVENT)
+      zlog_info ("SEND to socket %d port %d addr %s",
+                 sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr));
+
+  if (ret < 0)
+    zlog_warn ("can't send packet : %s", strerror (errno));
+
+  if (! to)
+    close (sock);
+
+  return ret;
+}
+
+/* Add redistributed route to RIP table. */
+void
+rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, 
+                     unsigned int ifindex, struct in_addr *nexthop)
+{
+  int ret;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  /* Redistribute route  */
+  ret = rip_destination_check (p->prefix);
+  if (! ret)
+    return;
+
+  rp = route_node_get (rip->table, (struct prefix *) p);
+
+  rinfo = rp->info;
+
+  if (rinfo)
+    {
+      if (rinfo->type == ZEBRA_ROUTE_CONNECT 
+         && rinfo->sub_type == RIP_ROUTE_INTERFACE
+         && rinfo->metric != RIP_METRIC_INFINITY)
+       {
+         route_unlock_node (rp);
+         return;
+       }
+
+      /* Manually configured RIP route check. */
+      if (rinfo->type == ZEBRA_ROUTE_RIP 
+         && rinfo->sub_type == RIP_ROUTE_STATIC)
+       {
+         if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC)
+           {
+             route_unlock_node (rp);
+             return;
+           }
+       }
+
+      RIP_TIMER_OFF (rinfo->t_timeout);
+      RIP_TIMER_OFF (rinfo->t_garbage_collect);
+
+      if (rip_route_rte (rinfo))
+       rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
+                              rinfo->metric);
+      rp->info = NULL;
+      rip_info_free (rinfo);
+      
+      route_unlock_node (rp);      
+    }
+
+  rinfo = rip_info_new ();
+    
+  rinfo->type = type;
+  rinfo->sub_type = sub_type;
+  rinfo->ifindex = ifindex;
+  rinfo->metric = 1;
+  rinfo->rp = rp;
+
+  if (nexthop)
+    rinfo->nexthop = *nexthop;
+
+  rinfo->flags |= RIP_RTF_FIB;
+  rp->info = rinfo;
+
+  rinfo->flags |= RIP_RTF_CHANGED;
+
+  rip_event (RIP_TRIGGERED_UPDATE, 0);
+}
+
+/* Delete redistributed route from RIP table. */
+void
+rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, 
+                          unsigned int ifindex)
+{
+  int ret;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  ret = rip_destination_check (p->prefix);
+  if (! ret)
+    return;
+
+  rp = route_node_lookup (rip->table, (struct prefix *) p);
+  if (rp)
+    {
+      rinfo = rp->info;
+
+      if (rinfo != NULL
+         && rinfo->type == type 
+         && rinfo->sub_type == sub_type 
+         && rinfo->ifindex == ifindex)
+       {
+         /* Perform poisoned reverse. */
+         rinfo->metric = RIP_METRIC_INFINITY;
+         RIP_TIMER_ON (rinfo->t_garbage_collect, 
+                       rip_garbage_collect, rip->garbage_time);
+         RIP_TIMER_OFF (rinfo->t_timeout);
+         rinfo->flags |= RIP_RTF_CHANGED;
+
+         rip_event (RIP_TRIGGERED_UPDATE, 0);
+       }
+    }
+}
+
+/* Response to request called from rip_read ().*/
+void
+rip_request_process (struct rip_packet *packet, int size, 
+                    struct sockaddr_in *from, struct interface *ifp)
+{
+  caddr_t lim;
+  struct rte *rte;
+  struct prefix_ipv4 p;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri;
+
+  ri = ifp->info;
+
+  /* When passive interface is specified, suppress responses */
+  if (ri->passive)
+    return;
+
+  /* RIP peer update. */
+  rip_peer_update (from, packet->version);
+
+  lim = ((caddr_t) packet) + size;
+  rte = packet->rte;
+
+  /* The Request is processed entry by entry.  If there are no
+     entries, no response is given. */
+  if (lim == (caddr_t) rte)
+    return;
+
+  /* There is one special case.  If there is exactly one entry in the
+     request, and it has an address family identifier of zero and a
+     metric of infinity (i.e., 16), then this is a request to send the
+     entire routing table. */
+  if (lim == ((caddr_t) (rte + 1)) &&
+      ntohs (rte->family) == 0 &&
+      ntohl (rte->metric) == RIP_METRIC_INFINITY)
+    {  
+      /* All route with split horizon */
+      rip_output_process (ifp, from, rip_all_route, packet->version);
+    }
+  else
+    {
+      /* Examine the list of RTEs in the Request one by one.  For each
+        entry, look up the destination in the router's routing
+        database and, if there is a route, put that route's metric in
+        the metric field of the RTE.  If there is no explicit route
+        to the specified destination, put infinity in the metric
+        field.  Once all the entries have been filled in, change the
+        command from Request to Response and send the datagram back
+        to the requestor. */
+      p.family = AF_INET;
+
+      for (; ((caddr_t) rte) < lim; rte++)
+       {
+         p.prefix = rte->prefix;
+         p.prefixlen = ip_masklen (rte->mask);
+         apply_mask_ipv4 (&p);
+         
+         rp = route_node_lookup (rip->table, (struct prefix *) &p);
+         if (rp)
+           {
+             rinfo = rp->info;
+             rte->metric = htonl (rinfo->metric);
+             route_unlock_node (rp);
+           }
+         else
+           rte->metric = htonl (RIP_METRIC_INFINITY);
+       }
+      packet->command = RIP_RESPONSE;
+
+      rip_send_packet ((caddr_t) packet, size, from, ifp);
+    }
+  rip_global_queries++;
+}
+
+#if RIP_RECVMSG
+/* Set IPv6 packet info to the socket. */
+static int
+setsockopt_pktinfo (int sock)
+{
+  int ret;
+  int val = 1;
+    
+  ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("Can't setsockopt IP_PKTINFO : %s", strerror (errno));
+  return ret;
+}
+
+/* Read RIP packet by recvmsg function. */
+int
+rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
+            int *ifindex)
+{
+  int ret;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr *ptr;
+  char adata[1024];
+
+  msg.msg_name = (void *) from;
+  msg.msg_namelen = sizeof (struct sockaddr_in);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = size;
+
+  ret = recvmsg (sock, &msg, 0);
+  if (ret < 0)
+    return ret;
+
+  for (ptr = CMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
+    if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) 
+      {
+       struct in_pktinfo *pktinfo;
+       int i;
+
+       pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
+       i = pktinfo->ipi_ifindex;
+      }
+  return ret;
+}
+
+/* RIP packet read function. */
+int
+rip_read_new (struct thread *t)
+{
+  int ret;
+  int sock;
+  char buf[RIP_PACKET_MAXSIZ];
+  struct sockaddr_in from;
+  unsigned int ifindex;
+  
+  /* Fetch socket then register myself. */
+  sock = THREAD_FD (t);
+  rip_event (RIP_READ, sock);
+
+  /* Read RIP packet. */
+  ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
+  if (ret < 0)
+    {
+      zlog_warn ("Can't read RIP packet: %s", strerror (errno));
+      return ret;
+    }
+
+  return ret;
+}
+#endif /* RIP_RECVMSG */
+
+/* First entry point of RIP packet. */
+int
+rip_read (struct thread *t)
+{
+  int sock;
+  int ret;
+  int rtenum;
+  union rip_buf rip_buf;
+  struct rip_packet *packet;
+  struct sockaddr_in from;
+  int fromlen, len;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  /* Fetch socket then register myself. */
+  sock = THREAD_FD (t);
+  rip->t_read = NULL;
+
+  /* Add myself to tne next event */
+  rip_event (RIP_READ, sock);
+
+  /* RIPd manages only IPv4. */
+  memset (&from, 0, sizeof (struct sockaddr_in));
+  fromlen = sizeof (struct sockaddr_in);
+
+  len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0, 
+                 (struct sockaddr *) &from, &fromlen);
+  if (len < 0) 
+    {
+      zlog_info ("recvfrom failed: %s", strerror (errno));
+      return len;
+    }
+
+  /* Check is this packet comming from myself? */
+  if (if_check_address (from.sin_addr)) 
+    {
+      if (IS_RIP_DEBUG_PACKET)
+       zlog_warn ("ignore packet comes from myself");
+      return -1;
+    }
+
+  /* Which interface is this packet comes from. */
+  ifp = if_lookup_address (from.sin_addr);
+
+  /* RIP packet received */
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("RECV packet from %s port %d on %s",
+              inet_ntoa (from.sin_addr), ntohs (from.sin_port),
+              ifp ? ifp->name : "unknown");
+
+  /* If this packet come from unknown interface, ignore it. */
+  if (ifp == NULL)
+    {
+      zlog_info ("packet comes from unknown interface");
+      return -1;
+    }
+
+  /* Packet length check. */
+  if (len < RIP_PACKET_MINSIZ)
+    {
+      zlog_warn ("packet size %d is smaller than minimum size %d",
+                len, RIP_PACKET_MINSIZ);
+      rip_peer_bad_packet (&from);
+      return len;
+    }
+  if (len > RIP_PACKET_MAXSIZ)
+    {
+      zlog_warn ("packet size %d is larger than max size %d",
+                len, RIP_PACKET_MAXSIZ);
+      rip_peer_bad_packet (&from);
+      return len;
+    }
+
+  /* Packet alignment check. */
+  if ((len - RIP_PACKET_MINSIZ) % 20)
+    {
+      zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
+      rip_peer_bad_packet (&from);
+      return len;
+    }
+
+  /* Set RTE number. */
+  rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
+
+  /* For easy to handle. */
+  packet = &rip_buf.rip_packet;
+
+  /* RIP version check. */
+  if (packet->version == 0)
+    {
+      zlog_info ("version 0 with command %d received.", packet->command);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+
+  /* Dump RIP packet. */
+  if (IS_RIP_DEBUG_RECV)
+    rip_packet_dump (packet, len, "RECV");
+
+  /* RIP version adjust.  This code should rethink now.  RFC1058 says
+     that "Version 1 implementations are to ignore this extra data and
+     process only the fields specified in this document.". So RIPv3
+     packet should be treated as RIPv1 ignoring must be zero field. */
+  if (packet->version > RIPv2)
+    packet->version = RIPv2;
+
+  /* Is RIP running or is this RIP neighbor ?*/
+  ri = ifp->info;
+  if (! ri->running && ! rip_neighbor_lookup (&from))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("RIP is not enabled on interface %s.", ifp->name);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+
+  /* RIP Version check. */
+  if (packet->command == RIP_RESPONSE)
+    {
+      if (ri->ri_receive == RI_RIP_UNSPEC)
+       {
+         if (packet->version != rip->version) 
+           {
+             if (IS_RIP_DEBUG_PACKET)
+               zlog_warn ("  packet's v%d doesn't fit to my version %d", 
+                          packet->version, rip->version);
+             rip_peer_bad_packet (&from);
+             return -1;
+           }
+       }
+      else
+       {
+         if (packet->version == RIPv1)
+           if (! (ri->ri_receive & RIPv1))
+             {
+               if (IS_RIP_DEBUG_PACKET)
+                 zlog_warn ("  packet's v%d doesn't fit to if version spec", 
+                            packet->version);
+               rip_peer_bad_packet (&from);
+               return -1;
+             }
+         if (packet->version == RIPv2)
+           if (! (ri->ri_receive & RIPv2))
+             {
+               if (IS_RIP_DEBUG_PACKET)
+                 zlog_warn ("  packet's v%d doesn't fit to if version spec", 
+                            packet->version);
+               rip_peer_bad_packet (&from);
+               return -1;
+             }
+       }
+    }
+
+  /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
+     messages, then RIP-1 and unauthenticated RIP-2 messages will be
+     accepted; authenticated RIP-2 messages shall be discarded.  */
+
+  if ((ri->auth_type == RIP_NO_AUTH) 
+      && rtenum 
+      && (packet->version == RIPv2) && (packet->rte->family == 0xffff))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_warn ("packet RIPv%d is dropped because authentication disabled", 
+                  packet->version);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+
+  /* If the router is configured to authenticate RIP-2 messages, then
+     RIP-1 messages and RIP-2 messages which pass authentication
+     testing shall be accepted; unauthenticated and failed
+     authentication RIP-2 messages shall be discarded.  For maximum
+     security, RIP-1 messages should be ignored when authentication is
+     in use (see section 4.1); otherwise, the routing information from
+     authenticated messages will be propagated by RIP-1 routers in an
+     unauthenticated manner. */
+
+  if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD 
+       || ri->auth_type == RIP_AUTH_MD5)
+      && rtenum)
+    {
+      /* We follow maximum security. */
+      if (packet->version == RIPv1 && packet->rte->family == 0xffff)
+       {
+         if (IS_RIP_DEBUG_PACKET)
+           zlog_warn ("packet RIPv%d is dropped because authentication enabled", packet->version);
+         rip_peer_bad_packet (&from);
+         return -1;
+       }
+
+      /* Check RIPv2 authentication. */
+      if (packet->version == RIPv2)
+       {
+         if (packet->rte->family == 0xffff)
+           {
+             if (ntohs (packet->rte->tag) == RIP_AUTH_SIMPLE_PASSWORD)
+                {
+                 ret = rip_auth_simple_password (packet->rte, &from, ifp);
+                 if (! ret)
+                   {
+                     if (IS_RIP_DEBUG_EVENT)
+                       zlog_warn ("RIPv2 simple password authentication failed");
+                     rip_peer_bad_packet (&from);
+                     return -1;
+                   }
+                 else
+                   {
+                     if (IS_RIP_DEBUG_EVENT)
+                       zlog_info ("RIPv2 simple password authentication success");
+                   }
+                }
+             else if (ntohs (packet->rte->tag) == RIP_AUTH_MD5)
+                {
+                 ret = rip_auth_md5 (packet, &from, ifp);
+                 if (! ret)
+                   {
+                     if (IS_RIP_DEBUG_EVENT)
+                       zlog_warn ("RIPv2 MD5 authentication failed");
+                     rip_peer_bad_packet (&from);
+                     return -1;
+                   }
+                 else
+                   {
+                     if (IS_RIP_DEBUG_EVENT)
+                       zlog_info ("RIPv2 MD5 authentication success");
+                   }
+                 /* Reset RIP packet length to trim MD5 data. */
+                 len = ret; 
+                }
+             else
+               {
+                 if (IS_RIP_DEBUG_EVENT)
+                   zlog_warn ("Unknown authentication type %d",
+                              ntohs (packet->rte->tag));
+                 rip_peer_bad_packet (&from);
+                 return -1;
+               }
+           }
+         else
+           {
+             /* There is no authentication in the packet. */
+             if (ri->auth_str || ri->key_chain)
+               {
+                 if (IS_RIP_DEBUG_EVENT)
+                   zlog_warn ("RIPv2 authentication failed: no authentication in packet");
+                 rip_peer_bad_packet (&from);
+                 return -1;
+               }
+           }
+       }
+    }
+  
+  /* Process each command. */
+  switch (packet->command)
+    {
+    case RIP_RESPONSE:
+      rip_response_process (packet, len, &from, ifp);
+      break;
+    case RIP_REQUEST:
+    case RIP_POLL:
+      rip_request_process (packet, len, &from, ifp);
+      break;
+    case RIP_TRACEON:
+    case RIP_TRACEOFF:
+      zlog_info ("Obsolete command %s received, please sent it to routed", 
+                lookup (rip_msg, packet->command));
+      rip_peer_bad_packet (&from);
+      break;
+    case RIP_POLL_ENTRY:
+      zlog_info ("Obsolete command %s received", 
+                lookup (rip_msg, packet->command));
+      rip_peer_bad_packet (&from);
+      break;
+    default:
+      zlog_info ("Unknown RIP command %d received", packet->command);
+      rip_peer_bad_packet (&from);
+      break;
+    }
+
+  return len;
+}
+
+/* Make socket for RIP protocol. */
+int 
+rip_create_socket ()
+{
+  int ret;
+  int sock;
+  struct sockaddr_in addr;
+  struct servent *sp;
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+
+  /* Set RIP port. */
+  sp = getservbyname ("router", "udp");
+  if (sp) 
+    addr.sin_port = sp->s_port;
+  else 
+    addr.sin_port = htons (RIP_PORT_DEFAULT);
+
+  /* Address shoud be any address. */
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  /* Make datagram socket. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) 
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  sockopt_broadcast (sock);
+  sockopt_reuseaddr (sock);
+  sockopt_reuseport (sock);
+#ifdef RIP_RECVMSG
+  setsockopt_pktinfo (sock);
+#endif /* RIP_RECVMSG */
+
+  ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr));
+  if (ret < 0)
+    {
+      perror ("bind");
+      return ret;
+    }
+  
+  return sock;
+}
+
+/* Write routing table entry to the stream and return next index of
+   the routing table entry in the stream. */
+int
+rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
+              u_char version, struct rip_info *rinfo, struct interface *ifp)
+{
+  struct in_addr mask;
+  struct rip_interface *ri;
+
+  /* RIP packet header. */
+  if (num == 0)
+    {
+      stream_putc (s, RIP_RESPONSE);
+      stream_putc (s, version);
+      stream_putw (s, 0);
+
+      /* In case of we need RIPv2 authentication. */
+      if (version == RIPv2 && ifp)
+       {
+         ri = ifp->info;
+             
+         if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+           {
+             if (ri->auth_str)
+               {
+                 stream_putw (s, 0xffff);
+                 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
+
+                 memset ((s->data + s->putp), 0, 16);
+                 strncpy ((s->data + s->putp), ri->auth_str, 16);
+                 stream_set_putp (s, s->putp + 16);
+
+                 num++;
+               }
+             if (ri->key_chain)
+               {
+                 struct keychain *keychain;
+                 struct key *key;
+
+                 keychain = keychain_lookup (ri->key_chain);
+
+                 if (keychain)
+                   {
+                     key = key_lookup_for_send (keychain);
+                     
+                     if (key)
+                       {
+                         stream_putw (s, 0xffff);
+                         stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
+
+                         memset ((s->data + s->putp), 0, 16);
+                         strncpy ((s->data + s->putp), key->string, 16);
+                         stream_set_putp (s, s->putp + 16);
+
+                         num++;
+                       }
+                   }
+               }
+           }
+       }
+    }
+
+  /* Write routing table entry. */
+  if (version == RIPv1)
+    {
+      stream_putw (s, AF_INET);
+      stream_putw (s, 0);
+      stream_put_ipv4 (s, p->prefix.s_addr);
+      stream_put_ipv4 (s, 0);
+      stream_put_ipv4 (s, 0);
+      stream_putl (s, rinfo->metric_out);
+    }
+  else
+    {
+      masklen2ip (p->prefixlen, &mask);
+
+      stream_putw (s, AF_INET);
+      stream_putw (s, rinfo->tag);
+      stream_put_ipv4 (s, p->prefix.s_addr);
+      stream_put_ipv4 (s, mask.s_addr);
+      stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
+      stream_putl (s, rinfo->metric_out);
+    }
+
+  return ++num;
+}
+
+/* Send update to the ifp or spcified neighbor. */
+void
+rip_output_process (struct interface *ifp, struct sockaddr_in *to,
+                   int route_type, u_char version)
+{
+  int ret;
+  struct stream *s;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri;
+  struct prefix_ipv4 *p;
+  struct prefix_ipv4 classfull;
+  int num;
+  int rtemax;
+
+  /* Logging output event. */
+  if (IS_RIP_DEBUG_EVENT)
+    {
+      if (to)
+       zlog_info ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
+      else
+       zlog_info ("update routes on interface %s ifindex %d",
+                  ifp->name, ifp->ifindex);
+    }
+
+  /* Set output stream. */
+  s = rip->obuf;
+
+  /* Reset stream and RTE counter. */
+  stream_reset (s);
+  num = 0;
+  rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
+
+  /* Get RIP interface. */
+  ri = ifp->info;
+    
+  /* If output interface is in simple password authentication mode, we
+     need space for authentication data.  */
+  if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+    rtemax -= 1;
+
+  /* If output interface is in MD5 authentication mode, we need space
+     for authentication header and data. */
+  if (ri->auth_type == RIP_AUTH_MD5)
+    rtemax -= 2;
+
+  /* If output interface is in simple password authentication mode
+     and string or keychain is specified we need space for auth. data */
+  if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+    {
+      if (ri->key_chain)
+       {
+         struct keychain *keychain;
+
+         keychain = keychain_lookup (ri->key_chain);
+         if (keychain)
+           if (key_lookup_for_send (keychain))
+             rtemax -=1;
+       }
+      else
+       if (ri->auth_str)
+         rtemax -=1;
+    }
+
+  for (rp = route_top (rip->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      {
+       /* Some inheritance stuff:                                          */
+       /* Before we process with ipv4 prefix we should mask it             */
+       /* with Classful mask if we send RIPv1 packet.That's because        */
+       /* user could set non-classful mask or we could get it by RIPv2     */
+       /* or other protocol. checked with Cisco's way of life :)           */
+       
+       if (version == RIPv1)
+         {
+           memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4));
+
+           if (IS_RIP_DEBUG_PACKET)
+             zlog_info("%s/%d before RIPv1 mask check ",
+                       inet_ntoa (classfull.prefix), classfull.prefixlen);
+
+           apply_classful_mask_ipv4 (&classfull);
+           p = &classfull;
+
+           if (IS_RIP_DEBUG_PACKET)
+             zlog_info("%s/%d after RIPv1 mask check",
+                       inet_ntoa (p->prefix), p->prefixlen);
+         }
+       else 
+         p = (struct prefix_ipv4 *) &rp->p;
+
+       /* Apply output filters. */
+       ret = rip_outgoing_filter (p, ri);
+       if (ret < 0)
+         continue;
+
+       /* Changed route only output. */
+       if (route_type == rip_changed_route &&
+           (! (rinfo->flags & RIP_RTF_CHANGED)))
+         continue;
+
+       /* Split horizon. */
+       /* if (split_horizon == rip_split_horizon) */
+       if (ri->split_horizon)
+         {
+           /* We perform split horizon for RIP and connected route. */
+           if ((rinfo->type == ZEBRA_ROUTE_RIP ||
+                rinfo->type == ZEBRA_ROUTE_CONNECT) &&
+               rinfo->ifindex == ifp->ifindex)
+             continue;
+         }
+
+       /* Preparation for route-map. */
+       rinfo->metric_set = 0;
+       rinfo->nexthop_out.s_addr = 0;
+       rinfo->metric_out = rinfo->metric;
+       rinfo->ifindex_out = ifp->ifindex;
+
+       /* In order to avoid some local loops, if the RIP route has a
+          nexthop via this interface, keep the nexthop, otherwise set
+          it to 0. The nexthop should not be propagated beyond the
+          local broadcast/multicast area in order to avoid an IGP
+          multi-level recursive look-up.  For RIP and connected
+          route, we don't set next hop value automatically.  For
+          settting next hop to those routes, please use
+          route-map.  */
+
+       if (rinfo->type != ZEBRA_ROUTE_RIP
+           && rinfo->type != ZEBRA_ROUTE_CONNECT
+           && rinfo->ifindex == ifp->ifindex)
+         rinfo->nexthop_out = rinfo->nexthop;
+           
+       /* Apply route map - continue, if deny */
+       if (rip->route_map[rinfo->type].name
+           && rinfo->sub_type != RIP_ROUTE_INTERFACE)
+         {
+           ret = route_map_apply (rip->route_map[rinfo->type].map,
+                                  (struct prefix *)p, RMAP_RIP, rinfo);
+
+           if (ret == RMAP_DENYMATCH) 
+             {
+               if (IS_RIP_DEBUG_PACKET)
+                 zlog_info ("%s/%d is filtered by route-map",
+                            inet_ntoa (p->prefix), p->prefixlen);
+               continue;
+             }
+         }
+
+       /* When route-map does not set metric. */
+       if (! rinfo->metric_set)
+         {
+           /* If redistribute metric is set. */
+           if (rip->route_map[rinfo->type].metric_config
+               && rinfo->metric != RIP_METRIC_INFINITY)
+             {
+               rinfo->metric_out = rip->route_map[rinfo->type].metric;
+             }
+           else
+             {
+               /* If the route is not connected or localy generated
+                  one, use default-metric value*/
+               if (rinfo->type != ZEBRA_ROUTE_RIP 
+                   && rinfo->type != ZEBRA_ROUTE_CONNECT
+                   && rinfo->metric != RIP_METRIC_INFINITY)
+                 rinfo->metric_out = rip->default_metric;
+             }
+         }
+
+       /* Apply offset-list */
+       if (rinfo->metric != RIP_METRIC_INFINITY)
+         rip_offset_list_apply_out (p, ifp, &rinfo->metric_out);
+
+       if (rinfo->metric_out > RIP_METRIC_INFINITY)
+         rinfo->metric_out = RIP_METRIC_INFINITY;
+         
+       /* Write RTE to the stream. */
+       num = rip_write_rte (num, s, p, version, rinfo, to ? NULL : ifp);
+       if (num == rtemax)
+         {
+           if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
+             rip_auth_md5_set (s, ifp);
+
+           ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
+                                  to, ifp);
+
+           if (ret >= 0 && IS_RIP_DEBUG_SEND)
+             rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
+                              stream_get_endp(s), "SEND");
+           num = 0;
+           stream_reset (s);
+         }
+      }
+
+  /* Flush unwritten RTE. */
+  if (num != 0)
+    {
+      if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
+       rip_auth_md5_set (s, ifp);
+
+      ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp);
+
+      if (ret >= 0 && IS_RIP_DEBUG_SEND)
+       rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
+                        stream_get_endp (s), "SEND");
+      num = 0;
+      stream_reset (s);
+    }
+
+  /* Statistics updates. */
+  ri->sent_updates++;
+}
+
+/* Send RIP packet to the interface. */
+void
+rip_update_interface (struct interface *ifp, u_char version, int route_type)
+{
+  struct prefix_ipv4 *p;
+  struct connected *connected;
+  listnode node;
+  struct sockaddr_in to;
+
+  /* When RIP version is 2 and multicast enable interface. */
+  if (version == RIPv2 && if_is_multicast (ifp)) 
+    {
+      if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("multicast announce on %s ", ifp->name);
+
+      rip_output_process (ifp, NULL, route_type, version);
+      return;
+    }
+
+  /* If we can't send multicast packet, send it with unicast. */
+  if (if_is_broadcast (ifp) || if_is_pointopoint (ifp))
+    {
+      for (node = listhead (ifp->connected); node; nextnode (node))
+       {           
+         connected = getdata (node);
+
+         /* Fetch broadcast address or poin-to-point destination
+             address . */
+         p = (struct prefix_ipv4 *) connected->destination;
+
+         if (p->family == AF_INET)
+           {
+             /* Destination address and port setting. */
+             memset (&to, 0, sizeof (struct sockaddr_in));
+             to.sin_addr = p->prefix;
+             to.sin_port = htons (RIP_PORT_DEFAULT);
+
+             if (IS_RIP_DEBUG_EVENT)
+               zlog_info ("%s announce to %s on %s",
+                          if_is_pointopoint (ifp) ? "unicast" : "broadcast",
+                          inet_ntoa (to.sin_addr), ifp->name);
+
+             rip_output_process (ifp, &to, route_type, version);
+           }
+       }
+    }
+}
+
+/* Update send to all interface and neighbor. */
+void
+rip_update_process (int route_type)
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+  struct route_node *rp;
+  struct sockaddr_in to;
+  struct prefix_ipv4 *p;
+
+  /* Send RIP update to each interface. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if (if_is_loopback (ifp))
+       continue;
+
+      if (! if_is_up (ifp))
+       continue;
+
+      /* Fetch RIP interface information. */
+      ri = ifp->info;
+
+      /* When passive interface is specified, suppress announce to the
+         interface. */
+      if (ri->passive)
+       continue;
+
+      if (ri->running)
+       {
+         if (IS_RIP_DEBUG_EVENT) 
+           {
+             if (ifp->name) 
+               zlog_info ("SEND UPDATE to %s ifindex %d",
+                          ifp->name, ifp->ifindex);
+             else
+               zlog_info ("SEND UPDATE to _unknown_ ifindex %d",
+                          ifp->ifindex);
+           }
+
+         /* If there is no version configuration in the interface,
+             use rip's version setting. */
+         if (ri->ri_send == RI_RIP_UNSPEC)
+           {
+             if (rip->version == RIPv1)
+               rip_update_interface (ifp, RIPv1, route_type);
+             else
+               rip_update_interface (ifp, RIPv2, route_type);
+           }
+         /* If interface has RIP version configuration use it. */
+         else
+           {
+             if (ri->ri_send & RIPv1)
+               rip_update_interface (ifp, RIPv1, route_type);
+             if (ri->ri_send & RIPv2)
+               rip_update_interface (ifp, RIPv2, route_type);
+           }
+       }
+    }
+
+  /* RIP send updates to each neighbor. */
+  for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
+    if (rp->info != NULL)
+      {
+       p = (struct prefix_ipv4 *) &rp->p;
+
+       ifp = if_lookup_address (p->prefix);
+       if (! ifp)
+         {
+           zlog_warn ("Neighbor %s doesn't exist direct connected network",
+                      inet_ntoa (p->prefix));
+           continue;
+         }
+
+       /* Set destination address and port */
+       memset (&to, 0, sizeof (struct sockaddr_in));
+       to.sin_addr = p->prefix;
+       to.sin_port = htons (RIP_PORT_DEFAULT);
+
+       /* RIP version is rip's configuration. */
+       rip_output_process (ifp, &to, route_type, rip->version);
+      }
+}
+
+/* RIP's periodical timer. */
+int
+rip_update (struct thread *t)
+{
+  /* Clear timer pointer. */
+  rip->t_update = NULL;
+
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("update timer fire!");
+
+  /* Process update output. */
+  rip_update_process (rip_all_route);
+
+  /* Triggered updates may be suppressed if a regular update is due by
+     the time the triggered update would be sent. */
+  if (rip->t_triggered_interval)
+    {
+      thread_cancel (rip->t_triggered_interval);
+      rip->t_triggered_interval = NULL;
+    }
+  rip->trigger = 0;
+
+  /* Register myself. */
+  rip_event (RIP_UPDATE_EVENT, 0);
+
+  return 0;
+}
+
+/* Walk down the RIP routing table then clear changed flag. */
+void
+rip_clear_changed_flag ()
+{
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  for (rp = route_top (rip->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      if (rinfo->flags & RIP_RTF_CHANGED)
+       rinfo->flags &= ~RIP_RTF_CHANGED;
+}
+
+/* Triggered update interval timer. */
+int
+rip_triggered_interval (struct thread *t)
+{
+  int rip_triggered_update (struct thread *);
+
+  rip->t_triggered_interval = NULL;
+
+  if (rip->trigger)
+    {
+      rip->trigger = 0;
+      rip_triggered_update (t);
+    }
+  return 0;
+}     
+
+/* Execute triggered update. */
+int
+rip_triggered_update (struct thread *t)
+{
+  int interval;
+
+  /* Clear thred pointer. */
+  rip->t_triggered_update = NULL;
+
+  /* Cancel interval timer. */
+  if (rip->t_triggered_interval)
+    {
+      thread_cancel (rip->t_triggered_interval);
+      rip->t_triggered_interval = NULL;
+    }
+  rip->trigger = 0;
+
+  /* Logging triggered update. */
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("triggered update!");
+
+  /* Split Horizon processing is done when generating triggered
+     updates as well as normal updates (see section 2.6). */
+  rip_update_process (rip_changed_route);
+
+  /* Once all of the triggered updates have been generated, the route
+     change flags should be cleared. */
+  rip_clear_changed_flag ();
+
+  /* After a triggered update is sent, a timer should be set for a
+   random interval between 1 and 5 seconds.  If other changes that
+   would trigger updates occur before the timer expires, a single
+   update is triggered when the timer expires. */
+  interval = (random () % 5) + 1;
+
+  rip->t_triggered_interval = 
+    thread_add_timer (master, rip_triggered_interval, NULL, interval);
+
+  return 0;
+}
+
+/* Withdraw redistributed route. */
+void
+rip_redistribute_withdraw (int type)
+{
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  if (!rip)
+    return;
+
+  for (rp = route_top (rip->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      {
+       if (rinfo->type == type
+           && rinfo->sub_type != RIP_ROUTE_INTERFACE)
+         {
+           /* Perform poisoned reverse. */
+           rinfo->metric = RIP_METRIC_INFINITY;
+           RIP_TIMER_ON (rinfo->t_garbage_collect, 
+                         rip_garbage_collect, rip->garbage_time);
+           RIP_TIMER_OFF (rinfo->t_timeout);
+           rinfo->flags |= RIP_RTF_CHANGED;
+
+           rip_event (RIP_TRIGGERED_UPDATE, 0);
+         }
+      }
+}
+
+/* Create new RIP instance and set it to global variable. */
+int
+rip_create ()
+{
+  rip = XMALLOC (MTYPE_RIP, sizeof (struct rip));
+  memset (rip, 0, sizeof (struct rip));
+
+  /* Set initial value. */
+  rip->version = RIPv2;
+  rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
+  rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
+  rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
+  rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
+
+  /* Initialize RIP routig table. */
+  rip->table = route_table_init ();
+  rip->route = route_table_init ();
+  rip->neighbor = route_table_init ();
+
+  /* Make output stream. */
+  rip->obuf = stream_new (1500);
+
+  /* Make socket. */
+  rip->sock = rip_create_socket ();
+  if (rip->sock < 0)
+    return rip->sock;
+
+  /* Create read and timer thread. */
+  rip_event (RIP_READ, rip->sock);
+  rip_event (RIP_UPDATE_EVENT, 1);
+
+  return 0;
+}
+
+/* Sned RIP request to the destination. */
+int
+rip_request_send (struct sockaddr_in *to, struct interface *ifp,
+                 u_char version)
+{
+  struct rte *rte;
+  struct rip_packet rip_packet;
+
+  memset (&rip_packet, 0, sizeof (rip_packet));
+
+  rip_packet.command = RIP_REQUEST;
+  rip_packet.version = version;
+  rte = rip_packet.rte;
+  rte->metric = htonl (RIP_METRIC_INFINITY);
+
+  return rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), to, ifp);
+}
+\f
+int
+rip_update_jitter (unsigned long time)
+{
+  return ((rand () % (time + 1)) - (time / 2));
+}
+
+void
+rip_event (enum rip_event event, int sock)
+{
+  int jitter = 0;
+
+  switch (event)
+    {
+    case RIP_READ:
+      rip->t_read = thread_add_read (master, rip_read, NULL, sock);
+      break;
+    case RIP_UPDATE_EVENT:
+      if (rip->t_update)
+       {
+         thread_cancel (rip->t_update);
+         rip->t_update = NULL;
+       }
+      jitter = rip_update_jitter (rip->update_time);
+      rip->t_update = 
+       thread_add_timer (master, rip_update, NULL, 
+                         sock ? 2 : rip->update_time + jitter);
+      break;
+    case RIP_TRIGGERED_UPDATE:
+      if (rip->t_triggered_interval)
+       rip->trigger = 1;
+      else if (! rip->t_triggered_update)
+       rip->t_triggered_update = 
+         thread_add_event (master, rip_triggered_update, NULL, 0);
+      break;
+    default:
+      break;
+    }
+}
+\f
+DEFUN (router_rip,
+       router_rip_cmd,
+       "router rip",
+       "Enable a routing process\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  int ret;
+
+  /* If rip is not enabled before. */
+  if (! rip)
+    {
+      ret = rip_create ();
+      if (ret < 0)
+       {
+         zlog_info ("Can't create RIP");
+         return CMD_WARNING;
+       }
+    }
+  vty->node = RIP_NODE;
+  vty->index = rip;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_rip,
+       no_router_rip_cmd,
+       "no router rip",
+       NO_STR
+       "Enable a routing process\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  if (rip)
+    rip_clean ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_version,
+       rip_version_cmd,
+       "version <1-2>",
+       "Set routing protocol version\n"
+       "version\n")
+{
+  int version;
+
+  version = atoi (argv[0]);
+  if (version != RIPv1 && version != RIPv2)
+    {
+      vty_out (vty, "invalid rip version %d%s", version,
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  rip->version = version;
+
+  return CMD_SUCCESS;
+} 
+
+DEFUN (no_rip_version,
+       no_rip_version_cmd,
+       "no version",
+       NO_STR
+       "Set routing protocol version\n")
+{
+  /* Set RIP version to the default. */
+  rip->version = RIPv2;
+
+  return CMD_SUCCESS;
+} 
+
+ALIAS (no_rip_version,
+       no_rip_version_val_cmd,
+       "no version <1-2>",
+       NO_STR
+       "Set routing protocol version\n"
+       "version\n")
+
+DEFUN (rip_route,
+       rip_route_cmd,
+       "route A.B.C.D/M",
+       "RIP static route configuration\n"
+       "IP prefix <network>/<length>\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_node *node;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret < 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask_ipv4 (&p);
+
+  /* For router rip configuration. */
+  node = route_node_get (rip->route, (struct prefix *) &p);
+
+  if (node->info)
+    {
+      vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
+      route_unlock_node (node);
+      return CMD_WARNING;
+    }
+
+  node->info = "static";
+
+  rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_route,
+       no_rip_route_cmd,
+       "no route A.B.C.D/M",
+       NO_STR
+       "RIP static route configuration\n"
+       "IP prefix <network>/<length>\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_node *node;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret < 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask_ipv4 (&p);
+
+  /* For router rip configuration. */
+  node = route_node_lookup (rip->route, (struct prefix *) &p);
+  if (! node)
+    {
+      vty_out (vty, "Can't find route %s.%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+  route_unlock_node (node);
+
+  node->info = NULL;
+  route_unlock_node (node);
+
+  return CMD_SUCCESS;
+}
+
+void
+rip_update_default_metric ()
+{
+  struct route_node *np;
+  struct rip_info *rinfo;
+
+  for (np = route_top (rip->table); np; np = route_next (np))
+    if ((rinfo = np->info) != NULL)
+      if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
+        rinfo->metric = rip->default_metric;
+}
+
+DEFUN (rip_default_metric,
+       rip_default_metric_cmd,
+       "default-metric <1-16>",
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+{
+  if (rip)
+    {
+      rip->default_metric = atoi (argv[0]);
+      /* rip_update_default_metric (); */
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_default_metric,
+       no_rip_default_metric_cmd,
+       "no default-metric",
+       NO_STR
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+{
+  if (rip)
+    {
+      rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
+      /* rip_update_default_metric (); */
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_rip_default_metric,
+       no_rip_default_metric_val_cmd,
+       "no default-metric <1-16>",
+       NO_STR
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFUN (rip_timers,
+       rip_timers_cmd,
+       "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n"
+       "Routing table update timer value in second. Default is 30.\n"
+       "Routing information timeout timer. Default is 180.\n"
+       "Garbage collection timer. Default is 120.\n")
+{
+  unsigned long update;
+  unsigned long timeout;
+  unsigned long garbage;
+  char *endptr = NULL;
+  unsigned long RIP_TIMER_MAX = 2147483647;
+  unsigned long RIP_TIMER_MIN = 5;
+
+  update = strtoul (argv[0], &endptr, 10);
+  if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')  
+    {
+      vty_out (vty, "update timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  timeout = strtoul (argv[1], &endptr, 10);
+  if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0') 
+    {
+      vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  garbage = strtoul (argv[2], &endptr, 10);
+  if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0') 
+    {
+      vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Set each timer value. */
+  rip->update_time = update;
+  rip->timeout_time = timeout;
+  rip->garbage_time = garbage;
+
+  /* Reset update timer thread. */
+  rip_event (RIP_UPDATE_EVENT, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_timers,
+       no_rip_timers_cmd,
+       "no timers basic",
+       NO_STR
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n")
+{
+  /* Set each timer value to the default. */
+  rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
+  rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
+  rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
+
+  /* Reset update timer thread. */
+  rip_event (RIP_UPDATE_EVENT, 0);
+
+  return CMD_SUCCESS;
+}
+\f
+struct route_table *rip_distance_table;
+
+struct rip_distance
+{
+  /* Distance value for the IP source prefix. */
+  u_char distance;
+
+  /* Name of the access-list to be matched. */
+  char *access_list;
+};
+
+struct rip_distance *
+rip_distance_new ()
+{
+  struct rip_distance *new;
+  new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
+  memset (new, 0, sizeof (struct rip_distance));
+  return new;
+}
+
+void
+rip_distance_free (struct rip_distance *rdistance)
+{
+  XFREE (MTYPE_RIP_DISTANCE, rdistance);
+}
+
+int
+rip_distance_set (struct vty *vty, char *distance_str, char *ip_str,
+                 char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  /* Get RIP distance node. */
+  rn = route_node_get (rip_distance_table, (struct prefix *) &p);
+  if (rn->info)
+    {
+      rdistance = rn->info;
+      route_unlock_node (rn);
+    }
+  else
+    {
+      rdistance = rip_distance_new ();
+      rn->info = rdistance;
+    }
+
+  /* Set distance value. */
+  rdistance->distance = distance;
+
+  /* Reset access-list configuration. */
+  if (rdistance->access_list)
+    {
+      free (rdistance->access_list);
+      rdistance->access_list = NULL;
+    }
+  if (access_list_str)
+    rdistance->access_list = strdup (access_list_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_distance_unset (struct vty *vty, char *distance_str, char *ip_str,
+                   char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
+  if (! rn)
+    {
+      vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rdistance = rn->info;
+
+  if (rdistance->access_list)
+    free (rdistance->access_list);
+  rip_distance_free (rdistance);
+
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+rip_distance_reset ()
+{
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
+    if ((rdistance = rn->info) != NULL)
+      {
+       if (rdistance->access_list)
+         free (rdistance->access_list);
+       rip_distance_free (rdistance);
+       rn->info = NULL;
+       route_unlock_node (rn);
+      }
+}
+
+/* Apply RIP information to distance method. */
+u_char
+rip_distance_apply (struct rip_info *rinfo)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  struct rip_distance *rdistance;
+  struct access_list *alist;
+
+  if (! rip)
+    return 0;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = rinfo->from;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  /* Check source address. */
+  rn = route_node_match (rip_distance_table, (struct prefix *) &p);
+  if (rn)
+    {
+      rdistance = rn->info;
+      route_unlock_node (rn);
+
+      if (rdistance->access_list)
+       {
+         alist = access_list_lookup (AFI_IP, rdistance->access_list);
+         if (alist == NULL)
+           return 0;
+         if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
+           return 0;
+
+         return rdistance->distance;
+       }
+      else
+       return rdistance->distance;
+    }
+
+  if (rip->distance)
+    return rip->distance;
+
+  return 0;
+}
+
+void
+rip_distance_show (struct vty *vty)
+{
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+  int header = 1;
+  char buf[BUFSIZ];
+  
+  vty_out (vty, "  Distance: (default is %d)%s",
+          rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
+          VTY_NEWLINE);
+
+  for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
+    if ((rdistance = rn->info) != NULL)
+      {
+       if (header)
+         {
+           vty_out (vty, "    Address           Distance  List%s",
+                    VTY_NEWLINE);
+           header = 0;
+         }
+       sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+       vty_out (vty, "    %-20s  %4d  %s%s",
+                buf, rdistance->distance,
+                rdistance->access_list ? rdistance->access_list : "",
+                VTY_NEWLINE);
+      }
+}
+
+DEFUN (rip_distance,
+       rip_distance_cmd,
+       "distance <1-255>",
+       "Administrative distance\n"
+       "Distance value\n")
+{
+  rip->distance = atoi (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_distance,
+       no_rip_distance_cmd,
+       "no distance <1-255>",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n")
+{
+  rip->distance = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_distance_source,
+       rip_distance_source_cmd,
+       "distance <1-255> A.B.C.D/M",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  rip_distance_set (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_distance_source,
+       no_rip_distance_source_cmd,
+       "no distance <1-255> A.B.C.D/M",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  rip_distance_unset (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_distance_source_access_list,
+       rip_distance_source_access_list_cmd,
+       "distance <1-255> A.B.C.D/M WORD",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  rip_distance_set (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_distance_source_access_list,
+       no_rip_distance_source_access_list_cmd,
+       "no distance <1-255> A.B.C.D/M WORD",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  rip_distance_unset (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+\f
+/* Print out routes update time. */
+void
+rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
+{
+  struct timeval timer_now;
+  time_t clock;
+  struct tm *tm;
+#define TIME_BUF 25
+  char timebuf [TIME_BUF];
+  struct thread *thread;
+
+  gettimeofday (&timer_now, NULL);
+
+  if ((thread = rinfo->t_timeout) != NULL)
+    {
+      clock = thread->u.sands.tv_sec - timer_now.tv_sec;
+      tm = gmtime (&clock);
+      strftime (timebuf, TIME_BUF, "%M:%S", tm);
+      vty_out (vty, "%5s", timebuf);
+    }
+  else if ((thread = rinfo->t_garbage_collect) != NULL)
+    {
+      clock = thread->u.sands.tv_sec - timer_now.tv_sec;
+      tm = gmtime (&clock);
+      strftime (timebuf, TIME_BUF, "%M:%S", tm);
+      vty_out (vty, "%5s", timebuf);
+    }
+}
+
+char *
+rip_route_type_print (int sub_type)
+{
+  switch (sub_type)
+    {
+      case RIP_ROUTE_RTE:
+       return "n";
+      case RIP_ROUTE_STATIC:
+       return "s";
+      case RIP_ROUTE_DEFAULT:
+       return "d";
+      case RIP_ROUTE_REDISTRIBUTE:
+       return "r";
+      case RIP_ROUTE_INTERFACE:
+       return "i";
+      default:
+       return "?";
+    }
+}
+
+DEFUN (show_ip_rip,
+       show_ip_rip_cmd,
+       "show ip rip",
+       SHOW_STR
+       IP_STR
+       "Show RIP routes\n")
+{
+  struct route_node *np;
+  struct rip_info *rinfo;
+
+  if (! rip)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s"
+          "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
+          "      (i) - interface%s%s"
+          "     Network            Next Hop         Metric From            Time%s",
+          VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+  
+  for (np = route_top (rip->table); np; np = route_next (np))
+    if ((rinfo = np->info) != NULL)
+      {
+       int len;
+
+       len = vty_out (vty, "%s(%s) %s/%d",
+                      /* np->lock, For debugging. */
+                      route_info[rinfo->type].str,
+                      rip_route_type_print (rinfo->sub_type),
+                      inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
+       
+       len = 24 - len;
+
+       if (len > 0)
+         vty_out (vty, "%*s", len, " ");
+
+        if (rinfo->nexthop.s_addr) 
+         vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
+                  rinfo->metric);
+        else
+         vty_out (vty, "0.0.0.0              %2d ", rinfo->metric);
+
+       /* Route which exist in kernel routing table. */
+       if ((rinfo->type == ZEBRA_ROUTE_RIP) && 
+           (rinfo->sub_type == RIP_ROUTE_RTE))
+         {
+           vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
+           rip_vty_out_uptime (vty, rinfo);
+         }
+       else if (rinfo->metric == RIP_METRIC_INFINITY)
+         {
+           vty_out (vty, "self            ");
+           rip_vty_out_uptime (vty, rinfo);
+         }
+       else
+         vty_out (vty, "self");
+
+       vty_out (vty, "%s", VTY_NEWLINE);
+      }
+  return CMD_SUCCESS;
+}
+
+/* Return next event time. */
+int
+rip_next_thread_timer (struct thread *thread)
+{
+  struct timeval timer_now;
+
+  gettimeofday (&timer_now, NULL);
+
+  return thread->u.sands.tv_sec - timer_now.tv_sec;
+}
+
+DEFUN (show_ip_protocols_rip,
+       show_ip_protocols_rip_cmd,
+       "show ip protocols",
+       SHOW_STR
+       IP_STR
+       "IP routing protocol process parameters and statistics\n")
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+  extern struct message ri_version_msg[];
+  char *send_version;
+  char *receive_version;
+
+  if (! rip)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
+  vty_out (vty, "  Sending updates every %ld seconds with +/-50%%,",
+          rip->update_time);
+  vty_out (vty, " next due in %d seconds%s", 
+          rip_next_thread_timer (rip->t_update),
+          VTY_NEWLINE);
+  vty_out (vty, "  Timeout after %ld seconds,", rip->timeout_time);
+  vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
+          VTY_NEWLINE);
+
+  /* Filtering status show. */
+  config_show_distribute (vty);
+                
+  /* Default metric information. */
+  vty_out (vty, "  Default redistribution metric is %d%s",
+          rip->default_metric, VTY_NEWLINE);
+
+  /* Redistribute information. */
+  vty_out (vty, "  Redistributing:");
+  config_write_rip_redistribute (vty, 0);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "  Default version control: send version %d,", rip->version);
+  vty_out (vty, " receive version %d %s", rip->version,
+          VTY_NEWLINE);
+
+  vty_out (vty, "    Interface        Send  Recv   Key-chain%s", VTY_NEWLINE);
+
+  for (node = listhead (iflist); node; node = nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      if (ri->enable_network || ri->enable_interface)
+       {
+         if (ri->ri_send == RI_RIP_UNSPEC)
+           send_version = lookup (ri_version_msg, rip->version);
+         else
+           send_version = lookup (ri_version_msg, ri->ri_send);
+
+         if (ri->ri_receive == RI_RIP_UNSPEC)
+           receive_version = lookup (ri_version_msg, rip->version);
+         else
+           receive_version = lookup (ri_version_msg, ri->ri_receive);
+       
+         vty_out (vty, "    %-17s%-3s   %-3s    %s%s", ifp->name,
+                  send_version,
+                  receive_version,
+                  ri->key_chain ? ri->key_chain : "",
+                  VTY_NEWLINE);
+       }
+    }
+
+  vty_out (vty, "  Routing for Networks:%s", VTY_NEWLINE);
+  config_write_rip_network (vty, 0);  
+
+  vty_out (vty, "  Routing Information Sources:%s", VTY_NEWLINE);
+  vty_out (vty, "    Gateway          BadPackets BadRoutes  Distance Last Update%s", VTY_NEWLINE);
+  rip_peer_display (vty);
+
+  rip_distance_show (vty);
+
+  return CMD_SUCCESS;
+}
+
+/* RIP configuration write function. */
+int
+config_write_rip (struct vty *vty)
+{
+  int write = 0;
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  if (rip)
+    {
+      /* Router RIP statement. */
+      vty_out (vty, "router rip%s", VTY_NEWLINE);
+      write++;
+  
+      /* RIP version statement.  Default is RIP version 2. */
+      if (rip->version != RIPv2)
+       vty_out (vty, " version %d%s", rip->version,
+                VTY_NEWLINE);
+      /* RIP timer configuration. */
+      if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT 
+         || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT 
+         || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
+       vty_out (vty, " timers basic %lu %lu %lu%s",
+                rip->update_time,
+                rip->timeout_time,
+                rip->garbage_time,
+                VTY_NEWLINE);
+
+      /* Default information configuration. */
+      if (rip->default_information)
+       {
+         if (rip->default_information_route_map)
+           vty_out (vty, " default-information originate route-map %s%s",
+                    rip->default_information_route_map, VTY_NEWLINE);
+         else
+           vty_out (vty, " default-information originate%s",
+                    VTY_NEWLINE);
+       }
+
+      /* Redistribute configuration. */
+      config_write_rip_redistribute (vty, 1);
+
+      /* RIP offset-list configuration. */
+      config_write_rip_offset_list (vty);
+
+      /* RIP enabled network and interface configuration. */
+      config_write_rip_network (vty, 1);
+                       
+      /* RIP default metric configuration */
+      if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
+        vty_out (vty, " default-metric %d%s",
+                rip->default_metric, VTY_NEWLINE);
+
+      /* Distribute configuration. */
+      write += config_write_distribute (vty);
+
+      /* Distance configuration. */
+      if (rip->distance)
+       vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
+
+      /* RIP source IP prefix distance configuration. */
+      for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
+       if ((rdistance = rn->info) != NULL)
+         vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
+                  inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+                  rdistance->access_list ? rdistance->access_list : "",
+                  VTY_NEWLINE);
+
+      /* RIP static route configuration. */
+      for (rn = route_top (rip->route); rn; rn = route_next (rn))
+       if (rn->info)
+         vty_out (vty, " route %s/%d%s", 
+                  inet_ntoa (rn->p.u.prefix4),
+                  rn->p.prefixlen,
+                  VTY_NEWLINE);
+
+    }
+  return write;
+}
+
+/* RIP node structure. */
+struct cmd_node rip_node =
+{
+  RIP_NODE,
+  "%s(config-router)# ",
+  1
+};
+\f
+/* Distribute-list update functions. */
+void
+rip_distribute_update (struct distribute *dist)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  if (! dist->ifname)
+    return;
+
+  ifp = if_lookup_by_name (dist->ifname);
+  if (ifp == NULL)
+    return;
+
+  ri = ifp->info;
+
+  if (dist->list[DISTRIBUTE_IN])
+    {
+      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
+      if (alist)
+       ri->list[RIP_FILTER_IN] = alist;
+      else
+       ri->list[RIP_FILTER_IN] = NULL;
+    }
+  else
+    ri->list[RIP_FILTER_IN] = NULL;
+
+  if (dist->list[DISTRIBUTE_OUT])
+    {
+      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
+      if (alist)
+       ri->list[RIP_FILTER_OUT] = alist;
+      else
+       ri->list[RIP_FILTER_OUT] = NULL;
+    }
+  else
+    ri->list[RIP_FILTER_OUT] = NULL;
+
+  if (dist->prefix[DISTRIBUTE_IN])
+    {
+      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
+      if (plist)
+       ri->prefix[RIP_FILTER_IN] = plist;
+      else
+       ri->prefix[RIP_FILTER_IN] = NULL;
+    }
+  else
+    ri->prefix[RIP_FILTER_IN] = NULL;
+
+  if (dist->prefix[DISTRIBUTE_OUT])
+    {
+      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
+      if (plist)
+       ri->prefix[RIP_FILTER_OUT] = plist;
+      else
+       ri->prefix[RIP_FILTER_OUT] = NULL;
+    }
+  else
+    ri->prefix[RIP_FILTER_OUT] = NULL;
+}
+
+void
+rip_distribute_update_interface (struct interface *ifp)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifp->name);
+  if (dist)
+    rip_distribute_update (dist);
+}
+
+/* Update all interface's distribute list. */
+void
+rip_distribute_update_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_distribute_update_interface (ifp);
+    }
+}
+\f
+/* Delete all added rip route. */
+void
+rip_clean ()
+{
+  int i;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  if (rip)
+    {
+      /* Clear RIP routes */
+      for (rp = route_top (rip->table); rp; rp = route_next (rp))
+       if ((rinfo = rp->info) != NULL)
+         {
+           if (rinfo->type == ZEBRA_ROUTE_RIP &&
+               rinfo->sub_type == RIP_ROUTE_RTE)
+             rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
+                                    &rinfo->nexthop, rinfo->metric);
+       
+           RIP_TIMER_OFF (rinfo->t_timeout);
+           RIP_TIMER_OFF (rinfo->t_garbage_collect);
+
+           rp->info = NULL;
+           route_unlock_node (rp);
+
+           rip_info_free (rinfo);
+         }
+
+      /* Cancel RIP related timers. */
+      RIP_TIMER_OFF (rip->t_update);
+      RIP_TIMER_OFF (rip->t_triggered_update);
+      RIP_TIMER_OFF (rip->t_triggered_interval);
+
+      /* Cancel read thread. */
+      if (rip->t_read)
+       {
+         thread_cancel (rip->t_read);
+         rip->t_read = NULL;
+       }
+
+      /* Close RIP socket. */
+      if (rip->sock >= 0)
+       {
+         close (rip->sock);
+         rip->sock = -1;
+       }
+
+      /* Static RIP route configuration. */
+      for (rp = route_top (rip->route); rp; rp = route_next (rp))
+       if (rp->info)
+         {
+           rp->info = NULL;
+           route_unlock_node (rp);
+         }
+
+      /* RIP neighbor configuration. */
+      for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
+       if (rp->info)
+         {
+           rp->info = NULL;
+           route_unlock_node (rp);
+         }
+
+      /* Redistribute related clear. */
+      if (rip->default_information_route_map)
+       free (rip->default_information_route_map);
+
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+       if (rip->route_map[i].name)
+         free (rip->route_map[i].name);
+
+      XFREE (MTYPE_ROUTE_TABLE, rip->table);
+      XFREE (MTYPE_ROUTE_TABLE, rip->route);
+      XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
+      
+      XFREE (MTYPE_RIP, rip);
+      rip = NULL;
+    }
+
+  rip_clean_network ();
+  rip_passive_interface_clean ();
+  rip_offset_clean ();
+  rip_interface_clean ();
+  rip_distance_reset ();
+  rip_redistribute_clean ();
+}
+
+/* Reset all values to the default settings. */
+void
+rip_reset ()
+{
+  /* Reset global counters. */
+  rip_global_route_changes = 0;
+  rip_global_queries = 0;
+
+  /* Call ripd related reset functions. */
+  rip_debug_reset ();
+  rip_route_map_reset ();
+
+  /* Call library reset functions. */
+  vty_reset ();
+  access_list_reset ();
+  prefix_list_reset ();
+
+  distribute_list_reset ();
+
+  rip_interface_reset ();
+  rip_distance_reset ();
+
+  rip_zclient_reset ();
+}
+
+/* Allocate new rip structure and set default value. */
+void
+rip_init ()
+{
+  /* Randomize for triggered update random(). */
+  srand (time (NULL));
+
+  /* Install top nodes. */
+  install_node (&rip_node, config_write_rip);
+
+  /* Install rip commands. */
+  install_element (VIEW_NODE, &show_ip_rip_cmd);
+  install_element (VIEW_NODE, &show_ip_protocols_rip_cmd);
+  install_element (ENABLE_NODE, &show_ip_rip_cmd);
+  install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd);
+  install_element (CONFIG_NODE, &router_rip_cmd);
+  install_element (CONFIG_NODE, &no_router_rip_cmd);
+
+  install_default (RIP_NODE);
+  install_element (RIP_NODE, &rip_version_cmd);
+  install_element (RIP_NODE, &no_rip_version_cmd);
+  install_element (RIP_NODE, &no_rip_version_val_cmd);
+  install_element (RIP_NODE, &rip_default_metric_cmd);
+  install_element (RIP_NODE, &no_rip_default_metric_cmd);
+  install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
+  install_element (RIP_NODE, &rip_timers_cmd);
+  install_element (RIP_NODE, &no_rip_timers_cmd);
+  install_element (RIP_NODE, &rip_route_cmd);
+  install_element (RIP_NODE, &no_rip_route_cmd);
+  install_element (RIP_NODE, &rip_distance_cmd);
+  install_element (RIP_NODE, &no_rip_distance_cmd);
+  install_element (RIP_NODE, &rip_distance_source_cmd);
+  install_element (RIP_NODE, &no_rip_distance_source_cmd);
+  install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
+  install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
+
+  /* Debug related init. */
+  rip_debug_init ();
+
+  /* Filter related init. */
+  rip_route_map_init ();
+  rip_offset_init ();
+
+  /* SNMP init. */
+#ifdef HAVE_SNMP
+  rip_snmp_init ();
+#endif /* HAVE_SNMP */
+
+  /* Access list install. */
+  access_list_init ();
+  access_list_add_hook (rip_distribute_update_all);
+  access_list_delete_hook (rip_distribute_update_all);
+
+  /* Prefix list initialize.*/
+  prefix_list_init ();
+  prefix_list_add_hook (rip_distribute_update_all);
+  prefix_list_delete_hook (rip_distribute_update_all);
+
+  /* Distribute list install. */
+  distribute_list_init (RIP_NODE);
+  distribute_list_add_hook (rip_distribute_update);
+  distribute_list_delete_hook (rip_distribute_update);
+
+  /* Distance control. */
+  rip_distance_table = route_table_init ();
+}
diff --git a/ripd/ripd.conf.sample b/ripd/ripd.conf.sample
new file mode 100644 (file)
index 0000000..2902ff9
--- /dev/null
@@ -0,0 +1,24 @@
+! -*- rip -*-
+!
+! RIPd sample configuration file
+!
+! $Id: ripd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
+!
+hostname ripd
+password zebra
+!
+! debug rip events
+! debug rip packet
+!
+router rip
+! network 11.0.0.0/8
+! network eth0
+! route 10.0.0.0/8
+! distribute-list private-only in eth0
+!
+!access-list private-only permit 10.0.0.0/8
+!access-list private-only deny any
+! 
+!log file ripd.log
+!
+log stdout
diff --git a/ripd/ripd.h b/ripd/ripd.h
new file mode 100644 (file)
index 0000000..2545db0
--- /dev/null
@@ -0,0 +1,408 @@
+/* RIP related values and structures.
+ * Copyright (C) 1997, 1998, 1999 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.  
+ */
+
+#ifndef _ZEBRA_RIP_H
+#define _ZEBRA_RIP_H
+
+/* RIP version number. */
+#define RIPv1                            1
+#define RIPv2                            2
+
+/* RIP command list. */
+#define RIP_REQUEST                      1
+#define RIP_RESPONSE                     2
+#define RIP_TRACEON                      3     /* Obsolete */
+#define RIP_TRACEOFF                     4     /* Obsolete */
+#define RIP_POLL                         5
+#define RIP_POLL_ENTRY                   6
+#define RIP_COMMAND_MAX                  7
+
+/* RIP metric infinity value.*/
+#define RIP_METRIC_INFINITY             16
+
+/* Normal RIP packet min and max size. */
+#define RIP_PACKET_MINSIZ                4
+#define RIP_PACKET_MAXSIZ              512
+
+#define RIP_HEADER_SIZE                  4
+#define RIP_RTE_SIZE                    20
+
+/* Max count of routing table entry in one rip packet. */
+#define RIP_MAX_RTE                     25
+
+/* RIP version 2 multicast address. */
+#ifndef INADDR_RIP_GROUP
+#define INADDR_RIP_GROUP        0xe0000009    /* 224.0.0.9 */
+#endif
+
+/* RIP timers */
+#define RIP_UPDATE_TIMER_DEFAULT        30
+#define RIP_TIMEOUT_TIMER_DEFAULT      180
+#define RIP_GARBAGE_TIMER_DEFAULT      120
+
+/* RIP peer timeout value. */
+#define RIP_PEER_TIMER_DEFAULT         180
+
+/* RIP port number. */
+#define RIP_PORT_DEFAULT               520
+#define RIP_VTY_PORT                  2602
+#define RIP_VTYSH_PATH        "/tmp/.ripd"
+
+/* Default configuration file name. */
+#define RIPD_DEFAULT_CONFIG    "ripd.conf"
+
+/* RIP route types. */
+#define RIP_ROUTE_RTE                    0
+#define RIP_ROUTE_STATIC                 1
+#define RIP_ROUTE_DEFAULT                2
+#define RIP_ROUTE_REDISTRIBUTE           3
+#define RIP_ROUTE_INTERFACE              4
+
+/* RIP MD5 authentication. */
+#define RIP_AUTH_MD5_SIZE               16
+
+/* RIP structure. */
+struct rip 
+{
+  /* RIP socket. */
+  int sock;
+
+  /* Default version of rip instance. */
+  u_char version;
+
+  /* Output buffer of RIP. */
+  struct stream *obuf;
+
+  /* RIP routing information base. */
+  struct route_table *table;
+
+  /* RIP only static routing information. */
+  struct route_table *route;
+  
+  /* RIP neighbor. */
+  struct route_table *neighbor;
+  
+  /* RIP threads. */
+  struct thread *t_read;
+
+  /* Update and garbage timer. */
+  struct thread *t_update;
+
+  /* Triggered update hack. */
+  int trigger;
+  struct thread *t_triggered_update;
+  struct thread *t_triggered_interval;
+
+  /* RIP timer values. */
+  unsigned long update_time;
+  unsigned long timeout_time;
+  unsigned long garbage_time;
+
+  /* RIP default metric. */
+  int default_metric;
+
+  /* RIP default-information originate. */
+  u_char default_information;
+  char *default_information_route_map;
+
+  /* RIP default distance. */
+  u_char distance;
+  struct route_table *distance_table;
+
+  /* For redistribute route map. */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+    int metric_config;
+    u_int32_t metric;
+  } route_map[ZEBRA_ROUTE_MAX];
+};
+
+/* RIP routing table entry which belong to rip_packet. */
+struct rte
+{
+  u_int16_t family;            /* Address family of this route. */
+  u_int16_t tag;               /* Route Tag which included in RIP2 packet. */
+  struct in_addr prefix;       /* Prefix of rip route. */
+  struct in_addr mask;         /* Netmask of rip route. */
+  struct in_addr nexthop;      /* Next hop of rip route. */
+  u_int32_t metric;            /* Metric value of rip route. */
+};
+
+/* RIP packet structure. */
+struct rip_packet
+{
+  unsigned char command;       /* Command type of RIP packet. */
+  unsigned char version;       /* RIP version which coming from peer. */
+  unsigned char pad1;          /* Padding of RIP packet header. */
+  unsigned char pad2;          /* Same as above. */
+  struct rte rte[1];           /* Address structure. */
+};
+
+/* Buffer to read RIP packet. */
+union rip_buf
+{
+  struct rip_packet rip_packet;
+  char buf[RIP_PACKET_MAXSIZ];
+};
+
+/* RIP route information. */
+struct rip_info
+{
+  /* This route's type. */
+  int type;
+
+  /* Sub type. */
+  int sub_type;
+
+  /* RIP nexthop. */
+  struct in_addr nexthop;
+  struct in_addr from;
+
+  /* Which interface does this route come from. */
+  unsigned int ifindex;
+
+  /* Metric of this route. */
+  u_int32_t metric;
+
+  /* Tag information of this route. */
+  u_int16_t tag;
+
+  /* Flags of RIP route. */
+#define RIP_RTF_FIB      1
+#define RIP_RTF_CHANGED  2
+  u_char flags;
+
+  /* Garbage collect timer. */
+  struct thread *t_timeout;
+  struct thread *t_garbage_collect;
+
+  /* Route-map futures - this variables can be changed. */
+  struct in_addr nexthop_out;
+  u_char metric_set;
+  u_int32_t metric_out;
+  unsigned int ifindex_out;
+
+  struct route_node *rp;
+
+  u_char distance;
+
+#ifdef NEW_RIP_TABLE
+  struct rip_info *next;
+  struct rip_info *prev;
+#endif /* NEW_RIP_TABLE */
+};
+
+/* RIP specific interface configuration. */
+struct rip_interface
+{
+  /* RIP is enabled on this interface. */
+  int enable_network;
+  int enable_interface;
+
+  /* RIP is running on this interface. */
+  int running;
+
+  /* RIP version control. */
+  int ri_send;
+  int ri_receive;
+
+  /* RIPv2 authentication type. */
+#define RIP_NO_AUTH                0
+#define RIP_AUTH_DATA              1
+#define RIP_AUTH_SIMPLE_PASSWORD   2
+#define RIP_AUTH_MD5               3
+  int auth_type;
+
+  /* RIPv2 authentication string. */
+  char *auth_str;
+
+  /* RIPv2 authentication key chain. */
+  char *key_chain;
+
+  /* Split horizon flag. */
+  int split_horizon;
+  int split_horizon_default;
+
+  /* For filter type slot. */
+#define RIP_FILTER_IN  0
+#define RIP_FILTER_OUT 1
+#define RIP_FILTER_MAX 2
+
+  /* Access-list. */
+  struct access_list *list[RIP_FILTER_MAX];
+
+  /* Prefix-list. */
+  struct prefix_list *prefix[RIP_FILTER_MAX];
+
+  /* Wake up thread. */
+  struct thread *t_wakeup;
+
+  /* Interface statistics. */
+  int recv_badpackets;
+  int recv_badroutes;
+  int sent_updates;
+
+  /* Passive interface. */
+  int passive;
+};
+
+/* RIP peer information. */
+struct rip_peer
+{
+  /* Peer address. */
+  struct in_addr addr;
+
+  /* Peer RIP tag value. */
+  int domain;
+
+  /* Last update time. */
+  time_t uptime;
+
+  /* Peer RIP version. */
+  u_char version;
+
+  /* Statistics. */
+  int recv_badpackets;
+  int recv_badroutes;
+
+  /* Timeout thread. */
+  struct thread *t_timeout;
+};
+
+struct rip_md5_info
+{
+  u_int16_t family;
+  u_int16_t type;
+  u_int16_t packet_len;
+  u_char keyid;
+  u_char auth_len;
+  u_int32_t sequence;
+  u_int32_t reserv1;
+  u_int32_t reserv2;
+};
+
+struct rip_md5_data
+{
+  u_int16_t family;
+  u_int16_t type;
+  u_char digest[16];
+};
+
+/* RIP accepet/announce methods. */
+#define RI_RIP_UNSPEC                      0
+#define RI_RIP_VERSION_1                   1
+#define RI_RIP_VERSION_2                   2
+#define RI_RIP_VERSION_1_AND_2             3
+
+/* Default value for "default-metric" command. */
+#define RIP_DEFAULT_METRIC_DEFAULT         1
+
+/* RIP event. */
+enum rip_event 
+{
+  RIP_READ,
+  RIP_UPDATE_EVENT,
+  RIP_TRIGGERED_UPDATE,
+};
+
+/* Macro for timer turn on. */
+#define RIP_TIMER_ON(T,F,V) \
+  do { \
+    if (!(T)) \
+      (T) = thread_add_timer (master, (F), rinfo, (V)); \
+  } while (0)
+
+/* Macro for timer turn off. */
+#define RIP_TIMER_OFF(X) \
+  do { \
+    if (X) \
+      { \
+        thread_cancel (X); \
+        (X) = NULL; \
+      } \
+  } while (0)
+
+/* Prototypes. */
+void rip_init ();
+void rip_reset ();
+void rip_clean ();
+void rip_clean_network ();
+void rip_interface_clean ();
+void rip_interface_reset ();
+void rip_passive_interface_clean ();
+void rip_if_init ();
+void rip_if_down_all ();
+void rip_route_map_init ();
+void rip_route_map_reset ();
+void rip_snmp_init ();
+void rip_zclient_init ();
+void rip_zclient_start ();
+void rip_zclient_reset ();
+void rip_offset_init ();
+int if_check_address (struct in_addr addr);
+int if_valid_neighbor (struct in_addr addr);
+
+int rip_request_send (struct sockaddr_in *, struct interface *, u_char);
+int rip_neighbor_lookup (struct sockaddr_in *);
+void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, 
+                          struct in_addr *);
+void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int);
+void rip_redistribute_withdraw (int);
+void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char);
+void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t);
+void rip_interface_multicast_set (int, struct interface *);
+void rip_distribute_update_interface (struct interface *);
+
+int config_write_rip_network (struct vty *, int);
+int config_write_rip_offset_list (struct vty *);
+int config_write_rip_redistribute (struct vty *, int);
+
+void rip_peer_init ();
+void rip_peer_update (struct sockaddr_in *, u_char);
+void rip_peer_bad_route (struct sockaddr_in *);
+void rip_peer_bad_packet (struct sockaddr_in *);
+void rip_peer_display (struct vty *);
+struct rip_peer *rip_peer_lookup (struct in_addr *);
+struct rip_peer *rip_peer_lookup_next (struct in_addr *);
+
+int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *);
+int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *);
+void rip_offset_clean ();
+
+void rip_info_free (struct rip_info *);
+u_char rip_distance_apply (struct rip_info *);
+void rip_redistribute_clean ();
+void rip_ifaddr_add (struct interface *, struct connected *);
+void rip_ifaddr_delete (struct interface *, struct connected *);
+
+/* There is only one rip strucutre. */
+extern struct rip *rip;
+
+/* Master thread strucutre. */
+extern struct thread_master *master;
+
+/* RIP statistics for SNMP. */
+extern long rip_global_route_changes;
+extern long rip_global_queries;
+
+#endif /* _ZEBRA_RIP_H */
diff --git a/ripngd/.cvsignore b/ripngd/.cvsignore
new file mode 100644 (file)
index 0000000..cd9e083
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile
+*.o
+ripngd
+ripngd.conf
+tags
+TAGS
+.deps
diff --git a/ripngd/ChangeLog b/ripngd/ChangeLog
new file mode 100644 (file)
index 0000000..07e3d76
--- /dev/null
@@ -0,0 +1,216 @@
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2001-08-28  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * ripngd.c (no_ripng_route): route_unlock_node () is not needed.
+
+2001-08-26  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * ripngd.h (struct ripng_interface): Add passive interface option.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-08-07  Akira Kato <kato@wide.ad.jp>
+
+       * ripngd.c (ripng_timers): "timers basic" argument is fixed.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.h (RIPNG_VTYSH_PATH): Change "/tmp/ripngd" to
+       "/tmp/.ripngd".
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-09-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_send_packet): Use CMSG_SPACE instead of sizeof
+       hack.  Revert privious alignment patch.
+
+2000-09-20  URA Hiroshi <ura@hiru.aoba.yokohama.jp>
+
+       * ripngd.c (ripng_send_packet): Fix an alignment bug. Thus ripngd
+       can't send packets.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_interface.c (ripng_interface_address_delete): Connected
+       address delete treatment added.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_routemap.c (route_set_metric_compile): When checking '-'
+       character, argv[1] should be argv[0].  Reported by SHIRASAKI
+       Yasuhiro <yasuhiro@ocn.v6.ntt.net>.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+2000-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_route_process): Clear prefix_ipv6 before using
+       it.
+       (ripng_redistribute_delete): Fix bug of missing
+       route_unlock_node() when redistribute route is not found.
+       (ripng_redistribute_delete): Make it sure that timers are off.
+       (ripng_redistribute_delete): Likewise.
+
+2000-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_route_process): Fix bug of mis-checking of same
+       route.
+       (show_ipv6_ripng): Include ifindex to "show ipv6 ripng" output.
+
+1999-11-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_output_process): Use MINMTU when mtu value is
+       not available.
+
+1999-11-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_output_process): Calculate max RTE count from
+       interface MTU value.
+
+1999-09-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_distribute_update): Fix bug of updating
+       access-list and prefix-list.
+
+1999-09-07  URA Hiroshi <ura@hiru.aoba.yokohama.jp>
+
+       * ripngd.c (ripng_recv_packet): Change CMSG_DATA cast from (u_char
+       *) to (int *).  (u_char *) does not work for NetBSD-currnet on
+       SparcStation 10.
+
+1999-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_request_process): When request packet comes,
+       check RIPng process is enabled on the interface.
+       (ripng_redistribute_withdraw): Delete routes when `no
+       redistribute' is executed.
+
+1999-08-13  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * ripng_zebra.c (ripng_redistribute_ospf6_cmd): Add OSPF6
+       redistribute command.
+
+1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (default_information_originate): Add
+       default-information command.
+
+1999-07-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_route_process): rip_add_route() and
+       rip_delete_route() are deleted.  Both functions are integrated
+       into ripng_route_process().
+       (ripng_request_process): Proper reply for request message.
+
+       * ripng_routemap.c: New file added.
+
+1999-07-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_nexthop_rte): RIPng next hop routine is
+       rewritten.
+       (show_ipv6_ripng): Change `show ip ripng' to `show ipv6 ripng'.
+       (ripng_response_process): RIPng incoming packet's hop count check
+       added.
+       (ripng_response_process): Add strict RTE checking.
+
+1999-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_add_route): Fix metric compare bug.
+
+1999-06-25  itojun@iijlab.net
+
+       * ripngd.c (ripng_distribute_in): "distribute in" filter in ripngd
+       actually work.
+
+1999-05-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_zebra): Send each ripng information by separate
+       zebra packet.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_interface.c (if_add_multicast): Change log to zlog.
+
+1999-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_interface.c (ripng_zebra_get_interface): Add function.
+
+       * ripng_zebra.c (redistribute_ripng): Delete function because
+       redistirbute the routes to the zebra daemon is now default
+       behavior.
+
+1999-05-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.conf.sample: Change network to route statement.
+
+1999-03-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c: Old non Advanced API version ripng_send_packet and
+       ripng_recv_packet is removed.
+       * ripng_radix.c: File removed.
+
+1998-12-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Now I assume KAME support Advanced API and use sendmsg/recvmsg.
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_interface.c: Delete old ifa (interface address) related
+       functions.
+
+1998-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_debug.[ch]: New file.
+
+       * ripngd.c (ripng_supply): Do not send header only RIPng packet.
+       Change `network' statement to `route' statement.
+       (ripng_request_process): Reply to RIPng REQUEST packet.
+
+1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripngd.c (ripng_config_write): Delete vector v argument.
+       * ripng_zebra.c (zebra_config_write): Likewise.
+       * ripng_interface.c (interface_config_write): Likewise.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ripng_route.h: New file.
+
+       * ripng_interface.c:  Delete #include <linux/in6.h>.
+       ripng_main.c: likewise.
+       ripng_radix.c: likewise.
+       ripng_route.c: likewise.
+       ripng_zebra.c: likewise.
+       ripngd.c: likewise.
+
+1998-12-06  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * ripngd.h (IPV6_ADD_MEMBERSHIP): If IPV6_ADD_MEMBERSHIP is not
+       defined. Define IPV6_ADD_MEMBERSHIP as IPV6_JOIN_GROUP.
+
+1998-09-15  HEO SeonMeyong  <seirios@matrix.iri.co.jp>
+
+       * all Hydrangea define is changed to KAME.
+
diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am
new file mode 100644 (file)
index 0000000..2835aa2
--- /dev/null
@@ -0,0 +1,37 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = libripng.a
+sbin_PROGRAMS = ripngd
+
+libripng_a_SOURCES = \
+       ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \
+       ripng_routemap.c
+
+noinst_HEADERS = \
+       ripng_debug.h ripng_route.h ripngd.h
+
+ripngd_SOURCES = \
+       ripng_main.c $(libripng_a_SOURCES)
+
+ripngd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ripngd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
diff --git a/ripngd/Makefile.in b/ripngd/Makefile.in
new file mode 100644 (file)
index 0000000..61e0df2
--- /dev/null
@@ -0,0 +1,487 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = libripng.a
+sbin_PROGRAMS = ripngd
+
+libripng_a_SOURCES = \
+       ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \
+       ripng_routemap.c
+
+
+noinst_HEADERS = \
+       ripng_debug.h ripng_route.h ripngd.h
+
+
+ripngd_SOURCES = \
+       ripng_main.c $(libripng_a_SOURCES)
+
+
+ripngd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ripngd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+subdir = ripngd
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libripng_a_AR = $(AR) cru
+libripng_a_LIBADD =
+am_libripng_a_OBJECTS = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \
+       ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \
+       ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT)
+libripng_a_OBJECTS = $(am_libripng_a_OBJECTS)
+sbin_PROGRAMS = ripngd$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \
+       ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \
+       ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT)
+am_ripngd_OBJECTS = ripng_main.$(OBJEXT) $(am__objects_1)
+ripngd_OBJECTS = $(am_ripngd_OBJECTS)
+ripngd_DEPENDENCIES = ../lib/libzebra.a
+ripngd_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ripng_debug.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ripng_interface.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ripng_main.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ripng_route.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ripng_routemap.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/ripng_zebra.Po ./$(DEPDIR)/ripngd.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  ripngd/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libripng.a: $(libripng_a_OBJECTS) $(libripng_a_DEPENDENCIES) 
+       -rm -f libripng.a
+       $(libripng_a_AR) libripng.a $(libripng_a_OBJECTS) $(libripng_a_LIBADD)
+       $(RANLIB) libripng.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sbindir)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+         rm -f $(DESTDIR)$(sbindir)/$$f; \
+       done
+
+clean-sbinPROGRAMS:
+       -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ripngd$(EXEEXT): $(ripngd_OBJECTS) $(ripngd_DEPENDENCIES) 
+       @rm -f ripngd$(EXEEXT)
+       $(LINK) $(ripngd_LDFLAGS) $(ripngd_OBJECTS) $(ripngd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripngd.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+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 =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-noinstLIBRARIES clean-sbinPROGRAMS ctags 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 pdf pdf-am ps ps-am tags uninstall \
+       uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c
new file mode 100644 (file)
index 0000000..51314bc
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * RIPng debug output routines
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include "command.h"
+#include "ripngd/ripng_debug.h"
+
+/* For debug statement. */
+unsigned long ripng_debug_event = 0;
+unsigned long ripng_debug_packet = 0;
+unsigned long ripng_debug_zebra = 0;
+\f
+DEFUN (show_debugging_ripng,
+       show_debugging_ripng_cmd,
+       "show debugging ripng",
+       SHOW_STR
+       "RIPng configuration\n"
+       "Debugging information\n")
+{
+  vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+  if (IS_RIPNG_DEBUG_EVENT)
+    vty_out (vty, "  RIPng event debugging is on%s", VTY_NEWLINE);
+
+  if (IS_RIPNG_DEBUG_PACKET)
+    {
+      if (IS_RIPNG_DEBUG_SEND && IS_RIPNG_DEBUG_RECV)
+       {
+         vty_out (vty, "  RIPng packet%s debugging is on%s",
+                  IS_RIPNG_DEBUG_DETAIL ? " detail" : "",
+                  VTY_NEWLINE);
+       }
+      else
+       {
+         if (IS_RIPNG_DEBUG_SEND)
+           vty_out (vty, "  RIPng packet send%s debugging is on%s",
+                    IS_RIPNG_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, "  RIPng packet receive%s debugging is on%s",
+                    IS_RIPNG_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+       }
+    }
+
+  if (IS_RIPNG_DEBUG_ZEBRA)
+    vty_out (vty, "  RIPng zebra debugging is on%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ripng_events,
+       debug_ripng_events_cmd,
+       "debug ripng events",
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng events\n")
+{
+  ripng_debug_event = RIPNG_DEBUG_EVENT;
+  return CMD_WARNING;
+}
+
+DEFUN (debug_ripng_packet,
+       debug_ripng_packet_cmd,
+       "debug ripng packet",
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n")
+{
+  ripng_debug_packet = RIPNG_DEBUG_PACKET;
+  ripng_debug_packet |= RIPNG_DEBUG_SEND;
+  ripng_debug_packet |= RIPNG_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ripng_packet_direct,
+       debug_ripng_packet_direct_cmd,
+       "debug ripng packet (recv|send)",
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+{
+  ripng_debug_packet |= RIPNG_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    ripng_debug_packet |= RIPNG_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    ripng_debug_packet |= RIPNG_DEBUG_RECV;
+  ripng_debug_packet &= ~RIPNG_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ripng_packet_detail,
+       debug_ripng_packet_detail_cmd,
+       "debug ripng packet (recv|send) detail",
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n"
+       "Debug option set detaied information\n")
+{
+  ripng_debug_packet |= RIPNG_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    ripng_debug_packet |= RIPNG_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    ripng_debug_packet |= RIPNG_DEBUG_RECV;
+  ripng_debug_packet |= RIPNG_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ripng_zebra,
+       debug_ripng_zebra_cmd,
+       "debug ripng zebra",
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng and zebra communication\n")
+{
+  ripng_debug_zebra = RIPNG_DEBUG_ZEBRA;
+  return CMD_WARNING;
+}
+
+DEFUN (no_debug_ripng_events,
+       no_debug_ripng_events_cmd,
+       "no debug ripng events",
+       NO_STR
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng events\n")
+{
+  ripng_debug_event = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ripng_packet,
+       no_debug_ripng_packet_cmd,
+       "no debug ripng packet",
+       NO_STR
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n")
+{
+  ripng_debug_packet = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ripng_packet_direct,
+       no_debug_ripng_packet_direct_cmd,
+       "no debug ripng packet (recv|send)",
+       NO_STR
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+{
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    {
+      if (IS_RIPNG_DEBUG_RECV)
+       ripng_debug_packet &= ~RIPNG_DEBUG_SEND;
+      else
+       ripng_debug_packet = 0;
+    }
+  else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    {
+      if (IS_RIPNG_DEBUG_SEND)
+       ripng_debug_packet &= ~RIPNG_DEBUG_RECV;
+      else
+       ripng_debug_packet = 0;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ripng_zebra,
+       no_debug_ripng_zebra_cmd,
+       "no debug ripng zebra",
+       NO_STR
+       DEBUG_STR
+       "RIPng configuration\n"
+       "Debug option set for ripng and zebra communication\n")
+{
+  ripng_debug_zebra = 0;
+  return CMD_WARNING;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  ""                           /* Debug node has no interface. */
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+  int write = 0;
+
+  if (IS_RIPNG_DEBUG_EVENT)
+    {
+      vty_out (vty, "debug ripng events%s", VTY_NEWLINE);
+      write++;
+    }
+  if (IS_RIPNG_DEBUG_PACKET)
+    {
+      if (IS_RIPNG_DEBUG_SEND && IS_RIPNG_DEBUG_RECV)
+       {
+         vty_out (vty, "debug ripng packet%s%s",
+                  IS_RIPNG_DEBUG_DETAIL ? " detail" : "",
+                  VTY_NEWLINE);
+         write++;
+       }
+      else
+       {
+         if (IS_RIPNG_DEBUG_SEND)
+           vty_out (vty, "debug ripng packet send%s%s",
+                    IS_RIPNG_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, "debug ripng packet recv%s%s",
+                    IS_RIPNG_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         write++;
+       }
+    }
+  if (IS_RIPNG_DEBUG_ZEBRA)
+    {
+      vty_out (vty, "debug ripng zebra%s", VTY_NEWLINE);
+      write++;
+    }
+  return write;
+}
+
+void
+ripng_debug_reset ()
+{
+  ripng_debug_event = 0;
+  ripng_debug_packet = 0;
+  ripng_debug_zebra = 0;
+}
+
+void
+ripng_debug_init ()
+{
+  ripng_debug_event = 0;
+  ripng_debug_packet = 0;
+  ripng_debug_zebra = 0;
+
+  install_node (&debug_node, config_write_debug);
+
+  install_element (VIEW_NODE, &show_debugging_ripng_cmd);
+
+  install_element (ENABLE_NODE, &show_debugging_ripng_cmd);
+  install_element (ENABLE_NODE, &debug_ripng_events_cmd);
+  install_element (ENABLE_NODE, &debug_ripng_packet_cmd);
+  install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd);
+  install_element (ENABLE_NODE, &debug_ripng_packet_detail_cmd);
+  install_element (ENABLE_NODE, &debug_ripng_zebra_cmd);
+  install_element (ENABLE_NODE, &no_debug_ripng_events_cmd);
+  install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd);
+  install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd);
+  install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd);
+
+  install_element (CONFIG_NODE, &debug_ripng_events_cmd);
+  install_element (CONFIG_NODE, &debug_ripng_packet_cmd);
+  install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd);
+  install_element (CONFIG_NODE, &debug_ripng_packet_detail_cmd);
+  install_element (CONFIG_NODE, &debug_ripng_zebra_cmd);
+  install_element (CONFIG_NODE, &no_debug_ripng_events_cmd);
+  install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd);
+  install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd);
+  install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd);
+}
diff --git a/ripngd/ripng_debug.h b/ripngd/ripng_debug.h
new file mode 100644 (file)
index 0000000..6713a15
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * RIPng debug output routines
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_RIPNG_DEBUG_H
+#define _ZEBRA_RIPNG_DEBUG_H
+
+/* Debug flags. */
+#define RIPNG_DEBUG_EVENT   0x01
+
+#define RIPNG_DEBUG_PACKET  0x01
+#define RIPNG_DEBUG_SEND    0x20
+#define RIPNG_DEBUG_RECV    0x40
+#define RIPNG_DEBUG_DETAIL  0x80
+
+#define RIPNG_DEBUG_ZEBRA   0x01
+
+/* Debug related macro. */
+#define IS_RIPNG_DEBUG_EVENT  (ripng_debug_event & RIPNG_DEBUG_EVENT)
+
+#define IS_RIPNG_DEBUG_PACKET (ripng_debug_packet & RIPNG_DEBUG_PACKET)
+#define IS_RIPNG_DEBUG_SEND   (ripng_debug_packet & RIPNG_DEBUG_SEND)
+#define IS_RIPNG_DEBUG_RECV   (ripng_debug_packet & RIPNG_DEBUG_RECV)
+#define IS_RIPNG_DEBUG_DETAIL (ripng_debug_packet & RIPNG_DEBUG_DETAIL)
+
+#define IS_RIPNG_DEBUG_ZEBRA  (ripng_debug_zebra & RIPNG_DEBUG_ZEBRA)
+
+extern unsigned long ripng_debug_event;
+extern unsigned long ripng_debug_packet;
+extern unsigned long ripng_debug_zebra;
+
+void ripng_debug_init ();
+
+#endif /* _ZEBRA_RIPNG_DEBUG_H */
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
new file mode 100644 (file)
index 0000000..c177381
--- /dev/null
@@ -0,0 +1,835 @@
+/*
+ * Interface related function for RIPng.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "prefix.h"
+#include "memory.h"
+#include "network.h"
+#include "filter.h"
+#include "log.h"
+#include "stream.h"
+#include "zclient.h"
+#include "command.h"
+#include "table.h"
+#include "thread.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_debug.h"
+\f
+/* If RFC2133 definition is used. */
+#ifndef IPV6_JOIN_GROUP
+#define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP 
+#endif
+#ifndef IPV6_LEAVE_GROUP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP 
+#endif
+
+/* Static utility function. */
+static void ripng_enable_apply (struct interface *);
+static void ripng_passive_interface_apply (struct interface *);
+
+/* Join to the all rip routers multicast group. */
+int
+ripng_multicast_join (struct interface *ifp)
+{
+  int ret;
+  struct ipv6_mreq mreq;
+
+  memset (&mreq, 0, sizeof (mreq));
+  inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
+  mreq.ipv6mr_interface = ifp->ifindex;
+
+  ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                   (char *) &mreq, sizeof (mreq));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
+
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name);
+
+  return ret;
+}
+
+/* Leave from the all rip routers multicast group. */
+int
+ripng_multicast_leave (struct interface *ifp)
+{
+  int ret;
+  struct ipv6_mreq mreq;
+
+  memset (&mreq, 0, sizeof (mreq));
+  inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
+  mreq.ipv6mr_interface = ifp->ifindex;
+
+  ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+                   (char *) &mreq, sizeof (mreq));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno));
+
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng %s leave from all-rip-routers multicast group",
+              ifp->name);
+
+  return ret;
+}
+
+/* Check max mtu size. */
+int
+ripng_check_max_mtu ()
+{
+  listnode node;
+  struct interface *ifp;
+  int mtu;
+
+  mtu = 0;
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (mtu < ifp->mtu)
+       mtu = ifp->mtu;
+    }
+  return mtu;
+}
+
+int
+ripng_if_down (struct interface *ifp)
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_interface *ri;
+
+  if (ripng->table)
+    {
+      for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+       if ((rinfo = rp->info) != NULL)
+         {
+           /* Routes got through this interface. */
+           if (rinfo->ifindex == ifp->ifindex
+               && rinfo->type == ZEBRA_ROUTE_RIPNG
+               && rinfo->sub_type == RIPNG_ROUTE_RTE)
+             {
+               ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p,
+                                        &rinfo->nexthop,
+                                        rinfo->ifindex);
+
+               RIPNG_TIMER_OFF (rinfo->t_timeout);
+               RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+             
+               rp->info = NULL;
+               route_unlock_node (rp);
+             
+               ripng_info_free (rinfo);
+             }
+           else
+             {
+               /* All redistributed routes got through this interface. */
+               if (rinfo->ifindex == ifp->ifindex)
+                 ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
+                                            (struct prefix_ipv6 *) &rp->p,
+                                            rinfo->ifindex);
+             }
+         }
+    }
+
+  ri = ifp->info;
+  
+  if (ripng && ri->running)
+   {
+     if (IS_RIPNG_DEBUG_EVENT)
+       zlog_info ("turn off %s", ifp->name);
+
+     /* Leave from multicast group. */
+     ripng_multicast_leave (ifp);
+
+     ri->running = 0;
+   }
+
+  return 0;
+}
+
+/* Inteface link up message processing. */
+int
+ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct interface *ifp;
+
+  /* zebra_interface_state_read() updates interface structure in iflist. */
+  s = zclient->ibuf;
+  ifp = zebra_interface_state_read (s);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (IS_RIPNG_DEBUG_ZEBRA)
+    zlog_info ("interface up %s index %d flags %ld metric %d mtu %d",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  /* Check if this interface is RIPng enabled or not. */
+  ripng_enable_apply (ifp);
+
+  /* Check for a passive interface. */
+  ripng_passive_interface_apply (ifp);
+
+  /* Apply distribute list to the all interface. */
+  ripng_distribute_update_interface (ifp);
+
+  return 0;
+}
+
+/* Inteface link down message processing. */
+int
+ripng_interface_down (int command, struct zclient *zclient,
+                     zebra_size_t length)
+{
+  struct stream *s;
+  struct interface *ifp;
+
+  /* zebra_interface_state_read() updates interface structure in iflist. */
+  s = zclient->ibuf;
+  ifp = zebra_interface_state_read (s);
+
+  if (ifp == NULL)
+    return 0;
+
+  ripng_if_down (ifp);
+
+  if (IS_RIPNG_DEBUG_ZEBRA)
+    zlog_info ("interface down %s index %d flags %ld metric %d mtu %d",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  return 0;
+}
+
+/* Inteface addition message from zebra. */
+int
+ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+
+  if (IS_RIPNG_DEBUG_ZEBRA)
+    zlog_info ("RIPng interface add %s index %d flags %ld metric %d mtu %d",
+              ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  /* Check is this interface is RIP enabled or not.*/
+  ripng_enable_apply (ifp);
+
+  /* Apply distribute list to the interface. */
+  ripng_distribute_update_interface (ifp);
+
+  /* Check interface routemap. */
+  ripng_if_rmap_update_interface (ifp);
+
+  return 0;
+}
+
+int
+ripng_interface_delete (int command, struct zclient *zclient,
+                       zebra_size_t length)
+{
+  return 0;
+}
+
+int
+ripng_interface_address_add (int command, struct zclient *zclient,
+                            zebra_size_t length)
+{
+  struct connected *c;
+  struct prefix *p;
+  char buf[INET6_ADDRSTRLEN];
+
+  c = zebra_interface_address_add_read (zclient->ibuf);
+
+  if (c == NULL)
+    return 0;
+
+  p = c->address;
+
+  if (p->family == AF_INET6)
+    {
+      if (IS_RIPNG_DEBUG_ZEBRA)
+       zlog_info ("RIPng connected address %s/%d add",
+                  inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN),
+                  p->prefixlen);
+      
+      /* Check is this interface is RIP enabled or not.*/
+      ripng_enable_apply (c->ifp);
+    }
+
+  return 0;
+}
+
+int
+ripng_interface_address_delete (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *ifc;
+  struct prefix *p;
+  char buf[INET6_ADDRSTRLEN];
+
+  ifc = zebra_interface_address_delete_read (zclient->ibuf);
+  
+  if (ifc)
+    {
+      p = ifc->address;
+
+      if (p->family == AF_INET6)
+       {
+         if (IS_RIPNG_DEBUG_ZEBRA)
+           zlog_info ("RIPng connected address %s/%d delete",
+                      inet_ntop (AF_INET6, &p->u.prefix6, buf,
+                                 INET6_ADDRSTRLEN),
+                      p->prefixlen);
+
+         /* Check is this interface is RIP enabled or not.*/
+         ripng_enable_apply (ifc->ifp);
+       }
+      connected_free (ifc);
+    }
+
+  return 0;
+}
+\f
+/* RIPng enable interface vector. */
+vector ripng_enable_if;
+
+/* RIPng enable network table. */
+struct route_table *ripng_enable_network;
+
+/* Lookup RIPng enable network. */
+int
+ripng_enable_network_lookup (struct interface *ifp)
+{
+  listnode listnode;
+  struct connected *connected;
+
+  for (listnode = listhead (ifp->connected); listnode; nextnode (listnode))
+    if ((connected = getdata (listnode)) != NULL)
+      {
+       struct prefix *p; 
+       struct route_node *node;
+
+       p = connected->address;
+
+       if (p->family == AF_INET6)
+         {
+           node = route_node_match (ripng_enable_network, p);
+           if (node)
+             {
+               route_unlock_node (node);
+               return 1;
+             }
+         }
+      }
+  return -1;
+}
+
+/* Add RIPng enable network. */
+int
+ripng_enable_network_add (struct prefix *p)
+{
+  struct route_node *node;
+
+  node = route_node_get (ripng_enable_network, p);
+
+  if (node->info)
+    {
+      route_unlock_node (node);
+      return -1;
+    }
+  else
+    node->info = "enabled";
+
+  return 1;
+}
+
+/* Delete RIPng enable network. */
+int
+ripng_enable_network_delete (struct prefix *p)
+{
+  struct route_node *node;
+
+  node = route_node_lookup (ripng_enable_network, p);
+  if (node)
+    {
+      node->info = NULL;
+
+      /* Unlock info lock. */
+      route_unlock_node (node);
+
+      /* Unlock lookup lock. */
+      route_unlock_node (node);
+
+      return 1;
+    }
+  return -1;
+}
+
+/* Lookup function. */
+int
+ripng_enable_if_lookup (char *ifname)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (ripng_enable_if); i++)
+    if ((str = vector_slot (ripng_enable_if, i)) != NULL)
+      if (strcmp (str, ifname) == 0)
+       return i;
+  return -1;
+}
+
+/* Add interface to ripng_enable_if. */
+int
+ripng_enable_if_add (char *ifname)
+{
+  int ret;
+
+  ret = ripng_enable_if_lookup (ifname);
+  if (ret >= 0)
+    return -1;
+
+  vector_set (ripng_enable_if, strdup (ifname));
+
+  return 1;
+}
+
+/* Delete interface from ripng_enable_if. */
+int
+ripng_enable_if_delete (char *ifname)
+{
+  int index;
+  char *str;
+
+  index = ripng_enable_if_lookup (ifname);
+  if (index < 0)
+    return -1;
+
+  str = vector_slot (ripng_enable_if, index);
+  free (str);
+  vector_unset (ripng_enable_if, index);
+
+  return 1;
+}
+
+/* Wake up interface. */
+int
+ripng_interface_wakeup (struct thread *t)
+{
+  struct interface *ifp;
+  struct ripng_interface *ri;
+
+  /* Get interface. */
+  ifp = THREAD_ARG (t);
+
+  ri = ifp->info;
+  ri->t_wakeup = NULL;
+
+  /* Join to multicast group. */
+  ripng_multicast_join (ifp);
+
+  /* Send RIP request to the interface. */
+  ripng_request (ifp);
+
+  return 0;
+}
+
+/* Check RIPng is enabed on this interface. */
+void
+ripng_enable_apply (struct interface *ifp)
+{
+  int ret;
+  struct ripng_interface *ri = NULL;
+
+  /* Check interface. */
+  if (if_is_loopback (ifp))
+    return;
+
+  if (! if_is_up (ifp))
+    return;
+  
+  ri = ifp->info;
+
+  /* Check network configuration. */
+  ret = ripng_enable_network_lookup (ifp);
+
+  /* If the interface is matched. */
+  if (ret > 0)
+    ri->enable_network = 1;
+  else
+    ri->enable_network = 0;
+
+  /* Check interface name configuration. */
+  ret = ripng_enable_if_lookup (ifp->name);
+  if (ret >= 0)
+    ri->enable_interface = 1;
+  else
+    ri->enable_interface = 0;
+
+  /* Update running status of the interface. */
+  if (ri->enable_network || ri->enable_interface)
+    {
+      if (! ri->running)
+       {
+         if (IS_RIPNG_DEBUG_EVENT)
+           zlog_info ("RIPng turn on %s", ifp->name);
+
+         /* Add interface wake up thread. */
+         if (! ri->t_wakeup)
+           ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
+                                            ifp, 1);
+#if 0
+         /* Join to multicast group. */
+         ripng_multicast_join (ifp);
+
+         /* Send RIP request to the interface. */
+         ripng_request (ifp);
+#endif /* 0 */
+
+         ri->running = 1;
+       }
+    }
+  else
+    {
+      if (ri->running)
+       {
+         if (IS_RIPNG_DEBUG_EVENT)
+           zlog_info ("RIPng turn off %s", ifp->name);
+
+         /* Leave from multicast group. */
+         ripng_multicast_leave (ifp);
+
+         ri->running = 0;
+       }
+    }
+}
+
+/* Set distribute list to all interfaces. */
+static void
+ripng_enable_apply_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ripng_enable_apply (ifp);
+    }
+}
+\f
+/* Vector to store passive-interface name. */
+vector Vripng_passive_interface;
+
+/* Utility function for looking up passive interface settings. */
+int
+ripng_passive_interface_lookup (char *ifname)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (Vripng_passive_interface); i++)
+    if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
+      if (strcmp (str, ifname) == 0)
+       return i;
+  return -1;
+}
+
+void
+ripng_passive_interface_apply (struct interface *ifp)
+{
+  int ret;
+  struct ripng_interface *ri;
+
+  ri = ifp->info;
+
+  ret = ripng_passive_interface_lookup (ifp->name);
+  if (ret < 0)
+    ri->passive = 0;
+  else
+    ri->passive = 1;
+}
+
+void
+ripng_passive_interface_apply_all (void)
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ripng_passive_interface_apply (ifp);
+    }
+}
+
+/* Passive interface. */
+int
+ripng_passive_interface_set (struct vty *vty, char *ifname)
+{
+  if (ripng_passive_interface_lookup (ifname) >= 0)
+    return CMD_WARNING;
+
+  vector_set (Vripng_passive_interface, strdup (ifname));
+
+  ripng_passive_interface_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+int
+ripng_passive_interface_unset (struct vty *vty, char *ifname)
+{
+  int i;
+  char *str;
+
+  i = ripng_passive_interface_lookup (ifname);
+  if (i < 0)
+    return CMD_WARNING;
+
+  str = vector_slot (Vripng_passive_interface, i);
+  free (str);
+  vector_unset (Vripng_passive_interface, i);
+
+  ripng_passive_interface_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* Free all configured RIP passive-interface settings. */
+void
+ripng_passive_interface_clean (void)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (Vripng_passive_interface); i++)
+    if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
+      {
+       free (str);
+       vector_slot (Vripng_passive_interface, i) = NULL;
+      }
+  ripng_passive_interface_apply_all ();
+}
+
+/* Write RIPng enable network and interface to the vty. */
+int
+ripng_network_write (struct vty *vty)
+{
+  int i;
+  char *str;
+  char *ifname;
+  struct route_node *node;
+  char buf[BUFSIZ];
+
+  /* Write enable network. */
+  for (node = route_top (ripng_enable_network); node; node = route_next (node))
+    if (node->info)
+      {
+       struct prefix *p = &node->p;
+       vty_out (vty, " network %s/%d%s", 
+                inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                p->prefixlen,
+                VTY_NEWLINE);
+
+      }
+  
+  /* Write enable interface. */
+  for (i = 0; i < vector_max (ripng_enable_if); i++)
+    if ((str = vector_slot (ripng_enable_if, i)) != NULL)
+      vty_out (vty, " network %s%s", str,
+              VTY_NEWLINE);
+
+  /* Write passive interface. */
+  for (i = 0; i < vector_max (Vripng_passive_interface); i++)
+    if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
+      vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
+
+  return 0;
+}
+
+/* RIPng enable on specified interface or matched network. */
+DEFUN (ripng_network,
+       ripng_network_cmd,
+       "network IF_OR_ADDR",
+       "RIPng enable on specified interface or network.\n"
+       "Interface or address")
+{
+  int ret;
+  struct prefix p;
+
+  ret = str2prefix (argv[0], &p);
+
+  /* Given string is IPv6 network or interface name. */
+  if (ret)
+    ret = ripng_enable_network_add (&p);
+  else
+    ret = ripng_enable_if_add (argv[0]);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "There is same network configuration %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ripng_enable_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* RIPng enable on specified interface or matched network. */
+DEFUN (no_ripng_network,
+       no_ripng_network_cmd,
+       "no network IF_OR_ADDR",
+       NO_STR
+       "RIPng enable on specified interface or network.\n"
+       "Interface or address")
+{
+  int ret;
+  struct prefix p;
+
+  ret = str2prefix (argv[0], &p);
+
+  /* Given string is interface name. */
+  if (ret)
+    ret = ripng_enable_network_delete (&p);
+  else
+    ret = ripng_enable_if_delete (argv[0]);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "can't find network %s%s", argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  ripng_enable_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ripng_passive_interface,
+       ripng_passive_interface_cmd,
+       "passive-interface IFNAME",
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+{
+  return ripng_passive_interface_set (vty, argv[0]);
+}
+
+DEFUN (no_ripng_passive_interface,
+       no_ripng_passive_interface_cmd,
+       "no passive-interface IFNAME",
+       NO_STR
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+{
+  return ripng_passive_interface_unset (vty, argv[0]);
+}
+\f
+struct ripng_interface *
+ri_new ()
+{
+  struct ripng_interface *ri;
+  ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
+  return ri;
+}
+
+int
+ripng_if_new_hook (struct interface *ifp)
+{
+  ifp->info = ri_new ();
+  return 0;
+}
+
+/* Configuration write function for ripngd. */
+int
+interface_config_write (struct vty *vty)
+{
+  listnode node;
+  struct interface *ifp;
+  struct ripng_interface *ri;
+  int write = 0;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      vty_out (vty, "interface %s%s", ifp->name,
+              VTY_NEWLINE);
+      if (ifp->desc)
+       vty_out (vty, " description %s%s", ifp->desc,
+                VTY_NEWLINE);
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+
+      write++;
+    }
+  return write;
+}
+
+/* ripngd's interface node. */
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+};
+
+/* Initialization of interface. */
+void
+ripng_if_init ()
+{
+  /* Interface initialize. */
+  iflist = list_new ();
+  if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
+
+  /* RIPng enable network init. */
+  ripng_enable_network = route_table_init ();
+
+  /* RIPng enable interface init. */
+  ripng_enable_if = vector_init (1);
+
+  /* RIPng passive interface. */
+  Vripng_passive_interface = vector_init (1);
+
+  /* Install interface node. */
+  install_node (&interface_node, interface_config_write);
+
+  install_element (CONFIG_NODE, &interface_cmd);
+  install_element (INTERFACE_NODE, &config_end_cmd);
+  install_element (INTERFACE_NODE, &config_exit_cmd);
+  install_element (INTERFACE_NODE, &config_help_cmd);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+
+  install_element (RIPNG_NODE, &ripng_network_cmd);
+  install_element (RIPNG_NODE, &no_ripng_network_cmd);
+  install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
+  install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
+}
diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c
new file mode 100644 (file)
index 0000000..aec74bb
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * RIPngd main routine.
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "thread.h"
+#include "log.h"
+#include "prefix.h"
+#include "if.h"
+
+#include "ripngd/ripngd.h"
+
+/* Configuration filename and directory. */
+char config_current[] = RIPNG_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG;
+
+/* RIPngd options. */
+struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "log_mode",    no_argument,       NULL, 'l'},
+  { "help",        no_argument,       NULL, 'h'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "retain",      no_argument,       NULL, 'r'},
+  { "version",     no_argument,       NULL, 'v'},
+  { 0 }
+};
+
+/* RIPngd program name */
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_RIPNGD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\
+Daemon which manages RIPng.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-l. --log_mode     Set verbose log mode flag\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-r, --retain       When program terminates, retain added route by ripngd.\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+  exit (status);
+}
+\f
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog (NULL, LOG_INFO, "SIGHUP received");
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog (NULL, LOG_INFO, "Terminating on signal");
+
+  if (! retain_mode)
+    ripng_terminate ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+  signal_set (SIGUSR1, sigusr1);
+}
+\f
+/* RIPngd main routine. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  char *vty_addr = NULL;
+  int vty_port = 0;
+  int daemon_mode = 0;
+  char *config_file = NULL;
+  char *progname;
+  struct thread thread;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* get program name */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  zlog_default = openzlog(progname, ZLOG_NOLOG, ZLOG_RIPNG,
+                         LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  while (1) 
+    {
+      int opt;
+
+      opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0);
+    
+      if (opt == EOF)
+       break;
+
+      switch (opt) 
+       {
+       case 0:
+         break;
+       case 'd':
+         daemon_mode = 1;
+         break;
+       case 'l':
+         /* log_mode = 1; */
+         break;
+       case 'f':
+         config_file = optarg;
+         break;
+       case 'A':
+         vty_addr = optarg;
+         break;
+        case 'i':
+          pid_file = optarg;
+          break;
+       case 'P':
+         vty_port = atoi (optarg);
+         break;
+       case 'r':
+         retain_mode = 1;
+         break;
+       case 'v':
+         print_version (progname);
+         exit (0);
+         break;
+       case 'h':
+         usage (progname, 0);
+         break;
+       default:
+         usage (progname, 1);
+         break;
+       }
+    }
+
+  master = thread_master_create ();
+
+  /* Library inits. */
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+
+  /* RIPngd inits. */
+  ripng_init ();
+  zebra_init ();
+  sort_node ();
+
+  /* Get configuration file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Change to the daemon program. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Create VTY socket */
+  vty_serv_sock (vty_addr,
+                vty_port ? vty_port : RIPNG_VTY_PORT, RIPNG_VTYSH_PATH);
+
+  /* Process id file create. */
+  pid_output (pid_file);
+
+  /* Fetch next active thread. */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached. */
+  exit (0);
+}
diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c
new file mode 100644 (file)
index 0000000..27475f0
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * RIPng routes function.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "if.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_route.h"
+
+struct ripng_aggregate *
+ripng_aggregate_new ()
+{
+  struct ripng_aggregate *new;
+
+  new = XCALLOC (MTYPE_RIPNG_AGGREGATE, sizeof (struct ripng_aggregate));
+  return new;
+}
+
+void
+ripng_aggregate_free (struct ripng_aggregate *aggregate)
+{
+  XFREE (MTYPE_RIPNG_AGGREGATE, aggregate);
+}
+
+/* Aggregate count increment check. */
+void
+ripng_aggregate_increment (struct route_node *child, struct ripng_info *rinfo)
+{
+  struct route_node *np;
+  struct ripng_aggregate *aggregate;
+
+  for (np = child; np; np = np->parent)
+    if ((aggregate = np->aggregate) != NULL)
+      {
+       aggregate->count++;
+       rinfo->suppress++;
+      }
+}
+
+/* Aggregate count decrement check. */
+void
+ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo)
+{
+  struct route_node *np;
+  struct ripng_aggregate *aggregate;
+
+  for (np = child; np; np = np->parent)
+    if ((aggregate = np->aggregate) != NULL)
+      {
+       aggregate->count--;
+       rinfo->suppress--;
+      }
+}
+
+/* RIPng routes treatment. */
+int
+ripng_aggregate_add (struct prefix *p)
+{
+  struct route_node *top;
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_aggregate *aggregate;
+  struct ripng_aggregate *sub;
+
+  /* Get top node for aggregation. */
+  top = route_node_get (ripng->table, p);
+
+  /* Allocate new aggregate. */
+  aggregate = ripng_aggregate_new ();
+  aggregate->metric = 1;
+
+  top->aggregate = aggregate;
+
+  /* Suppress routes match to the aggregate. */
+  for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top))
+    {
+      /* Suppress normal route. */
+      if ((rinfo = rp->info) != NULL)
+       {
+         aggregate->count++;
+         rinfo->suppress++;
+       }
+      /* Suppress aggregate route.  This may not need. */
+      if (rp != top && (sub = rp->aggregate) != NULL)
+       {
+         aggregate->count++;
+         sub->suppress++;
+       }
+    }
+
+  return 0;
+}
+
+/* Delete RIPng static route. */
+int
+ripng_aggregate_delete (struct prefix *p)
+{
+  struct route_node *top;
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_aggregate *aggregate;
+  struct ripng_aggregate *sub;
+
+  /* Get top node for aggregation. */
+  top = route_node_get (ripng->table, p);
+
+  /* Allocate new aggregate. */
+  aggregate = top->aggregate;
+
+  /* Suppress routes match to the aggregate. */
+  for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top))
+    {
+      /* Suppress normal route. */
+      if ((rinfo = rp->info) != NULL)
+       {
+         aggregate->count--;
+         rinfo->suppress--;
+       }
+
+      if (rp != top && (sub = rp->aggregate) != NULL)
+       {
+         aggregate->count--;
+         sub->suppress--;
+       }
+    }
+
+  top->aggregate = NULL;
+  ripng_aggregate_free (aggregate);
+
+  route_unlock_node (top);
+  route_unlock_node (top);
+
+  return 0;
+}
diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h
new file mode 100644 (file)
index 0000000..283d826
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * RIPng daemon
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_RIPNG_ROUTE_H
+#define _ZEBRA_RIPNG_ROUTE_H
+
+struct ripng_aggregate
+{
+  /* Aggregate route count. */
+  unsigned int count;
+
+  /* Suppressed route count. */
+  unsigned int suppress;
+
+  /* Metric of this route.  */
+  u_char metric;               
+
+  /* Tag field of RIPng packet.*/
+  u_short tag;         
+};
+
+void
+ripng_aggregate_increment (struct route_node *rp, struct ripng_info *rinfo);
+
+void
+ripng_aggregate_decrement (struct route_node *rp, struct ripng_info *rinfo);
+
+int
+ripng_aggregate_add (struct prefix *p);
+
+int
+ripng_aggregate_delete (struct prefix *p);
+
+#endif /* _ZEBRA_RIPNG_ROUTE_H */
diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c
new file mode 100644 (file)
index 0000000..f237e6b
--- /dev/null
@@ -0,0 +1,342 @@
+/* RIPng routemap.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "memory.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+
+#include "ripngd/ripngd.h"
+\f
+#if 0
+/* `match interface IFNAME' */
+route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+                      route_map_object_t type, void *object)
+{
+  struct ripng_info *rinfo;
+  struct interface *ifp;
+  char *ifname;
+
+  if (type == ROUTE_MAP_RIPNG)
+    {
+      ifname = rule;
+      ifp = if_lookup_by_name(ifname);
+
+      if (!ifp)
+       return RM_NOMATCH;
+
+      rinfo = object;
+
+      if (rinfo->ifindex == ifp->ifindex)
+       return RM_MATCH;
+      else
+       return RM_NOMATCH;
+    }
+  return RM_NOMATCH;
+}
+
+void *
+route_match_interface_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_interface_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+  "interface",
+  route_match_interface,
+  route_match_interface_compile,
+  route_match_interface_free
+};
+#endif /* 0 */
+\f
+struct rip_metric_modifier
+{
+  enum 
+  {
+    metric_increment,
+    metric_decrement,
+    metric_absolute
+  } type;
+
+  u_char metric;
+};
+
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix, 
+                 route_map_object_t type, void *object)
+{
+  if (type == RMAP_RIPNG)
+    {
+      struct rip_metric_modifier *mod;
+      struct ripng_info *rinfo;
+
+      mod = rule;
+      rinfo = object;
+
+      if (mod->type == metric_increment)
+       rinfo->metric += mod->metric;
+      else if (mod->type == metric_decrement)
+       rinfo->metric -= mod->metric;
+      else if (mod->type == metric_absolute)
+       rinfo->metric = mod->metric;
+
+      if (rinfo->metric < 1)
+       rinfo->metric = 1;
+      if (rinfo->metric > RIPNG_METRIC_INFINITY)
+       rinfo->metric = RIPNG_METRIC_INFINITY;
+
+      rinfo->metric_set = 1;
+    }
+  return RMAP_OKAY;
+}
+
+void *
+route_set_metric_compile (char *arg)
+{
+  int len;
+  char *pnt;
+  int type;
+  long metric;
+  char *endptr = NULL;
+  struct rip_metric_modifier *mod;
+
+  len = strlen (arg);
+  pnt = arg;
+
+  if (len == 0)
+    return NULL;
+
+  /* Examine first character. */
+  if (arg[0] == '+')
+    {
+      type = metric_increment;
+      pnt++;
+    }
+  else if (arg[0] == '-')
+    {
+      type = metric_decrement;
+      pnt++;
+    }
+  else
+    type = metric_absolute;
+
+  /* Check beginning with digit string. */
+  if (*pnt < '0' || *pnt > '9')
+    return NULL;
+
+  /* Convert string to integer. */
+  metric = strtol (pnt, &endptr, 10);
+
+  if (metric == LONG_MAX || *endptr != '\0')
+    return NULL;
+  if (metric < 0 || metric > RIPNG_METRIC_INFINITY)
+    return NULL;
+
+  mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, 
+                sizeof (struct rip_metric_modifier));
+  mod->type = type;
+  mod->metric = metric;
+
+  return mod;
+}
+
+void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_set_metric_cmd = 
+{
+  "metric",
+  route_set_metric,
+  route_set_metric_compile,
+  route_set_metric_free,
+};
+\f
+int
+ripng_route_match_add (struct vty *vty, struct route_map_index *index,
+                      char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+int
+ripng_route_match_delete (struct vty *vty, struct route_map_index *index,
+                         char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+int
+ripng_route_set_add (struct vty *vty, struct route_map_index *index,
+                    char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+int
+ripng_route_set_delete (struct vty *vty, struct route_map_index *index,
+                       char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+       {
+       case RMAP_RULE_MISSING:
+         vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       case RMAP_COMPILE_ERROR:
+         vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+         return CMD_WARNING;
+         break;
+       }
+    }
+  return CMD_SUCCESS;
+}
+\f
+#if 0
+DEFUN (match_interface,
+       match_interface_cmd,
+       "match interface WORD",
+       "Match value\n"
+       "Interface\n"
+       "Interface name\n")
+{
+  return ripng_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+       no_match_interface_cmd,
+       "no match interface WORD",
+       NO_STR
+       "Match value\n"
+       "Interface\n"
+       "Interface name\n")
+{
+  return ripng_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+#endif /* 0 */
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       "Set value\n"
+       "Metric\n"
+       "METRIC value\n")
+{
+  return ripng_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       "Set value\n"
+       "Metric\n"
+       "METRIC value\n")
+{
+  return ripng_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+void
+ripng_route_map_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+
+  /* route_map_install_match (&route_match_interface_cmd); */
+  route_map_install_set (&route_set_metric_cmd);
+
+  /*
+  install_element (RMAP_NODE, &match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_cmd);
+  */
+
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+}
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
new file mode 100644 (file)
index 0000000..4d8a48d
--- /dev/null
@@ -0,0 +1,877 @@
+/*
+ * RIPngd and zebra interface.
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "routemap.h"
+#include "zclient.h"
+#include "log.h"
+
+#include "ripngd/ripngd.h"
+
+/* All information about zebra. */
+struct zclient *zclient = NULL;
+
+/* Callback prototypes for zebra client service. */
+int ripng_interface_up (int, struct zclient *, zebra_size_t);
+int ripng_interface_down (int, struct zclient *, zebra_size_t);
+int ripng_interface_add (int, struct zclient *, zebra_size_t);
+int ripng_interface_delete (int, struct zclient *, zebra_size_t);
+int ripng_interface_address_add (int, struct zclient *, zebra_size_t);
+int ripng_interface_address_delete (int, struct zclient *, zebra_size_t);
+\f
+void
+ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop,
+                     unsigned int ifindex)
+{
+  struct zapi_ipv6 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_RIPNG])
+    {
+      api.type = ZEBRA_ROUTE_RIPNG;
+      api.flags = 0;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+      api.ifindex_num = 1;
+      api.ifindex = &ifindex;
+
+      zapi_ipv6_add (zclient, p, &api);
+    }
+}
+
+void
+ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop,
+                        unsigned int ifindex)
+{
+  struct zapi_ipv6 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_RIPNG])
+    {
+      api.type = ZEBRA_ROUTE_RIPNG;
+      api.flags = 0;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+      api.ifindex_num = 1;
+      api.ifindex = &ifindex;
+
+      zapi_ipv6_delete (zclient, p, &api);
+    }
+}
+
+/* Zebra route add and delete treatment. */
+int
+ripng_zebra_read_ipv6 (int command, struct zclient *zclient,
+                      zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv6 api;
+  unsigned long ifindex;
+  struct in6_addr nexthop;
+  struct prefix_ipv6 p;
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv6 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      stream_get (&nexthop, s, 16);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+
+  if (command == ZEBRA_IPV6_ROUTE_ADD)
+    ripng_redistribute_add (api.type, 0, &p, ifindex);
+  else
+    ripng_redistribute_delete (api.type, 0, &p, ifindex);
+
+  return 0;
+}
+
+int
+ripng_redistribute_unset (int type)
+{
+  if (! zclient->redist[type])
+    return CMD_SUCCESS;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+
+  ripng_redistribute_withdraw (type);
+  
+  return CMD_SUCCESS;
+}
+
+void
+ripng_redistribute_metric_set (int type, int metric)
+{
+  ripng->route_map[type].metric_config = 1;
+  ripng->route_map[type].metric = metric;
+}
+
+void
+ripng_redistribute_metric_unset (int type)
+{
+  ripng->route_map[type].metric_config = 0;
+  ripng->route_map[type].metric = 0;
+}
+
+void
+ripng_redistribute_routemap_set (int type, char *name)
+{
+  if (ripng->route_map[type].name)
+    free (ripng->route_map[type].name);
+
+  ripng->route_map[type].name = strdup (name);
+  ripng->route_map[type].map = route_map_lookup_by_name (name);
+}
+
+void
+ripng_redistribute_routemap_unset (int type)
+{
+  if (ripng->route_map[type].name)
+    free (ripng->route_map[type].name);
+
+  ripng->route_map[type].name = NULL;
+  ripng->route_map[type].map = NULL;
+}
+
+\f
+DEFUN (router_zebra,
+       router_zebra_cmd,
+       "router zebra",
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  vty->node = ZEBRA_NODE;
+  zclient->enable = 1;
+  zclient_start (zclient);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+       no_router_zebra_cmd,
+       "no router zebra",
+       NO_STR
+       "Disable a routing process\n"
+       "Stop connection to zebra daemon\n")
+{
+  zclient->enable = 0;
+  zclient_stop (zclient);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ripng_redistribute_ripng,
+       ripng_redistribute_ripng_cmd,
+       "redistribute ripng",
+       "Redistribute information from another routing protocol\n"
+       "RIPng route\n")
+{
+  zclient->redist[ZEBRA_ROUTE_RIPNG] = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_redistribute_ripng,
+       no_ripng_redistribute_ripng_cmd,
+       "no redistribute ripng",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "RIPng route\n")
+{
+  zclient->redist[ZEBRA_ROUTE_RIPNG] = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ripng_redistribute_static,
+       ripng_redistribute_static_cmd,
+       "redistribute static",
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n")
+{
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_redistribute_static,
+       no_ripng_redistribute_static_cmd,
+       "no redistribute static",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n")
+{
+  ripng_redistribute_metric_unset (ZEBRA_ROUTE_STATIC);
+  ripng_redistribute_routemap_unset (ZEBRA_ROUTE_STATIC);
+  return ripng_redistribute_unset (ZEBRA_ROUTE_STATIC);
+}
+
+DEFUN (ripng_redistribute_kernel,
+       ripng_redistribute_kernel_cmd,
+       "redistribute kernel",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n")
+{
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_redistribute_kernel,
+       no_ripng_redistribute_kernel_cmd,
+       "no redistribute kernel",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n")
+{
+  ripng_redistribute_metric_unset (ZEBRA_ROUTE_KERNEL);
+  ripng_redistribute_routemap_unset (ZEBRA_ROUTE_KERNEL);
+  return ripng_redistribute_unset (ZEBRA_ROUTE_KERNEL);
+}
+
+DEFUN (ripng_redistribute_connected,
+       ripng_redistribute_connected_cmd,
+       "redistribute connected",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n")
+{
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_redistribute_connected,
+       no_ripng_redistribute_connected_cmd,
+       "no redistribute connected",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n")
+{
+  ripng_redistribute_metric_unset (ZEBRA_ROUTE_CONNECT);
+  ripng_redistribute_routemap_unset (ZEBRA_ROUTE_CONNECT);
+  return ripng_redistribute_unset (ZEBRA_ROUTE_CONNECT);
+}
+
+DEFUN (ripng_redistribute_bgp,
+       ripng_redistribute_bgp_cmd,
+       "redistribute bgp",
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_redistribute_bgp,
+       no_ripng_redistribute_bgp_cmd,
+       "no redistribute bgp",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  ripng_redistribute_metric_unset (ZEBRA_ROUTE_BGP);
+  ripng_redistribute_routemap_unset (ZEBRA_ROUTE_BGP);
+  return ripng_redistribute_unset (ZEBRA_ROUTE_BGP);
+}
+
+DEFUN (ripng_redistribute_ospf6,
+       ripng_redistribute_ospf6_cmd,
+       "redistribute ospf6",
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n")
+{
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_redistribute_ospf6,
+       no_ripng_redistribute_ospf6_cmd,
+       "no redistribute ospf6",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n")
+{
+  ripng_redistribute_metric_unset (ZEBRA_ROUTE_OSPF6);
+  ripng_redistribute_routemap_unset (ZEBRA_ROUTE_OSPF6);
+  return ripng_redistribute_unset (ZEBRA_ROUTE_OSPF6);
+}
+
+DEFUN (ripng_redistribute_kernel_metric,
+       ripng_redistribute_kernel_metric_cmd,
+       "redistribute kernel metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0]));
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_kernel,
+       no_ripng_redistribute_kernel_metric_cmd,
+       "no redistribute kernel metric",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n")
+
+ALIAS (no_ripng_redistribute_kernel,
+       no_ripng_redistribute_kernel_metric_val_cmd,
+       "no redistribute kernel metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFUN (ripng_redistribute_connected_metric,
+       ripng_redistribute_connected_metric_cmd,
+       "redistribute connected metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0]));
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_connected,
+       no_ripng_redistribute_connected_metric_cmd,
+       "no redistribute connected metric",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n")
+
+ALIAS (no_ripng_redistribute_connected,
+       no_ripng_redistribute_connected_metric_val_cmd,
+       "no redistribute connected metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFUN (ripng_redistribute_static_metric,
+       ripng_redistribute_static_metric_cmd,
+       "redistribute static metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0]));
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_static,
+       no_ripng_redistribute_static_metric_cmd,
+       "no redistribute static metric",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n")
+
+ALIAS (no_ripng_redistribute_static,
+       no_ripng_redistribute_static_metric_val_cmd,
+       "no redistribute static metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFUN (ripng_redistribute_ospf6_metric,
+       ripng_redistribute_ospf6_metric_cmd,
+       "redistribute ospf6 metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0]));
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_ospf6,
+       no_ripng_redistribute_ospf6_metric_cmd,
+       "no redistribute ospf6 metric",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n")
+
+ALIAS (no_ripng_redistribute_ospf6,
+       no_ripng_redistribute_ospf6_metric_val_cmd,
+       "no redistribute ospf6 metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFUN (ripng_redistribute_bgp_metric,
+       ripng_redistribute_bgp_metric_cmd,
+       "redistribute bgp metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0]));
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_bgp,
+       no_ripng_redistribute_bgp_metric_cmd,
+       "no redistribute bgp metric",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n")
+
+ALIAS (no_ripng_redistribute_bgp,
+       no_ripng_redistribute_bgp_metric_val_cmd,
+       "no redistribute bgp metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFUN (ripng_redistribute_kernel_routemap,
+       ripng_redistribute_kernel_routemap_cmd,
+       "redistribute kernel route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[0]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_kernel,
+       no_ripng_redistribute_kernel_routemap_cmd,
+       "no redistribute kernel route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_connected_routemap,
+       ripng_redistribute_connected_routemap_cmd,
+       "redistribute connected route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[0]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_connected,
+       no_ripng_redistribute_connected_routemap_cmd,
+       "no redistribute connected route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_static_routemap,
+       ripng_redistribute_static_routemap_cmd,
+       "redistribute static route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[0]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_static,
+       no_ripng_redistribute_static_routemap_cmd,
+       "no redistribute static route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_ospf6_routemap,
+       ripng_redistribute_ospf6_routemap_cmd,
+       "redistribute ospf6 route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[0]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_ospf6,
+       no_ripng_redistribute_ospf6_routemap_cmd,
+       "no redistribute ospf6 route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_bgp_routemap,
+       ripng_redistribute_bgp_routemap_cmd,
+       "redistribute bgp route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[0]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_bgp,
+       no_ripng_redistribute_bgp_routemap_cmd,
+       "no redistribute bgp route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_kernel_metric_routemap,
+       ripng_redistribute_kernel_metric_routemap_cmd,
+       "redistribute kernel metric <0-16> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0]));
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[1]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_kernel,
+       no_ripng_redistribute_kernel_metric_routemap_cmd,
+       "no redistribute kernel metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_connected_metric_routemap,
+       ripng_redistribute_connected_metric_routemap_cmd,
+       "redistribute connected metric <0-16> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0]));
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[1]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_connected,
+       no_ripng_redistribute_connected_metric_routemap_cmd,
+       "no redistribute connected metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_static_metric_routemap,
+       ripng_redistribute_static_metric_routemap_cmd,
+       "redistribute static metric <0-16> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0]));
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[1]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_static,
+       no_ripng_redistribute_static_metric_routemap_cmd,
+       "no redistribute static metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_ospf6_metric_routemap,
+       ripng_redistribute_ospf6_metric_routemap_cmd,
+       "redistribute ospf6 metric <0-16> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0]));
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[1]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_ospf6,
+       no_ripng_redistribute_ospf6_metric_routemap_cmd,
+       "no redistribute ospf6 metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFUN (ripng_redistribute_bgp_metric_routemap,
+       ripng_redistribute_bgp_metric_routemap_cmd,
+       "redistribute bgp metric <0-16> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0]));
+  ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[1]);
+  zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_redistribute_bgp,
+       no_ripng_redistribute_bgp_metric_routemap_cmd,
+       "no redistribute bgp metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+void
+ripng_redistribute_write (struct vty *vty)
+{
+  int i;
+  char *str[] = { "system", "kernel", "connected", "static", "rip",
+                 "ripng", "ospf", "ospf6", "bgp"};
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    if (i != zclient->redist_default && zclient->redist[i])
+      {
+       if (ripng->route_map[i].metric_config)
+         {
+           if (ripng->route_map[i].name)
+             vty_out (vty, " redistribute %s metric %d route-map %s%s",
+                      str[i], ripng->route_map[i].metric,
+                      ripng->route_map[i].name, VTY_NEWLINE);
+           else
+             vty_out (vty, " redistribute %s metric %d%s",
+                      str[i], ripng->route_map[i].metric, VTY_NEWLINE);
+         }
+       else
+         {
+           if (ripng->route_map[i].name)
+             vty_out (vty, " redistribute %s route-map %s%s",
+                      str[i], ripng->route_map[i].name, VTY_NEWLINE);
+           else
+             vty_out (vty, " redistribute %s%s", str[i], VTY_NEWLINE);
+         }
+      }
+}
+
+/* RIPng configuration write function. */
+int
+zebra_config_write (struct vty *vty)
+{
+  if (! zclient->enable)
+    {
+      vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+      return 1;
+    }
+  else if (! zclient->redist[ZEBRA_ROUTE_RIPNG])
+    {
+      vty_out (vty, "router zebra%s", VTY_NEWLINE);
+      vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE);
+      return 1;
+    }
+  return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-router)# ",
+};
+
+/* Initialize zebra structure and it's commands. */
+void
+zebra_init ()
+{
+  /* Allocate zebra structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_RIPNG);
+
+  zclient->interface_up = ripng_interface_up;
+  zclient->interface_down = ripng_interface_down;
+  zclient->interface_add = ripng_interface_add;
+  zclient->interface_delete = ripng_interface_delete;
+  zclient->interface_address_add = ripng_interface_address_add;
+  zclient->interface_address_delete = ripng_interface_address_delete;
+  zclient->ipv6_route_add = ripng_zebra_read_ipv6;
+  zclient->ipv6_route_delete = ripng_zebra_read_ipv6;
+  
+  /* Install zebra node. */
+  install_node (&zebra_node, zebra_config_write);
+
+  /* Install command element for zebra node. */ 
+  install_element (CONFIG_NODE, &router_zebra_cmd);
+  install_element (CONFIG_NODE, &no_router_zebra_cmd);
+  install_default (ZEBRA_NODE);
+  install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd);
+  install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd);
+  install_element (RIPNG_NODE,
+                  &no_ripng_redistribute_connected_metric_val_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd);
+  install_element (RIPNG_NODE,
+                  &no_ripng_redistribute_kernel_metric_routemap_cmd);
+  install_element (RIPNG_NODE,
+                  &ripng_redistribute_connected_metric_routemap_cmd);
+  install_element (RIPNG_NODE,
+                  &no_ripng_redistribute_connected_metric_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd);
+  install_element (RIPNG_NODE,
+                  &no_ripng_redistribute_static_metric_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd);
+  install_element (RIPNG_NODE,
+                  &no_ripng_redistribute_ospf6_metric_routemap_cmd);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd);
+}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
new file mode 100644 (file)
index 0000000..81f0eca
--- /dev/null
@@ -0,0 +1,2526 @@
+/* RIPng daemon
+ * Copyright (C) 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* For struct udphdr. */
+#include <netinet/udp.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "log.h"
+#include "thread.h"
+#include "memory.h"
+#include "if.h"
+#include "stream.h"
+#include "table.h"
+#include "command.h"
+#include "sockopt.h"
+#include "distribute.h"
+#include "plist.h"
+#include "routemap.h"
+#include "if_rmap.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_route.h"
+#include "ripngd/ripng_debug.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+/* RIPng structure which includes many parameters related to RIPng
+   protocol. If ripng couldn't active or ripng doesn't configured,
+   ripng->fd must be negative value. */
+struct ripng *ripng = NULL;
+
+enum
+{
+  ripng_all_route,
+  ripng_changed_route,
+  ripng_split_horizon,
+  ripng_no_split_horizon
+};
+
+/* Prototypes. */
+void
+ripng_output_process (struct interface *, struct sockaddr_in6 *, int, int);
+
+int
+ripng_triggered_update (struct thread *);
+
+/* RIPng next hop specification. */
+struct ripng_nexthop
+{
+  enum ripng_nexthop_type
+  {
+    RIPNG_NEXTHOP_UNSPEC,
+    RIPNG_NEXTHOP_ADDRESS
+  } flag;
+  struct in6_addr address;
+};
+\f
+/* Utility function for making IPv6 address string. */
+const char *
+inet6_ntop (struct in6_addr *p)
+{
+  static char buf[INET6_ADDRSTRLEN];
+
+  inet_ntop (AF_INET6, p, buf, INET6_ADDRSTRLEN);
+
+  return buf;
+}
+
+/* Allocate new ripng information. */
+struct ripng_info *
+ripng_info_new ()
+{
+  struct ripng_info *new;
+
+  new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
+  return new;
+}
+
+/* Free ripng information. */
+void
+ripng_info_free (struct ripng_info *rinfo)
+{
+  XFREE (MTYPE_RIPNG_ROUTE, rinfo);
+}
+\f
+static int
+setsockopt_so_recvbuf (int sock, int size)
+{
+  int ret;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int));
+  if (ret < 0)
+    zlog (NULL, LOG_ERR, "can't setsockopt SO_RCVBUF");
+  return ret;
+}
+
+/* Create ripng socket. */
+int 
+ripng_make_socket (void)
+{
+  int ret;
+  int sock;
+  struct sockaddr_in6 ripaddr;
+
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't make ripng socket");
+      return sock;
+    }
+
+  ret = setsockopt_so_recvbuf (sock, 8096);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_pktinfo (sock, 1);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_multicast_hops (sock, 255);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_multicast_loop (sock, 0);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_hoplimit (sock, 1);
+  if (ret < 0)
+    return ret;
+
+  memset (&ripaddr, 0, sizeof (ripaddr));
+  ripaddr.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  ripaddr.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
+
+  ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", strerror (errno));
+      return ret;
+    }
+  return sock;
+}
+
+/* Send RIPng packet. */
+int
+ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, 
+                  struct interface *ifp)
+{
+  int ret;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr  *cmsgptr;
+  char adata [256];
+  struct in6_pktinfo *pkt;
+  struct sockaddr_in6 addr;
+
+#ifdef DEBUG
+  if (to)
+    zlog_info ("DEBUG RIPng: send to %s", inet6_ntop (&to->sin6_addr));
+  zlog_info ("DEBUG RIPng: send if %s", ifp->name);
+  zlog_info ("DEBUG RIPng: send packet size %d", bufsize);
+#endif /* DEBUG */
+
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
+
+  /* When destination is specified. */
+  if (to != NULL)
+    {
+      addr.sin6_addr = to->sin6_addr;
+      addr.sin6_port = to->sin6_port;
+    }
+  else
+    {
+      inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
+      addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
+    }
+
+  msg.msg_name = (void *) &addr;
+  msg.msg_namelen = sizeof (struct sockaddr_in6);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+  iov.iov_base = buf;
+  iov.iov_len = bufsize;
+
+  cmsgptr = (struct cmsghdr *)adata;
+  cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
+  cmsgptr->cmsg_level = IPPROTO_IPV6;
+  cmsgptr->cmsg_type = IPV6_PKTINFO;
+
+  pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
+  memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
+  pkt->ipi6_ifindex = ifp->ifindex;
+
+  ret = sendmsg (ripng->sock, &msg, 0);
+
+  if (ret < 0)
+    zlog_warn ("RIPng send fail on %s: %s", ifp->name, strerror (errno));
+
+  return ret;
+}
+
+/* Receive UDP RIPng packet from socket. */
+int
+ripng_recv_packet (int sock, u_char *buf, int bufsize,
+                  struct sockaddr_in6 *from, unsigned int *ifindex, 
+                  int *hoplimit)
+{
+  int ret;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr  *cmsgptr;
+  struct in6_addr dst;
+
+  /* Ancillary data.  This store cmsghdr and in6_pktinfo.  But at this
+     point I can't determine size of cmsghdr */
+  char adata[1024];
+
+  /* Fill in message and iovec. */
+  msg.msg_name = (void *) from;
+  msg.msg_namelen = sizeof (struct sockaddr_in6);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = bufsize;
+
+  /* If recvmsg fail return minus value. */
+  ret = recvmsg (sock, &msg, 0);
+  if (ret < 0)
+    return ret;
+
+  for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+       cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) 
+    {
+      /* I want interface index which this packet comes from. */
+      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+         cmsgptr->cmsg_type == IPV6_PKTINFO) 
+       {
+         struct in6_pktinfo *ptr;
+         
+         ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
+         *ifindex = ptr->ipi6_ifindex;
+         dst = ptr->ipi6_addr;
+
+         if (*ifindex == 0)
+           zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
+        }
+
+      /* Incoming packet's multicast hop limit. */
+      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+         cmsgptr->cmsg_type == IPV6_HOPLIMIT)
+       *hoplimit = *((int *) CMSG_DATA (cmsgptr));
+    }
+
+  /* Hoplimit check shold be done when destination address is
+     multicast address. */
+  if (! IN6_IS_ADDR_MULTICAST (&dst))
+    *hoplimit = -1;
+
+  return ret;
+}
+
+/* Dump rip packet */
+void
+ripng_packet_dump (struct ripng_packet *packet, int size, char *sndrcv)
+{
+  caddr_t lim;
+  struct rte *rte;
+  char *command_str;
+
+  /* Set command string. */
+  if (packet->command == RIPNG_REQUEST)
+    command_str = "request";
+  else if (packet->command == RIPNG_RESPONSE)
+    command_str = "response";
+  else
+    command_str = "unknown";
+
+  /* Dump packet header. */
+  zlog_info ("%s %s version %d packet size %d", 
+            sndrcv, command_str, packet->version, size);
+
+  /* Dump each routing table entry. */
+  rte = packet->rte;
+
+  for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
+    {
+      if (rte->metric == RIPNG_METRIC_NEXTHOP)
+       zlog_info ("  nexthop %s/%d", inet6_ntop (&rte->addr), rte->prefixlen);
+      else
+       zlog_info ("  %s/%d metric %d tag %d", 
+                  inet6_ntop (&rte->addr), rte->prefixlen, 
+                  rte->metric, ntohs (rte->tag));
+    }
+}
+
+/* RIPng next hop address RTE (Route Table Entry). */
+void
+ripng_nexthop_rte (struct rte *rte,
+                  struct sockaddr_in6 *from,
+                  struct ripng_nexthop *nexthop)
+{
+  char buf[INET6_BUFSIZ];
+
+  /* Logging before checking RTE. */
+  if (IS_RIPNG_DEBUG_RECV)
+    zlog_info ("RIPng nexthop RTE address %s tag %d prefixlen %d",
+              inet6_ntop (&rte->addr), ntohs (rte->tag), rte->prefixlen);
+
+  /* RFC2080 2.1.1 Next Hop: 
+   The route tag and prefix length in the next hop RTE must be
+   set to zero on sending and ignored on receiption.  */
+  if (ntohs (rte->tag) != 0)
+    zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
+              ntohs (rte->tag), inet6_ntop (&from->sin6_addr));
+
+  if (rte->prefixlen != 0)
+    zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
+              rte->prefixlen, inet6_ntop (&from->sin6_addr));
+
+  /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
+   next hop RTE indicates that the next hop address should be the
+   originator of the RIPng advertisement.  An address specified as a
+   next hop must be a link-local address.  */
+  if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
+    {
+      nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
+      memset (&nexthop->address, 0, sizeof (struct in6_addr));
+      return;
+    }
+
+  if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
+    {
+      nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
+      IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
+      return;
+    }
+
+  /* The purpose of the next hop RTE is to eliminate packets being
+   routed through extra hops in the system.  It is particularly useful
+   when RIPng is not being run on all of the routers on a network.
+   Note that next hop RTE is "advisory".  That is, if the provided
+   information is ignored, a possibly sub-optimal, but absolutely
+   valid, route may be taken.  If the received next hop address is not
+   a link-local address, it should be treated as 0:0:0:0:0:0:0:0.  */
+  zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
+            inet6_ntop (&rte->addr),
+            inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
+
+  nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
+  memset (&nexthop->address, 0, sizeof (struct in6_addr));
+
+  return;
+}
+
+/* If ifp has same link-local address then return 1. */
+int
+ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
+{
+  listnode listnode;
+  struct connected *connected;
+  struct prefix *p;
+
+  for (listnode = listhead (ifp->connected); listnode; nextnode (listnode))
+    if ((connected = getdata (listnode)) != NULL)
+      {
+       p = connected->address;
+
+       if (p->family == AF_INET6 &&
+           IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
+           IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
+         return 1;
+      }
+  return 0;
+}
+
+/* RIPng route garbage collect timer. */
+int
+ripng_garbage_collect (struct thread *t)
+{
+  struct ripng_info *rinfo;
+  struct route_node *rp;
+
+  rinfo = THREAD_ARG (t);
+  rinfo->t_garbage_collect = NULL;
+
+  /* Off timeout timer. */
+  RIPNG_TIMER_OFF (rinfo->t_timeout);
+  
+  /* Get route_node pointer. */
+  rp = rinfo->rp;
+
+  /* Delete this route from the kernel. */
+  ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, 
+                          &rinfo->nexthop, rinfo->ifindex);
+  rinfo->flags &= ~RIPNG_RTF_FIB;
+
+  /* Aggregate count decrement. */
+  ripng_aggregate_decrement (rp, rinfo);
+
+  /* Unlock route_node. */
+  rp->info = NULL;
+  route_unlock_node (rp);
+
+  /* Free RIPng routing information. */
+  ripng_info_free (rinfo);
+
+  return 0;
+}
+
+/* Timeout RIPng routes. */
+int
+ripng_timeout (struct thread *t)
+{
+  struct ripng_info *rinfo;
+  struct route_node *rp;
+
+  rinfo = THREAD_ARG (t);
+  rinfo->t_timeout = NULL;
+
+  /* Get route_node pointer. */
+  rp = rinfo->rp;
+
+  /* - The garbage-collection timer is set for 120 seconds. */
+  RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, 
+                 ripng->garbage_time);
+
+  /* - The metric for the route is set to 16 (infinity).  This causes
+     the route to be removed from service. */
+  rinfo->metric = RIPNG_METRIC_INFINITY;
+
+  /* - The route change flag is to indicate that this entry has been
+     changed. */
+  rinfo->flags |= RIPNG_RTF_CHANGED;
+
+  /* - The output process is signalled to trigger a response. */
+  ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+
+  return 0;
+}
+
+void
+ripng_timeout_update (struct ripng_info *rinfo)
+{
+  if (rinfo->metric != RIPNG_METRIC_INFINITY)
+    {
+      RIPNG_TIMER_OFF (rinfo->t_timeout);
+      RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
+    }
+}
+
+/* Process RIPng route according to RFC2080. */
+void
+ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
+                    struct ripng_nexthop *ripng_nexthop,
+                    struct interface *ifp)
+{
+  struct prefix_ipv6 p;
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_interface *ri;
+  struct in6_addr *nexthop;
+  u_char oldmetric;
+  int same = 0;
+
+  /* Make prefix structure. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  /* p.prefix = rte->addr; */
+  IPV6_ADDR_COPY (&p.prefix, &rte->addr);
+  p.prefixlen = rte->prefixlen;
+
+  /* Make sure mask is applied. */
+  /* XXX We have to check the prefix is valid or not before call
+     apply_mask_ipv6. */
+  apply_mask_ipv6 (&p);
+
+  /* Apply input filters. */
+  ri = ifp->info;
+
+  if (ri->list[RIPNG_FILTER_IN])
+    {
+      if (access_list_apply (ri->list[RIPNG_FILTER_IN], &p) == FILTER_DENY)
+       {
+         if (IS_RIPNG_DEBUG_PACKET)
+           zlog_info ("RIPng %s/%d is filtered by distribute in",
+                      inet6_ntop (&p.prefix), p.prefixlen);
+         return;
+       }
+    }
+  if (ri->prefix[RIPNG_FILTER_IN])
+    {
+      if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], &p) == PREFIX_DENY)
+       {
+         if (IS_RIPNG_DEBUG_PACKET)
+           zlog_info ("RIPng %s/%d is filtered by prefix-list in",
+                      inet6_ntop (&p.prefix), p.prefixlen);
+         return;
+       }
+    }
+
+  /* Modify entry. */
+  if (ri->routemap[RIPNG_FILTER_IN])
+    {
+      int ret;
+      struct ripng_info newinfo;
+
+      memset (&rinfo, 0, sizeof (struct ripng_info));
+      newinfo.metric = rte->metric;
+
+      ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN], 
+                            (struct prefix *)&p, RMAP_RIPNG, &newinfo);
+
+      if (ret == RMAP_DENYMATCH)
+       {
+         if (IS_RIPNG_DEBUG_PACKET)
+           zlog_info ("RIPng %s/%d is filtered by route-map in",
+                      inet6_ntop (&p.prefix), p.prefixlen);
+         return;
+       }
+
+      rte->metric = newinfo.metric;
+    }
+
+  /* Set nexthop pointer. */
+  if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
+    nexthop = &ripng_nexthop->address;
+  else
+    nexthop = &from->sin6_addr;
+
+  /* Lookup RIPng routing table. */
+  rp = route_node_get (ripng->table, (struct prefix *) &p);
+
+  if (rp->info == NULL)
+    {
+      /* Now, check to see whether there is already an explicit route
+        for the destination prefix.  If there is no such route, add
+        this route to the routing table, unless the metric is
+        infinity (there is no point in adding a route which
+        unusable). */
+      if (rte->metric != RIPNG_METRIC_INFINITY)
+       {
+         rinfo = ripng_info_new ();
+         
+         /* - Setting the destination prefix and length to those in
+            the RTE. */
+         rp->info = rinfo;
+         rinfo->rp = rp;
+
+         /* - Setting the metric to the newly calculated metric (as
+            described above). */
+         rinfo->metric = rte->metric;
+         rinfo->tag = ntohs (rte->tag);
+
+         /* - Set the next hop address to be the address of the router
+            from which the datagram came or the next hop address
+            specified by a next hop RTE. */
+         IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
+         IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
+         rinfo->ifindex = ifp->ifindex;
+
+         /* - Initialize the timeout for the route.  If the
+            garbage-collection timer is running for this route, stop it. */
+         ripng_timeout_update (rinfo);
+
+         /* - Set the route change flag. */
+         rinfo->flags |= RIPNG_RTF_CHANGED;
+
+         /* - Signal the output process to trigger an update (see section
+            2.5). */
+         ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+
+         /* Finally, route goes into the kernel. */
+         rinfo->type = ZEBRA_ROUTE_RIPNG;
+         rinfo->sub_type = RIPNG_ROUTE_RTE;
+
+         ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex);
+         rinfo->flags |= RIPNG_RTF_FIB;
+
+         /* Aggregate check. */
+         ripng_aggregate_increment (rp, rinfo);
+       }
+    }
+  else
+    {
+      rinfo = rp->info;
+         
+      /* If there is an existing route, compare the next hop address
+        to the address of the router from which the datagram came.
+        If this datagram is from the same router as the existing
+        route, reinitialize the timeout.  */
+      same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) 
+             && (rinfo->ifindex == ifp->ifindex));
+
+      if (same)
+       ripng_timeout_update (rinfo);
+
+      /* Next, compare the metrics.  If the datagram is from the same
+        router as the existing route, and the new metric is different
+        than the old one; or, if the new metric is lower than the old
+        one; do the following actions: */
+      if ((same && rinfo->metric != rte->metric) ||
+         rte->metric < rinfo->metric)
+       {
+         /* - Adopt the route from the datagram.  That is, put the
+            new metric in, and adjust the next hop address (if
+            necessary). */
+         oldmetric = rinfo->metric;
+         rinfo->metric = rte->metric;
+         rinfo->tag = ntohs (rte->tag);
+
+         if (! IN6_ARE_ADDR_EQUAL (&rinfo->nexthop, nexthop))
+           {
+             ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
+             ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex);
+             rinfo->flags |= RIPNG_RTF_FIB;
+
+             IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
+           }
+         IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
+         rinfo->ifindex = ifp->ifindex;
+
+         /* - Set the route change flag and signal the output process
+            to trigger an update. */
+         rinfo->flags |= RIPNG_RTF_CHANGED;
+         ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
+
+         /* - If the new metric is infinity, start the deletion
+            process (described above); */
+         if (rinfo->metric == RIPNG_METRIC_INFINITY)
+           {
+             /* If the new metric is infinity, the deletion process
+                begins for the route, which is no longer used for
+                routing packets.  Note that the deletion process is
+                started only when the metric is first set to
+                infinity.  If the metric was already infinity, then a
+                new deletion process is not started. */
+             if (oldmetric != RIPNG_METRIC_INFINITY)
+               {
+                 /* - The garbage-collection timer is set for 120 seconds. */
+                 RIPNG_TIMER_ON (rinfo->t_garbage_collect, 
+                                 ripng_garbage_collect, ripng->garbage_time);
+                 RIPNG_TIMER_OFF (rinfo->t_timeout);
+
+                 /* - The metric for the route is set to 16
+                    (infinity).  This causes the route to be removed
+                    from service.*/
+                 /* - The route change flag is to indicate that this
+                    entry has been changed. */
+                 /* - The output process is signalled to trigger a
+                     response. */
+                 ;  /* Above processes are already done previously. */
+               }
+           }
+         else
+           {
+             /* otherwise, re-initialize the timeout. */
+             ripng_timeout_update (rinfo);
+
+             /* Should a new route to this network be established
+                while the garbage-collection timer is running, the
+                new route will replace the one that is about to be
+                deleted.  In this case the garbage-collection timer
+                must be cleared. */
+             RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+           }
+       }
+      /* Unlock tempolary lock of the route. */
+      route_unlock_node (rp);
+    }
+}
+
+/* Add redistributed route to RIPng table. */
+void
+ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, 
+                       unsigned int ifindex)
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+
+  /* Redistribute route  */
+  if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
+    return;
+  if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
+    return;
+
+  rp = route_node_get (ripng->table, (struct prefix *) p);
+  rinfo = rp->info;
+
+  if (rinfo)
+    {
+      RIPNG_TIMER_OFF (rinfo->t_timeout);
+      RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+      route_unlock_node (rp);
+    }
+  else
+    {
+      rinfo = ripng_info_new ();
+      ripng_aggregate_increment (rp, rinfo);
+    }
+
+  rinfo->type = type;
+  rinfo->sub_type = sub_type;
+  rinfo->ifindex = ifindex;
+  rinfo->metric = 1;
+  rinfo->flags |= RIPNG_RTF_FIB;
+
+  rinfo->rp = rp;
+  rp->info = rinfo;
+}
+
+/* Delete redistributed route to RIPng table. */
+void
+ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, 
+                          unsigned int ifindex)
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+
+  if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
+    return;
+  if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
+    return;
+
+  rp = route_node_lookup (ripng->table, (struct prefix *) p);
+
+  if (rp)
+    {
+      rinfo = rp->info;
+
+      if (rinfo != NULL
+         && rinfo->type == type 
+         && rinfo->sub_type == sub_type 
+         && rinfo->ifindex == ifindex)
+       {
+         rp->info = NULL;
+
+         RIPNG_TIMER_OFF (rinfo->t_timeout);
+         RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+         
+         ripng_info_free (rinfo);
+
+         route_unlock_node (rp);
+       }
+
+      /* For unlock route_node_lookup (). */
+      route_unlock_node (rp);
+    }
+}
+
+/* Withdraw redistributed route. */
+void
+ripng_redistribute_withdraw (int type)
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+
+  for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      {
+       if (rinfo->type == type)
+         {
+           rp->info = NULL;
+
+           RIPNG_TIMER_OFF (rinfo->t_timeout);
+           RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
+
+           ripng_info_free (rinfo);
+
+           route_unlock_node (rp);
+         }
+      }
+}
+
+/* RIP routing information. */
+void
+ripng_response_process (struct ripng_packet *packet, int size, 
+                       struct sockaddr_in6 *from, struct interface *ifp,
+                       int hoplimit)
+{
+  caddr_t lim;
+  struct rte *rte;
+  struct ripng_nexthop nexthop;
+
+  /* RFC2080 2.4.2  Response Messages:
+   The Response must be ignored if it is not from the RIPng port.  */
+  if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
+    {
+      zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
+                ntohs (from->sin6_port), inet6_ntop (&from->sin6_addr));
+      return;
+    }
+
+  /* The datagram's IPv6 source address should be checked to see
+   whether the datagram is from a valid neighbor; the source of the
+   datagram must be a link-local address.  */
+  if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
+   {
+      zlog_warn ("RIPng packet comes from non link local address %s",
+                inet6_ntop (&from->sin6_addr));
+      return;
+    }
+
+  /* It is also worth checking to see whether the response is from one
+   of the router's own addresses.  Interfaces on broadcast networks
+   may receive copies of their own multicasts immediately.  If a
+   router processes its own output as new input, confusion is likely,
+   and such datagrams must be ignored. */
+  if (ripng_lladdr_check (ifp, &from->sin6_addr))
+    {
+      zlog_warn ("RIPng packet comes from my own link local address %s",
+                inet6_ntop (&from->sin6_addr));
+      return;
+    }
+
+  /* As an additional check, periodic advertisements must have their
+   hop counts set to 255, and inbound, multicast packets sent from the
+   RIPng port (i.e. periodic advertisement or triggered update
+   packets) must be examined to ensure that the hop count is 255. */
+  if (hoplimit >= 0 && hoplimit != 255)
+    {
+      zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
+                hoplimit, inet6_ntop (&from->sin6_addr));
+      return;
+    }
+
+  /* Reset nexthop. */
+  memset (&nexthop, 0, sizeof (struct ripng_nexthop));
+  nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
+
+  /* Set RTE pointer. */
+  rte = packet->rte;
+
+  for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++) 
+    {
+      /* First of all, we have to check this RTE is next hop RTE or
+         not.  Next hop RTE is completely different with normal RTE so
+         we need special treatment. */
+      if (rte->metric == RIPNG_METRIC_NEXTHOP)
+       {
+         ripng_nexthop_rte (rte, from, &nexthop);
+         continue;
+       }
+
+      /* RTE information validation. */
+
+      /* - is the destination prefix valid (e.g., not a multicast
+         prefix and not a link-local address) A link-local address
+         should never be present in an RTE. */
+      if (IN6_IS_ADDR_MULTICAST (&rte->addr))
+       {
+         zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
+                    inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
+         continue;
+       }
+      if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
+       {
+         zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
+                    inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
+         continue;
+       }
+      if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
+       {
+         zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
+                    inet6_ntop (&rte->addr), rte->prefixlen, rte->metric);
+         continue;
+       }
+
+      /* - is the prefix length valid (i.e., between 0 and 128,
+         inclusive) */
+      if (rte->prefixlen > 128)
+       {
+         zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
+                    inet6_ntop (&rte->addr), rte->prefixlen,
+                    inet6_ntop (&from->sin6_addr), ifp->name);
+         continue;
+       }
+
+      /* - is the metric valid (i.e., between 1 and 16, inclusive) */
+      if (! (rte->metric >= 1 && rte->metric <= 16))
+       {
+         zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
+                    inet6_ntop (&from->sin6_addr), ifp->name);
+         continue;
+       }
+
+      /* Metric calculation. */
+      rte->metric += ifp->metric;
+      if (rte->metric > RIPNG_METRIC_INFINITY)
+       rte->metric = RIPNG_METRIC_INFINITY;
+
+      /* Routing table updates. */
+      ripng_route_process (rte, from, &nexthop, ifp);
+    }
+}
+
+/* Response to request message. */
+void
+ripng_request_process (struct ripng_packet *packet,int size, 
+                      struct sockaddr_in6 *from, struct interface *ifp)
+{
+  caddr_t lim;
+  struct rte *rte;
+  struct prefix_ipv6 p;
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_interface *ri;
+
+  /* Check RIPng process is enabled on this interface. */
+  ri = ifp->info;
+  if (! ri->running)
+    return;
+
+  /* When passive interface is specified, suppress responses */
+  if (ri->passive)
+    return;
+
+  lim = ((caddr_t) packet) + size;
+  rte = packet->rte;
+
+  /* The Request is processed entry by entry.  If there are no
+     entries, no response is given. */
+  if (lim == (caddr_t) rte)
+    return;
+
+  /* There is one special case.  If there is exactly one entry in the
+     request, and it has a destination prefix of zero, a prefix length
+     of zero, and a metric of infinity (i.e., 16), then this is a
+     request to send the entire routing table.  In that case, a call
+     is made to the output process to send the routing table to the
+     requesting address/port. */
+  if (lim == ((caddr_t) (rte + 1)) &&
+      IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
+      rte->prefixlen == 0 &&
+      rte->metric == RIPNG_METRIC_INFINITY)
+    {  
+      /* All route with split horizon */
+      ripng_output_process (ifp, from, ripng_all_route, ripng_split_horizon);
+    }
+  else
+    {
+      /* Except for this special case, processing is quite simple.
+        Examine the list of RTEs in the Request one by one.  For each
+        entry, look up the destination in the router's routing
+        database and, if there is a route, put that route's metric in
+        the metric field of the RTE.  If there is no explicit route
+        to the specified destination, put infinity in the metric
+        field.  Once all the entries have been filled in, change the
+        command from Request to Response and send the datagram back
+        to the requestor. */
+      memset (&p, 0, sizeof (struct prefix_ipv6));
+      p.family = AF_INET6;
+
+      for (; ((caddr_t) rte) < lim; rte++)
+       {
+         p.prefix = rte->addr;
+         p.prefixlen = rte->prefixlen;
+         apply_mask_ipv6 (&p);
+         
+         rp = route_node_lookup (ripng->table, (struct prefix *) &p);
+
+         if (rp)
+           {
+             rinfo = rp->info;
+             rte->metric = rinfo->metric;
+             route_unlock_node (rp);
+           }
+         else
+           rte->metric = RIPNG_METRIC_INFINITY;
+       }
+      packet->command = RIPNG_RESPONSE;
+
+      ripng_send_packet ((caddr_t) packet, size, from, ifp);
+    }
+}
+
+/* First entry point of reading RIPng packet. */
+int
+ripng_read (struct thread *thread)
+{
+  int len;
+  int sock;
+  struct sockaddr_in6 from;
+  struct ripng_packet *packet;
+  unsigned int ifindex;
+  struct interface *ifp;
+  int hoplimit = -1;
+
+  /* Check ripng is active and alive. */
+  assert (ripng != NULL);
+  assert (ripng->sock >= 0);
+
+  /* Fetch thread data and set read pointer to empty for event
+     managing.  `sock' sould be same as ripng->sock. */
+  sock = THREAD_FD (thread);
+  ripng->t_read = NULL;
+
+  /* Add myself to the next event. */
+  ripng_event (RIPNG_READ, sock);
+
+  /* Read RIPng packet. */
+  len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), 
+                          STREAM_SIZE (ripng->ibuf), &from, &ifindex,
+                          &hoplimit);
+  if (len < 0) 
+    {
+      zlog_warn ("RIPng recvfrom failed: %s.", strerror (errno));
+      return len;
+    }
+
+  /* Check RTE boundary.  RTE size (Packet length - RIPng header size
+     (4)) must be multiple size of one RTE size (20). */
+  if (((len - 4) % 20) != 0)
+    {
+      zlog_warn ("RIPng invalid packet size %d from %s", len,
+                inet6_ntop (&from.sin6_addr));
+      return 0;
+    }
+
+  packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
+  ifp = if_lookup_by_index (ifindex);
+
+  /* RIPng packet received. */
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng packet received from %s port %d on %s",
+              inet6_ntop (&from.sin6_addr), ntohs (from.sin6_port), 
+              ifp ? ifp->name : "unknown");
+
+  /* Logging before packet checking. */
+  if (IS_RIPNG_DEBUG_RECV)
+    ripng_packet_dump (packet, len, "RECV");
+
+  /* Packet comes from unknown interface. */
+  if (ifp == NULL)
+    {
+      zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
+      return 0;
+    }
+
+  /* Packet version mismatch checking. */
+  if (packet->version != ripng->version) 
+    {
+      zlog_warn ("RIPng packet version %d doesn't fit to my version %d", 
+                packet->version, ripng->version);
+      return 0;
+    }
+
+  /* Process RIPng packet. */
+  switch (packet->command)
+    {
+    case RIPNG_REQUEST:
+      ripng_request_process (packet, len, &from, ifp);
+      break;
+    case RIPNG_RESPONSE:
+      ripng_response_process (packet, len, &from, ifp, hoplimit);
+      break;
+    default:
+      zlog_warn ("Invalid RIPng command %d", packet->command);
+      break;
+    }
+  return 0;
+}
+
+/* Walk down the RIPng routing table then clear changed flag. */
+void
+ripng_clear_changed_flag ()
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+
+  for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      if (rinfo->flags & RIPNG_RTF_CHANGED)
+       rinfo->flags &= ~RIPNG_RTF_CHANGED;
+}
+
+/* Regular update of RIPng route.  Send all routing formation to RIPng
+   enabled interface. */
+int
+ripng_update (struct thread *t)
+{
+  listnode node;
+  struct interface *ifp;
+  struct ripng_interface *ri;
+
+  /* Clear update timer thread. */
+  ripng->t_update = NULL;
+
+  /* Logging update event. */
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng update timer expired!");
+
+  /* Supply routes to each interface. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      if (if_is_loopback (ifp) || ! if_is_up (ifp))
+       continue;
+
+      if (! ri->running)
+       continue;
+
+      /* When passive interface is specified, suppress announce to the
+         interface. */
+      if (ri->passive)
+       continue;
+
+#if RIPNG_ADVANCED
+      if (ri->ri_send == RIPNG_SEND_OFF)
+       {
+         if (IS_RIPNG_DEBUG_EVENT)
+           zlog (NULL, LOG_INFO, 
+                 "[Event] RIPng send to if %d is suppressed by config",
+                ifp->ifindex);
+         continue;
+       }
+#endif /* RIPNG_ADVANCED */
+
+      ripng_output_process (ifp, NULL, ripng_all_route, ripng_split_horizon);
+    }
+
+  /* Triggered updates may be suppressed if a regular update is due by
+     the time the triggered update would be sent. */
+  if (ripng->t_triggered_interval)
+    {
+      thread_cancel (ripng->t_triggered_interval);
+      ripng->t_triggered_interval = NULL;
+    }
+  ripng->trigger = 0;
+
+  /* Reset flush event. */
+  ripng_event (RIPNG_UPDATE_EVENT, 0);
+
+  return 0;
+}
+
+/* Triggered update interval timer. */
+int
+ripng_triggered_interval (struct thread *t)
+{
+  ripng->t_triggered_interval = NULL;
+
+  if (ripng->trigger)
+    {
+      ripng->trigger = 0;
+      ripng_triggered_update (t);
+    }
+  return 0;
+}     
+
+/* Execute triggered update. */
+int
+ripng_triggered_update (struct thread *t)
+{
+  listnode node;
+  struct interface *ifp;
+  struct ripng_interface *ri;
+  int interval;
+
+  ripng->t_triggered_update = NULL;
+
+  /* Cancel interval timer. */
+  if (ripng->t_triggered_interval)
+    {
+      thread_cancel (ripng->t_triggered_interval);
+      ripng->t_triggered_interval = NULL;
+    }
+  ripng->trigger = 0;
+
+  /* Logging triggered update. */
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng triggered update!");
+
+  /* Split Horizon processing is done when generating triggered
+     updates as well as normal updates (see section 2.6). */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      if (if_is_loopback (ifp) || ! if_is_up (ifp))
+       continue;
+
+      if (! ri->running)
+       continue;
+
+      /* When passive interface is specified, suppress announce to the
+         interface. */
+      if (ri->passive)
+       continue;
+
+      ripng_output_process (ifp, NULL, ripng_changed_route,
+                           ripng_split_horizon);
+    }
+
+  /* Once all of the triggered updates have been generated, the route
+     change flags should be cleared. */
+  ripng_clear_changed_flag ();
+
+  /* After a triggered update is sent, a timer should be set for a
+     random interval between 1 and 5 seconds.  If other changes that
+     would trigger updates occur before the timer expires, a single
+     update is triggered when the timer expires. */
+  interval = (random () % 5) + 1;
+
+  ripng->t_triggered_interval = 
+    thread_add_timer (master, ripng_triggered_interval, NULL, interval);
+
+  return 0;
+}
+
+/* Write routing table entry to the stream and return next index of
+   the routing table entry in the stream. */
+int
+ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
+                u_int16_t tag, u_char metric)
+{
+  /* RIPng packet header. */
+  if (num == 0)
+    {
+      stream_putc (s, RIPNG_RESPONSE);
+      stream_putc (s, RIPNG_V1);
+      stream_putw (s, 0);
+    }
+
+  /* Write routing table entry. */
+  stream_write (s, (caddr_t) &p->prefix, sizeof (struct in6_addr));
+  stream_putw (s, tag);
+  stream_putc (s, p->prefixlen);
+  stream_putc (s, metric);
+
+  return ++num;
+}
+
+/* Send RESPONSE message to specified destination. */
+void
+ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
+                     int route_type, int split_horizon)
+{
+  int ret;
+  struct stream *s;
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_interface *ri;
+  struct ripng_aggregate *aggregate;
+  struct prefix_ipv6 *p;
+  int num;
+  int mtu;
+  int rtemax;
+  u_char metric;
+  u_char metric_set;
+
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng update routes on interface %s", ifp->name);
+
+  /* Output stream get from ripng structre.  XXX this should be
+     interface structure. */
+  s = ripng->obuf;
+
+  /* Reset stream and RTE counter. */
+  stream_reset (s);
+  num = 0;
+
+  mtu = ifp->mtu;
+  if (mtu < 0)
+    mtu = IFMINMTU;
+
+  rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) -
+           IPV6_HDRLEN - 
+           sizeof (struct udphdr) -
+           sizeof (struct ripng_packet) +
+           sizeof (struct rte)) / sizeof (struct rte);
+
+#ifdef DEBUG
+  zlog_info ("DEBUG RIPng: ifmtu is %d", ifp->mtu);
+  zlog_info ("DEBUG RIPng: rtemax is %d", rtemax);
+#endif /* DEBUG */
+  
+  /* Get RIPng interface. */
+  ri = ifp->info;
+  
+  for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+    {
+      if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
+       {
+         p = (struct prefix_ipv6 *) &rp->p;
+         metric = rinfo->metric;
+
+         /* Changed route only output. */
+         if (route_type == ripng_changed_route &&
+             (! (rinfo->flags & RIPNG_RTF_CHANGED)))
+           continue;
+
+         /* Split horizon. */
+         if (split_horizon == ripng_split_horizon &&
+             rinfo->ifindex == ifp->ifindex)
+           continue;
+       
+         /* Apply output filters.*/
+         if (ri->list[RIPNG_FILTER_OUT])
+           {
+             if (access_list_apply (ri->list[RIPNG_FILTER_OUT], 
+                                    (struct prefix *) p) == FILTER_DENY)
+               {
+                 if (IS_RIPNG_DEBUG_PACKET)
+                   zlog_info ("RIPng %s/%d is filtered by distribute out",
+                              inet6_ntop (&p->prefix), p->prefixlen);
+                 continue;
+               }
+           }
+         if (ri->prefix[RIPNG_FILTER_OUT])
+           {
+             if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], 
+                                    (struct prefix *) p) == PREFIX_DENY)
+               {
+                 if (IS_RIPNG_DEBUG_PACKET)
+                   zlog_info ("RIPng %s/%d is filtered by prefix-list out",
+                              inet6_ntop (&p->prefix), p->prefixlen);
+                 continue;
+               }
+           }
+
+         /* Preparation for route-map. */
+         metric_set = 0;
+
+         /* Route-map */
+         if (ri->routemap[RIPNG_FILTER_OUT])
+           {
+             int ret;
+             struct ripng_info newinfo;
+
+             memset (&newinfo, 0, sizeof (struct ripng_info));
+             newinfo.metric = metric;
+
+             ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], 
+                                    (struct prefix *) p, RMAP_RIPNG, 
+                                    &newinfo);
+
+             if (ret == RMAP_DENYMATCH)
+               {
+                 if (IS_RIPNG_DEBUG_PACKET)
+                   zlog_info ("RIPng %s/%d is filtered by route-map out",
+                              inet6_ntop (&p->prefix), p->prefixlen);
+                 return;
+               }
+
+             metric = newinfo.metric;
+             metric_set = newinfo.metric_set;
+           }
+
+         /* When the interface route-map does not set metric */
+         if (! metric_set)
+           {
+             /* and the redistribute route-map is set. */
+             if (ripng->route_map[rinfo->type].name)
+               {
+                 int ret;
+                 struct ripng_info newinfo;
+
+                 memset (&newinfo, 0, sizeof (struct ripng_info));
+                 newinfo.metric = metric;
+             
+                 ret = route_map_apply (ripng->route_map[rinfo->type].map,
+                                        (struct prefix *) p, RMAP_RIPNG,
+                                        &newinfo);
+
+                 if (ret == RMAP_DENYMATCH)
+                   {
+                     if (IS_RIPNG_DEBUG_PACKET)
+                       zlog_info ("RIPng %s/%d is filtered by route-map",
+                                  inet6_ntop (&p->prefix), p->prefixlen);
+                     continue;
+                   }
+
+                 metric = newinfo.metric;
+                 metric_set = newinfo.metric_set;
+               }
+
+             /* When the redistribute route-map does not set metric. */
+             if (! metric_set)
+               {
+                 /* If the redistribute metric is set. */
+                 if (ripng->route_map[rinfo->type].metric_config
+                     && rinfo->metric != RIPNG_METRIC_INFINITY)
+                   {
+                     metric = ripng->route_map[rinfo->type].metric;
+                   }
+                 else
+                   {
+                     /* If the route is not connected or localy generated
+                        one, use default-metric value */
+                     if (rinfo->type != ZEBRA_ROUTE_RIPNG
+                         && rinfo->type != ZEBRA_ROUTE_CONNECT
+                         && rinfo->metric != RIPNG_METRIC_INFINITY)
+                       metric = ripng->default_metric;
+                   }
+               }
+           }
+
+         /* Write RTE to the stream. */
+         num = ripng_write_rte (num, s, p, rinfo->tag, metric);
+         if (num == rtemax)
+           {
+             ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+                                      to, ifp);
+
+             if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+               ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
+                                  stream_get_endp(s), "SEND");
+             num = 0;
+             stream_reset (s);
+           }
+       }
+      if ((aggregate = rp->aggregate) != NULL && 
+         aggregate->count > 0 && 
+         aggregate->suppress == 0)
+       {
+         p = (struct prefix_ipv6 *) &rp->p;
+         metric = aggregate->metric;
+
+         /* Apply output filters.*/
+         if (ri->list[RIPNG_FILTER_OUT])
+           {
+             if (access_list_apply (ri->list[RIPNG_FILTER_OUT], 
+                                    (struct prefix *) p) == FILTER_DENY)
+               {
+                 if (IS_RIPNG_DEBUG_PACKET)
+                   zlog_info ("RIPng %s/%d is filtered by distribute out",
+                              inet6_ntop (&p->prefix), p->prefixlen);
+                 continue;
+               }
+           }
+         if (ri->prefix[RIPNG_FILTER_OUT])
+           {
+             if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], 
+                                    (struct prefix *) p) == PREFIX_DENY)
+               {
+                 if (IS_RIPNG_DEBUG_PACKET)
+                   zlog_info ("RIPng %s/%d is filtered by prefix-list out",
+                              inet6_ntop (&p->prefix), p->prefixlen);
+                 continue;
+               }
+           }
+
+         /* Route-map */
+         if (ri->routemap[RIPNG_FILTER_OUT])
+           {
+             int ret;
+             struct ripng_info newinfo;
+
+             memset (&newinfo, 0, sizeof (struct ripng_info));
+             newinfo.metric = metric;
+
+             ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], 
+                                    (struct prefix *) p, RMAP_RIPNG, 
+                                    &newinfo);
+
+             if (ret == RMAP_DENYMATCH)
+               {
+                 if (IS_RIPNG_DEBUG_PACKET)
+                   zlog_info ("RIPng %s/%d is filtered by route-map out",
+                              inet6_ntop (&p->prefix), p->prefixlen);
+                 return;
+               }
+
+             metric = newinfo.metric;
+           }
+
+         /* Changed route only output. */
+         if (route_type == ripng_changed_route)
+           continue;
+
+         /* Write RTE to the stream. */
+         num = ripng_write_rte (num, s, p, aggregate->tag, metric);
+         if (num == rtemax)
+           {
+             ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+                                      to, ifp);
+
+             if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+               ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
+                                  stream_get_endp(s), "SEND");
+             num = 0;
+             stream_reset (s);
+           }
+       }
+
+    }
+  
+  /* If unwritten RTE exist, flush it. */
+  if (num != 0)
+    {
+      ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s),
+                              to, ifp);
+
+      if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
+       ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
+                          stream_get_endp (s), "SEND");
+      num = 0;
+      stream_reset (s);
+    }
+}
+
+/* Create new RIPng instance and set it to global variable. */
+int
+ripng_create ()
+{
+  /* ripng should be NULL. */
+  assert (ripng == NULL);
+
+  /* Allocaste RIPng instance. */
+  ripng = XMALLOC (0, sizeof (struct ripng));
+  memset (ripng, 0, sizeof (struct ripng));
+
+  /* Default version and timer values. */
+  ripng->version = RIPNG_V1;
+  ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
+  ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
+  ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
+  ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
+  
+  /* Make buffer.  */
+  ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
+  ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
+
+  /* Initialize RIPng routig table. */
+  ripng->table = route_table_init ();
+  ripng->route = route_table_init ();
+  ripng->aggregate = route_table_init ();
+  /* Make socket. */
+  ripng->sock = ripng_make_socket ();
+  if (ripng->sock < 0)
+    return ripng->sock;
+
+  /* Threads. */
+  ripng_event (RIPNG_READ, ripng->sock);
+  ripng_event (RIPNG_UPDATE_EVENT, 1);
+
+  return 0;
+}
+
+/* Sned RIPng request to the interface. */
+int
+ripng_request (struct interface *ifp)
+{
+  struct rte *rte;
+  struct ripng_packet ripng_packet;
+
+  if (IS_RIPNG_DEBUG_EVENT)
+    zlog_info ("RIPng send request to %s", ifp->name);
+
+  memset (&ripng_packet, 0, sizeof (ripng_packet));
+  ripng_packet.command = RIPNG_REQUEST;
+  ripng_packet.version = RIPNG_V1;
+  rte = ripng_packet.rte;
+  rte->metric = RIPNG_METRIC_INFINITY;
+
+  return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet), 
+                           NULL, ifp);
+}
+
+/* Clean up installed RIPng routes. */
+void
+ripng_terminate ()
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+
+  for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      {
+       if (rinfo->type == ZEBRA_ROUTE_RIPNG &&
+           rinfo->sub_type == RIPNG_ROUTE_RTE)
+         ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
+                                  &rinfo->nexthop, rinfo->ifindex);
+      }
+}
+\f
+int
+ripng_update_jitter (int time)
+{
+  return ((rand () % (time + 1)) - (time / 2));
+}
+
+void
+ripng_event (enum ripng_event event, int sock)
+{
+  int ripng_request_all (struct thread *);
+  int jitter = 0;
+
+  switch (event)
+    {
+    case RIPNG_READ:
+      if (!ripng->t_read)
+       ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
+      break;
+    case RIPNG_UPDATE_EVENT:
+      if (ripng->t_update)
+       {
+         thread_cancel (ripng->t_update);
+         ripng->t_update = NULL;
+       }
+      /* Update timer jitter. */
+      jitter = ripng_update_jitter (ripng->update_time);
+
+      ripng->t_update = 
+       thread_add_timer (master, ripng_update, NULL, 
+                         sock ? 2 : ripng->update_time + jitter);
+      break;
+    case RIPNG_TRIGGERED_UPDATE:
+      if (ripng->t_triggered_interval)
+       ripng->trigger = 1;
+      else if (! ripng->t_triggered_update)
+       ripng->t_triggered_update = 
+         thread_add_event (master, ripng_triggered_update, NULL, 0);
+      break;
+    default:
+      break;
+    }
+}
+\f
+/* Each route type's strings and default preference. */
+struct
+{  
+  int key;
+  char *str;
+  char *str_long;
+  int distance;
+} route_info[] =
+{
+  { ZEBRA_ROUTE_SYSTEM,  "X", "system",    10},
+  { ZEBRA_ROUTE_KERNEL,  "K", "kernel",    20},
+  { ZEBRA_ROUTE_CONNECT, "C", "connected", 30},
+  { ZEBRA_ROUTE_STATIC,  "S", "static",    40},
+  { ZEBRA_ROUTE_RIP,     "R", "rip",       50},
+  { ZEBRA_ROUTE_RIPNG,   "R", "ripng",     50},
+  { ZEBRA_ROUTE_OSPF,    "O", "ospf",      60},
+  { ZEBRA_ROUTE_OSPF6,   "O", "ospf6",     60},
+  { ZEBRA_ROUTE_BGP,     "B", "bgp",       70},
+};
+
+/* For messages. */
+struct message ripng_route_info[] =
+{
+  { RIPNG_ROUTE_RTE,       " "},
+  { RIPNG_ROUTE_STATIC,    "S"},
+  { RIPNG_ROUTE_AGGREGATE, "a"}
+};
+
+/* Print out routes update time. */
+static void
+ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
+{
+  struct timeval timer_now;
+  time_t clock;
+  struct tm *tm;
+#define TIME_BUF 25
+  char timebuf [TIME_BUF];
+  struct thread *thread;
+  
+  gettimeofday (&timer_now, NULL);
+
+  if ((thread = rinfo->t_timeout) != NULL)
+    {
+      clock = thread->u.sands.tv_sec - timer_now.tv_sec;
+      tm = gmtime (&clock);
+      strftime (timebuf, TIME_BUF, "%M:%S", tm);
+      vty_out (vty, "%5s", timebuf);
+    }
+  else if ((thread = rinfo->t_garbage_collect) != NULL)
+    {
+      clock = thread->u.sands.tv_sec - timer_now.tv_sec;
+      tm = gmtime (&clock);
+      strftime (timebuf, TIME_BUF, "%M:%S", tm);
+      vty_out (vty, "%5s", timebuf);
+    }
+}
+
+DEFUN (show_ipv6_ripng,
+       show_ipv6_ripng_cmd,
+       "show ipv6 ripng",
+       SHOW_STR
+       IP_STR
+       "Show RIPng routes\n")
+{
+  struct route_node *rp;
+  struct ripng_info *rinfo;
+  struct ripng_aggregate *aggregate;
+  struct prefix_ipv6 *p;
+  int len;
+
+  /* Header of display. */ 
+  vty_out (vty, "%sCodes: R - RIPng%s%s"
+          "   Network                           "
+          "Next Hop                  If Met Tag Time%s", VTY_NEWLINE,
+          VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+  
+  for (rp = route_top (ripng->table); rp; rp = route_next (rp))
+    {
+      if ((aggregate = rp->aggregate) != NULL)
+       {
+         p = (struct prefix_ipv6 *) &rp->p;
+
+#ifdef DEBUG
+         len = vty_out (vty, "Ra %d/%d %s/%d ",
+                        aggregate->count, aggregate->suppress,
+                        inet6_ntop (&p->prefix), p->prefixlen);
+#else
+         len = vty_out (vty, "Ra %s/%d ", 
+                        inet6_ntop (&p->prefix), p->prefixlen);
+#endif /* DEBUG */
+
+         len = 37 - len;
+         if (len > 0)
+           vty_out (vty, "%*s", len, " ");
+
+         vty_out (vty, "%*s", 26, " ");
+         vty_out (vty, "%4d %3d%s", aggregate->metric,
+                  aggregate->tag,
+                  VTY_NEWLINE);
+       }
+
+      if ((rinfo = rp->info) != NULL)
+       {
+         p = (struct prefix_ipv6 *) &rp->p;
+
+#ifdef DEBUG
+         len = vty_out (vty, "%s%s 0/%d %s/%d ",
+                        route_info[rinfo->type].str,
+                        rinfo->suppress ? "s" : " ",
+                        rinfo->suppress,
+                        inet6_ntop (&p->prefix), p->prefixlen);
+#else
+         len = vty_out (vty, "%s%s %s/%d ",
+                        route_info[rinfo->type].str,
+                        rinfo->suppress ? "s" : " ",
+                        inet6_ntop (&p->prefix), p->prefixlen);
+#endif /* DEBUG */
+         len = 37 - len;
+         if (len > 0)
+           vty_out (vty, "%*s", len, " ");
+
+         len = vty_out (vty, "%s", inet6_ntop (&rinfo->nexthop));
+
+         len = 26 - len;
+         if (len > 0)
+           vty_out (vty, "%*s", len, " ");
+
+         vty_out (vty, "%2d %2d %3d ",
+                  rinfo->ifindex, rinfo->metric, rinfo->tag);
+
+         if (rinfo->sub_type == RIPNG_ROUTE_RTE)
+           ripng_vty_out_uptime (vty, rinfo);
+
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (router_ripng,
+       router_ripng_cmd,
+       "router ripng",
+       "Enable a routing process\n"
+       "Make RIPng instance command\n")
+{
+  int ret;
+
+  vty->node = RIPNG_NODE;
+
+  if (!ripng)
+    {
+      ret = ripng_create ();
+
+      /* Notice to user we couldn't create RIPng. */
+      if (ret < 0)
+       {
+         zlog_warn ("can't create RIPng");
+         return CMD_WARNING;
+       }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ripng_route,
+       ripng_route_cmd,
+       "route IPV6ADDR",
+       "Static route setup\n"
+       "Set static RIPng route announcement\n")
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_node *rp;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask_ipv6 (&p);
+
+  rp = route_node_get (ripng->route, (struct prefix *) &p);
+  if (rp->info)
+    {
+      vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
+      route_unlock_node (rp);
+      return CMD_WARNING;
+    }
+  rp->info = (void *)1;
+
+  ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_route,
+       no_ripng_route_cmd,
+       "no route IPV6ADDR",
+       NO_STR
+       "Static route setup\n"
+       "Delete static RIPng route announcement\n")
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_node *rp;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask_ipv6 (&p);
+
+  rp = route_node_lookup (ripng->route, (struct prefix *) &p);
+  if (! rp)
+    {
+      vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+  route_unlock_node (rp);
+
+  rp->info = NULL;
+  route_unlock_node (rp);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ripng_aggregate_address,
+       ripng_aggregate_address_cmd,
+       "aggregate-address X:X::X:X/M",
+       "Set aggregate RIPng route announcement\n"
+       "Aggregate network\n")
+{
+  int ret;
+  struct prefix p;
+  struct route_node *node;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check aggregate alredy exist or not. */
+  node = route_node_get (ripng->aggregate, &p);
+  if (node->info)
+    {
+      vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
+      route_unlock_node (node);
+      return CMD_WARNING;
+    }
+  node->info = (void *)1;
+
+  ripng_aggregate_add (&p);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_aggregate_address,
+       no_ripng_aggregate_address_cmd,
+       "no aggregate-address X:X::X:X/M",
+       NO_STR
+       "Delete aggregate RIPng route announcement\n"
+       "Aggregate network")
+{
+  int ret;
+  struct prefix p;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rn = route_node_lookup (ripng->aggregate, &p);
+  if (! rn)
+    {
+      vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  route_unlock_node (rn);
+  rn->info = NULL;
+  route_unlock_node (rn);
+
+  ripng_aggregate_delete (&p);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ripng_default_metric,
+       ripng_default_metric_cmd,
+       "default-metric <1-16>",
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+{
+  if (ripng)
+    {
+      ripng->default_metric = atoi (argv[0]);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_default_metric,
+       no_ripng_default_metric_cmd,
+       "no default-metric",
+       NO_STR
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+{
+  if (ripng)
+    {
+      ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ripng_default_metric,
+       no_ripng_default_metric_val_cmd,
+       "no default-metric <1-16>",
+       NO_STR
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+#if 0
+/* RIPng update timer setup. */
+DEFUN (ripng_update_timer,
+       ripng_update_timer_cmd,
+       "update-timer SECOND",
+       "Set RIPng update timer in seconds\n"
+       "Seconds\n")
+{
+  unsigned long update;
+  char *endptr = NULL;
+
+  update = strtoul (argv[0], &endptr, 10);
+  if (update == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "update timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ripng->update_time = update;
+
+  ripng_event (RIPNG_UPDATE_EVENT, 0);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_update_timer,
+       no_ripng_update_timer_cmd,
+       "no update-timer SECOND",
+       NO_STR
+       "Unset RIPng update timer in seconds\n"
+       "Seconds\n")
+{
+  ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
+  ripng_event (RIPNG_UPDATE_EVENT, 0);
+  return CMD_SUCCESS;
+}
+
+/* RIPng timeout timer setup. */
+DEFUN (ripng_timeout_timer,
+       ripng_timeout_timer_cmd,
+       "timeout-timer SECOND",
+       "Set RIPng timeout timer in seconds\n"
+       "Seconds\n")
+{
+  unsigned long timeout;
+  char *endptr = NULL;
+
+  timeout = strtoul (argv[0], &endptr, 10);
+  if (timeout == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ripng->timeout_time = timeout;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_timeout_timer,
+       no_ripng_timeout_timer_cmd,
+       "no timeout-timer SECOND",
+       NO_STR
+       "Unset RIPng timeout timer in seconds\n"
+       "Seconds\n")
+{
+  ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
+  return CMD_SUCCESS;
+}
+
+/* RIPng garbage timer setup. */
+DEFUN (ripng_garbage_timer,
+       ripng_garbage_timer_cmd,
+       "garbage-timer SECOND",
+       "Set RIPng garbage timer in seconds\n"
+       "Seconds\n")
+{
+  unsigned long garbage;
+  char *endptr = NULL;
+
+  garbage = strtoul (argv[0], &endptr, 10);
+  if (garbage == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ripng->garbage_time = garbage;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_garbage_timer,
+       no_ripng_garbage_timer_cmd,
+       "no garbage-timer SECOND",
+       NO_STR
+       "Unset RIPng garbage timer in seconds\n"
+       "Seconds\n")
+{
+  ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
+  return CMD_SUCCESS;
+}
+#endif /* 0 */
+
+DEFUN (ripng_timers,
+       ripng_timers_cmd,
+       "timers basic <0-65535> <0-65535> <0-65535>",
+       "RIPng timers setup\n"
+       "Basic timer\n"
+       "Routing table update timer value in second. Default is 30.\n"
+       "Routing information timeout timer. Default is 180.\n"
+       "Garbage collection timer. Default is 120.\n")
+{
+  unsigned long update;
+  unsigned long timeout;
+  unsigned long garbage;
+  char *endptr = NULL;
+
+  update = strtoul (argv[0], &endptr, 10);
+  if (update == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "update timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  timeout = strtoul (argv[1], &endptr, 10);
+  if (timeout == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  garbage = strtoul (argv[2], &endptr, 10);
+  if (garbage == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Set each timer value. */
+  ripng->update_time = update;
+  ripng->timeout_time = timeout;
+  ripng->garbage_time = garbage;
+
+  /* Reset update timer thread. */
+  ripng_event (RIPNG_UPDATE_EVENT, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ripng_timers,
+       no_ripng_timers_cmd,
+       "no timers basic",
+       NO_STR
+       "RIPng timers setup\n"
+       "Basic timer\n")
+{
+  /* Set each timer value to the default. */
+  ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
+  ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
+  ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
+
+  /* Reset update timer thread. */
+  ripng_event (RIPNG_UPDATE_EVENT, 0);
+
+  return CMD_SUCCESS;
+}
+
+
+DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
+       "show ipv6 protocols",
+       SHOW_STR
+       IP_STR
+       "Routing protocol information")
+{
+  if (! ripng)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
+  
+  vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
+          ripng->update_time, 0,
+          VTY_NEWLINE);
+
+  vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
+          ripng->timeout_time,
+          ripng->garbage_time,
+          VTY_NEWLINE);
+
+  vty_out (vty, "Outgoing update filter list for all interfaces is not set");
+  vty_out (vty, "Incoming update filter list for all interfaces is not set");
+
+  return CMD_SUCCESS;
+}
+
+/* Please be carefull to use this command. */
+DEFUN (default_information_originate,
+       default_information_originate_cmd,
+       "default-information originate",
+       "Default route information\n"
+       "Distribute default route\n")
+{
+  struct prefix_ipv6 p;
+
+  ripng->default_information = 1;
+
+  str2prefix_ipv6 ("::/0", &p);
+  ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_default_information_originate,
+       no_default_information_originate_cmd,
+       "no default-information originate",
+       NO_STR
+       "Default route information\n"
+       "Distribute default route\n")
+{
+  struct prefix_ipv6 p;
+
+  ripng->default_information = 0;
+
+  str2prefix_ipv6 ("::/0", &p);
+  ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+
+  return CMD_SUCCESS;
+}
+
+/* RIPng configuration write function. */
+int
+ripng_config_write (struct vty *vty)
+{
+  int ripng_network_write (struct vty *);
+  void ripng_redistribute_write (struct vty *);
+  int write = 0;
+  struct route_node *rp;
+
+  if (ripng)
+    {
+
+      /* RIPng router. */
+      vty_out (vty, "router ripng%s", VTY_NEWLINE);
+
+      if (ripng->default_information)
+       vty_out (vty, " default-information originate%s", VTY_NEWLINE);
+
+      ripng_network_write (vty);
+
+      /* RIPng default metric configuration */
+      if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
+        vty_out (vty, " default-metric %d%s",
+                ripng->default_metric, VTY_NEWLINE);
+
+      ripng_redistribute_write (vty);
+      
+      /* RIPng aggregate routes. */
+      for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
+       if (rp->info != NULL)
+         vty_out (vty, " aggregate-address %s/%d%s", 
+                  inet6_ntop (&rp->p.u.prefix6),
+                  rp->p.prefixlen, 
+
+                  VTY_NEWLINE);
+
+      /* RIPng static routes. */
+      for (rp = route_top (ripng->route); rp; rp = route_next (rp))
+       if (rp->info != NULL)
+         vty_out (vty, " route %s/%d%s", inet6_ntop (&rp->p.u.prefix6),
+                  rp->p.prefixlen,
+                  VTY_NEWLINE);
+
+      /* RIPng timers configuration. */
+      if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
+         ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
+         ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
+       {
+         vty_out (vty, " timers basic %ld %ld %ld%s",
+                  ripng->update_time,
+                  ripng->timeout_time,
+                  ripng->garbage_time,
+                  VTY_NEWLINE);
+       }
+#if 0
+      if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
+       vty_out (vty, " update-timer %d%s", ripng->update_time,
+                VTY_NEWLINE);
+      if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
+       vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
+                VTY_NEWLINE);
+      if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
+       vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
+                VTY_NEWLINE);
+#endif /* 0 */
+
+      write += config_write_distribute (vty);
+
+      write += config_write_if_rmap (vty);
+
+      write++;
+    }
+  return write;
+}
+
+/* RIPng node structure. */
+struct cmd_node cmd_ripng_node =
+{
+  RIPNG_NODE,
+  "%s(config-router)# ",
+  1,
+};
+
+void
+ripng_distribute_update (struct distribute *dist)
+{
+  struct interface *ifp;
+  struct ripng_interface *ri;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  if (! dist->ifname)
+    return;
+
+  ifp = if_lookup_by_name (dist->ifname);
+  if (ifp == NULL)
+    return;
+
+  ri = ifp->info;
+
+  if (dist->list[DISTRIBUTE_IN])
+    {
+      alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
+      if (alist)
+       ri->list[RIPNG_FILTER_IN] = alist;
+      else
+       ri->list[RIPNG_FILTER_IN] = NULL;
+    }
+  else
+    ri->list[RIPNG_FILTER_IN] = NULL;
+
+  if (dist->list[DISTRIBUTE_OUT])
+    {
+      alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
+      if (alist)
+       ri->list[RIPNG_FILTER_OUT] = alist;
+      else
+       ri->list[RIPNG_FILTER_OUT] = NULL;
+    }
+  else
+    ri->list[RIPNG_FILTER_OUT] = NULL;
+
+  if (dist->prefix[DISTRIBUTE_IN])
+    {
+      plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
+      if (plist)
+       ri->prefix[RIPNG_FILTER_IN] = plist;
+      else
+       ri->prefix[RIPNG_FILTER_IN] = NULL;
+    }
+  else
+    ri->prefix[RIPNG_FILTER_IN] = NULL;
+
+  if (dist->prefix[DISTRIBUTE_OUT])
+    {
+      plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
+      if (plist)
+       ri->prefix[RIPNG_FILTER_OUT] = plist;
+      else
+       ri->prefix[RIPNG_FILTER_OUT] = NULL;
+    }
+  else
+    ri->prefix[RIPNG_FILTER_OUT] = NULL;
+}
+void
+ripng_distribute_update_interface (struct interface *ifp)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifp->name);
+  if (dist)
+    ripng_distribute_update (dist);
+}
+
+/* Update all interface's distribute list. */
+void
+ripng_distribute_update_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ripng_distribute_update_interface (ifp);
+    }
+}
+
+void
+ripng_if_rmap_update (struct if_rmap *if_rmap)
+{
+  struct interface *ifp;
+  struct ripng_interface *ri;
+  struct route_map *rmap;
+
+  ifp = if_lookup_by_name (if_rmap->ifname);
+  if (ifp == NULL)
+    return;
+
+  ri = ifp->info;
+
+  if (if_rmap->routemap[IF_RMAP_IN])
+    {
+      rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
+      if (rmap)
+       ri->routemap[IF_RMAP_IN] = rmap;
+      else
+       ri->routemap[IF_RMAP_IN] = NULL;
+    }
+  else
+    ri->routemap[RIPNG_FILTER_IN] = NULL;
+
+  if (if_rmap->routemap[IF_RMAP_OUT])
+    {
+      rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
+      if (rmap)
+       ri->routemap[IF_RMAP_OUT] = rmap;
+      else
+       ri->routemap[IF_RMAP_OUT] = NULL;
+    }
+  else
+    ri->routemap[RIPNG_FILTER_OUT] = NULL;
+}
+
+void
+ripng_if_rmap_update_interface (struct interface *ifp)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_lookup (ifp->name);
+  if (if_rmap)
+    ripng_if_rmap_update (if_rmap);
+}
+
+void
+ripng_routemap_update_redistribute (void)
+{
+  int i;
+
+  if (ripng)
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
+       {
+         if (ripng->route_map[i].name)
+           ripng->route_map[i].map = 
+             route_map_lookup_by_name (ripng->route_map[i].name);
+       }
+    }
+}
+
+void
+ripng_routemap_update ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ripng_if_rmap_update_interface (ifp);
+    }
+
+  ripng_routemap_update_redistribute ();
+}
+
+/* Initialize ripng structure and set commands. */
+void
+ripng_init ()
+{
+  /* Randomize. */
+  srand (time (NULL));
+
+  /* Install RIPNG_NODE. */
+  install_node (&cmd_ripng_node, ripng_config_write);
+
+  /* Install ripng commands. */
+  install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
+
+  install_element (CONFIG_NODE, &router_ripng_cmd);
+
+  install_default (RIPNG_NODE);
+  install_element (RIPNG_NODE, &ripng_route_cmd);
+  install_element (RIPNG_NODE, &no_ripng_route_cmd);
+  install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
+  install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
+
+  install_element (RIPNG_NODE, &ripng_default_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
+  install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
+
+  install_element (RIPNG_NODE, &ripng_timers_cmd);
+  install_element (RIPNG_NODE, &no_ripng_timers_cmd);
+#if 0
+  install_element (RIPNG_NODE, &ripng_update_timer_cmd);
+  install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
+  install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
+  install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
+  install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
+  install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
+#endif /* 0 */
+
+  install_element (RIPNG_NODE, &default_information_originate_cmd);
+  install_element (RIPNG_NODE, &no_default_information_originate_cmd);
+
+  ripng_if_init ();
+  ripng_debug_init ();
+
+  /* Access list install. */
+  access_list_init ();
+  access_list_add_hook (ripng_distribute_update_all);
+  access_list_delete_hook (ripng_distribute_update_all);
+
+  /* Prefix list initialize.*/
+  prefix_list_init ();
+  prefix_list_add_hook (ripng_distribute_update_all);
+  prefix_list_delete_hook (ripng_distribute_update_all);
+
+  /* Distribute list install. */
+  distribute_list_init (RIPNG_NODE);
+  distribute_list_add_hook (ripng_distribute_update);
+  distribute_list_delete_hook (ripng_distribute_update);
+
+  /* Route-map for interface. */
+  ripng_route_map_init ();
+  route_map_add_hook (ripng_routemap_update);
+  route_map_delete_hook (ripng_routemap_update);
+
+  if_rmap_init (RIPNG_NODE);
+  if_rmap_hook_add (ripng_if_rmap_update);
+  if_rmap_hook_delete (ripng_if_rmap_update);
+}
diff --git a/ripngd/ripngd.conf.sample b/ripngd/ripngd.conf.sample
new file mode 100644 (file)
index 0000000..ad673e5
--- /dev/null
@@ -0,0 +1,22 @@
+! -*- rip -*-
+!
+! RIPngd sample configuration file
+!
+! $Id: ripngd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
+!
+hostname ripngd
+password zebra
+!
+! debug ripng events
+! debug ripng packet
+!
+!
+router ripng
+! network sit1
+! route 3ffe:506::0/32
+! distribute-list local-only out sit1
+!
+!ipv6 access-list local-only permit 3ffe:506::0/32
+!ipv6 access-list local-only deny any
+!
+log stdout
diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h
new file mode 100644 (file)
index 0000000..2509bdd
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * RIPng related value and structure.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_RIPNG_RIPNGD_H
+#define _ZEBRA_RIPNG_RIPNGD_H
+
+/* RIPng version and port number. */
+#define RIPNG_V1                         1
+#define RIPNG_PORT_DEFAULT             521
+#define RIPNG_VTY_PORT                2603
+#define RIPNG_VTYSH_PATH              "/tmp/.ripngd"
+#define RIPNG_MAX_PACKET_SIZE         1500
+#define RIPNG_PRIORITY_DEFAULT           0
+
+/* RIPng commands. */
+#define RIPNG_REQUEST                    1
+#define RIPNG_RESPONSE                   2
+
+/* RIPng metric and multicast group address. */
+#define RIPNG_METRIC_INFINITY           16
+#define RIPNG_METRIC_NEXTHOP          0xff
+#define RIPNG_GROUP              "ff02::9"
+
+/* RIPng timers. */
+#define RIPNG_UPDATE_TIMER_DEFAULT      30
+#define RIPNG_TIMEOUT_TIMER_DEFAULT    180
+#define RIPNG_GARBAGE_TIMER_DEFAULT    120
+
+/* Default config file name. */
+#define RIPNG_DEFAULT_CONFIG "ripngd.conf"
+
+/* RIPng route types. */
+#define RIPNG_ROUTE_RTE                  0
+#define RIPNG_ROUTE_STATIC               1
+#define RIPNG_ROUTE_AGGREGATE            2
+
+/* Interface send/receive configuration. */
+#define RIPNG_SEND_UNSPEC                0
+#define RIPNG_SEND_OFF                   1
+#define RIPNG_RECEIVE_UNSPEC             0
+#define RIPNG_RECEIVE_OFF                1
+
+/* Split horizon definitions. */
+#define RIPNG_SPLIT_HORIZON_UNSPEC       0
+#define RIPNG_SPLIT_HORIZON_NONE         1
+#define RIPNG_SPLIT_HORIZON              2
+#define RIPNG_SPLIT_HORIZON_POISONED     3
+
+/* RIP default route's accept/announce methods. */
+#define RIPNG_DEFAULT_ADVERTISE_UNSPEC   0
+#define RIPNG_DEFAULT_ADVERTISE_NONE     1
+#define RIPNG_DEFAULT_ADVERTISE          2
+
+#define RIPNG_DEFAULT_ACCEPT_UNSPEC      0
+#define RIPNG_DEFAULT_ACCEPT_NONE        1
+#define RIPNG_DEFAULT_ACCEPT             2
+
+/* Default value for "default-metric" command. */
+#define RIPNG_DEFAULT_METRIC_DEFAULT     1
+
+/* For max RTE calculation. */
+#ifndef IPV6_HDRLEN
+#define IPV6_HDRLEN 40
+#endif /* IPV6_HDRLEN */
+
+#ifndef IFMINMTU
+#define IFMINMTU    576
+#endif /* IFMINMTU */
+
+/* RIPng structure. */
+struct ripng 
+{
+  /* RIPng socket. */
+  int sock;
+
+  /* RIPng Parameters.*/
+  u_char command;
+  u_char version;
+  unsigned long update_time;
+  unsigned long timeout_time;
+  unsigned long garbage_time;
+  int max_mtu;
+  int default_metric;
+  int default_information;
+
+  /* Input/output buffer of RIPng. */
+  struct stream *ibuf;
+  struct stream *obuf;
+
+  /* RIPng routing information base. */
+  struct route_table *table;
+
+  /* RIPng only static route information. */
+  struct route_table *route;
+
+  /* RIPng aggregate route information. */
+  struct route_table *aggregate;
+
+  /* RIPng threads. */
+  struct thread *t_read;
+  struct thread *t_write;
+  struct thread *t_update;
+  struct thread *t_garbage;
+  struct thread *t_zebra;
+
+  /* Triggered update hack. */
+  int trigger;
+  struct thread *t_triggered_update;
+  struct thread *t_triggered_interval;
+
+  /* For redistribute route map. */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+    int metric_config;
+    u_int32_t metric;
+  } route_map[ZEBRA_ROUTE_MAX];
+};
+
+/* Routing table entry. */
+struct rte
+{
+  struct in6_addr addr;
+  u_short tag;
+  u_char prefixlen;
+  u_char metric;
+};
+
+/* RIPNG send packet. */
+struct ripng_packet
+{
+  u_char command;
+  u_char version;
+  u_int16_t zero; 
+  struct rte rte[1];
+};
+
+/* Each route's information. */
+struct ripng_info
+{
+  /* This route's type.  Static, ripng or aggregate. */
+  u_char type;
+
+  /* Sub type for static route. */
+  u_char sub_type;
+
+  /* RIPng specific information */
+  struct in6_addr nexthop;     
+  struct in6_addr from;
+
+  /* Which interface does this route come from. */
+  unsigned int ifindex;                
+
+  /* Metric of this route.  */
+  u_char metric;               
+
+  /* Tag field of RIPng packet.*/
+  u_int16_t tag;               
+
+  /* For aggregation. */
+  unsigned int suppress;
+
+  /* Flags of RIPng route. */
+#define RIPNG_RTF_FIB      1
+#define RIPNG_RTF_CHANGED  2
+  u_char flags;
+
+  /* Garbage collect timer. */
+  struct thread *t_timeout;
+  struct thread *t_garbage_collect;
+
+  /* Route-map features - this variables can be changed. */
+  u_char metric_set;
+
+  struct route_node *rp;
+};
+
+/* RIPng tag structure. */
+struct ripng_tag
+{
+  /* Tag value. */
+  u_int16_t tag;
+
+  /* Port. */
+  u_int16_t port;
+
+  /* Multicast group. */
+  struct in6_addr maddr;
+
+  /* Table number. */
+  int table;
+
+  /* Distance. */
+  int distance;
+
+  /* Split horizon. */
+  u_char split_horizon;
+
+  /* Poison reverse. */
+  u_char poison_reverse;
+};
+
+/* RIPng specific interface configuration. */
+struct ripng_interface
+{
+  /* RIPng is enabled on this interface. */
+  int enable_network;
+  int enable_interface;
+
+  /* RIPng is running on this interface. */
+  int running;
+
+  /* For filter type slot. */
+#define RIPNG_FILTER_IN  0
+#define RIPNG_FILTER_OUT 1
+#define RIPNG_FILTER_MAX 2
+
+  /* Access-list. */
+  struct access_list *list[RIPNG_FILTER_MAX];
+
+  /* Prefix-list. */
+  struct prefix_list *prefix[RIPNG_FILTER_MAX];
+
+  /* Route-map. */
+  struct route_map *routemap[RIPNG_FILTER_MAX];
+
+  /* RIPng tag configuration. */
+  struct ripng_tag *rtag;
+
+  /* Default information originate. */
+  u_char default_originate;
+
+  /* Default information only. */
+  u_char default_only;
+
+  /* Wake up thread. */
+  struct thread *t_wakeup;
+
+  /* Passive interface. */
+  int passive;
+};
+
+/* All RIPng events. */
+enum ripng_event
+{
+  RIPNG_READ,
+  RIPNG_ZEBRA,
+  RIPNG_REQUEST_EVENT,
+  RIPNG_UPDATE_EVENT,
+  RIPNG_TRIGGERED_UPDATE,
+};
+
+/* RIPng timer on/off macro. */
+#define RIPNG_TIMER_ON(T,F,V) \
+do { \
+   if (!(T)) \
+      (T) = thread_add_timer (master, (F), rinfo, (V)); \
+} while (0)
+
+#define RIPNG_TIMER_OFF(T) \
+do { \
+   if (T) \
+     { \
+       thread_cancel(T); \
+       (T) = NULL; \
+     } \
+} while (0)
+
+/* Count prefix size from mask length */
+#define PSIZE(a) (((a) + 7) / (8))
+
+/* Extern variables. */
+extern struct ripng *ripng;
+
+extern struct thread_master *master;
+
+/* Prototypes. */
+void ripng_init ();
+void ripng_if_init ();
+void ripng_terminate ();
+void ripng_zclient_start ();
+void zebra_init ();
+struct ripng_info * ripng_info_new ();
+void ripng_info_free (struct ripng_info *rinfo);
+void ripng_event (enum ripng_event, int);
+int ripng_request (struct interface *ifp);
+void ripng_redistribute_add (int, int, struct prefix_ipv6 *, unsigned int);
+void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, unsigned int);
+void ripng_redistribute_withdraw (int type);
+
+void ripng_distribute_update_interface (struct interface *);
+void ripng_if_rmap_update_interface (struct interface *);
+
+void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex);
+void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex);
+void ripng_route_map_init ();
+
+#endif /* _ZEBRA_RIPNG_RIPNGD_H */
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp
diff --git a/tools/mrlg.cgi b/tools/mrlg.cgi
new file mode 100755 (executable)
index 0000000..ac468ee
--- /dev/null
@@ -0,0 +1,395 @@
+#!/usr/bin/perl
+##
+## Zebra Looking Glass version 1.0
+## 01 FEB 2000
+## Copyright (C) 2000 John W. Fraizer III <john.fraizer@enterzone.net>
+## *All* copyright notices must remain in place to use this code.
+##
+## The latest version of this code is available at:
+## ftp://ftp.enterzone.net/looking-glass/
+##
+##
+## This file is part of GNU Zebra.
+##
+## GNU Zebra is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by the
+## Free Software Foundation; either version 2, or (at your option) any
+## later version.
+##
+## GNU Zebra is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with GNU Zebra; see the file COPYING.  If not, write to the
+## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+## Boston, MA 02111-1307, USA.
+
+require 5.002;
+use POSIX;
+use Net::Telnet ();
+
+
+
+## Set the URL for your site.
+$url="http://www.sample.com/mrlg.cgi";
+
+## Set your router variables in sub set_router and modify the selections in Main to match.
+
+
+############################################################
+#Main
+############################################################
+{
+
+## Set the router default
+@Form{'router'} = "router1";
+
+## Get the form results now so we can override the default router 
+get_form();
+
+print "Content-type: text/html\n\n";
+
+print '
+<html>
+<head>
+<title>Multi-Router Looking Glass for Zebra</title>
+</head>
+<body bgcolor=white>
+       
+<font face=arial size=3 color=blue>
+<h1>Multi-Router Looking Glass for Zebra</h1>
+Copyright 2000 - John Fraizer, EnterZone Inc.
+<br>
+';
+
+print '
+<font color=black>
+';
+print "<form METHOD=\"POST\" action=\"$url\">\n";
+print "<B>Router:</B>  <SELECT Name=\"router\" Size=1>\n";
+print "<OPTION Value=\"$Form{'router'}\">$Form{'router'}\n";
+print '
+<OPTION Value="router1">router1
+<OPTION Value="router2">router2
+<OPTION Value="router3">router3
+<OPTION Value="router4">router4
+</select>
+<br><br>
+<B>Query</B>:
+<br>
+<input type=radio name=query value=1>show ip bgp<br>
+<input type=radio name=query value=2>show ip bgp summary<br>
+<input type=radio name=query value=3>show ip route<br>
+<input type=radio name=query value=4>show interface<br>
+<input type=radio name=query value=5>show ipv6 bgp<br>
+<input type=radio name=query value=6>show ipv6 bgp summary<br>
+<input type=radio name=query value=7>show ipv6 route<br>
+<br>
+<B>Argument:</B> <input type=text name=arg length=20 maxlength=60>
+<input type="submit" value="Execute"></form>   
+';
+
+## Set up the address, pw and ports, etc for the selected router.
+set_router();
+
+## Set up which command is to be executed (and then execute it!)
+set_command();
+
+
+print '
+<br><br>
+</font>
+<font color=blue face=arial size=2>
+Multi-Router Looking Glass for Zebra version 1.0<br>
+Written by: John Fraizer -
+<a href="http://www.ez-hosting.net/">EnterZone, Inc</a><br>
+Source code: <a href="ftp://ftp.enterzone.net/looking-glass/">ftp://ftp.enterzone.net/looking-glass/</a>
+</body>
+</html>
+';
+
+## All done!
+
+exit (0); 
+}
+
+
+############################################################
+sub get_form
+############################################################
+{
+        
+        #read STDIN
+        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
+
+        # Split the name-value pairs
+        @pairs = split(/&/, $buffer);
+  
+        # For each name-value pair:
+        foreach $pair (@pairs)
+                {
+                
+                # Split the pair up into individual variables.
+                local($name, $value) = split(/=/, $pair);
+
+                # Decode the form encoding on the name and value variables.
+                $name =~ tr/+/ /;
+                $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+                $value =~ tr/+/ /;
+                $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+
+                # If they try to include server side includes, erase them, so they
+                # aren't a security risk if the html gets returned.  Another
+                # security hole plugged up.
+                $value =~ s/<!--(.|\n)*-->//g;
+        
+                @Form{$name} = $value ;
+                 
+                }
+        
+}       
+
+############################################################
+sub set_router
+############################################################
+
+## $server is the IP address of the router running zebra
+## $login_pass is the password of the router
+## $bgpd is the port that bgpd will answer on
+## $zebra is the port that zebra will answer on
+## if $zebra is "", it will disable sh ip route and sh int for that router.
+## if $full_tables is set to "1" for a router, full BGP and IP ROUTE table dumps will be allowed via the looking glass.
+## This is a BAD thing to do if you have multiple full views on a router.  That's why the option is there.
+
+{
+if ($Form{'router'} eq 'router1')
+        {
+$server = '10.1.1.1';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "";
+$full_tables=1;
+
+        }
+
+elsif ($Form{'router'} eq 'router2')
+        {
+$server = '10.1.1.2';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "2601";
+        }
+
+elsif ($Form{'router'} eq 'router3')
+        {
+$server = '10.1.1.3';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "2601";
+$full_tables=1;
+        }
+
+elsif ($Form{'router'} eq 'router4')
+        {
+$server = '10.1.1.4';
+$login_pass = 'zebra';
+$bgpd = "2605";
+$zebra = "2601";
+        }
+
+
+}
+
+
+############################################################
+sub set_command
+############################################################
+{
+if ($Form{'query'} eq '1')
+       {
+       sh_ip_bgp('ip');
+       }
+
+elsif ($Form{'query'} eq '2')
+       {
+       sh_ip_bgp_sum('ip');
+       }
+
+if ($Form{'query'} eq '3')
+       {
+       sh_ip_route('ip');
+       }
+
+if ($Form{'query'} eq '4')
+       {
+       sh_int();
+       }
+if ($Form{'query'} eq '5')
+       {
+       sh_ip_bgp('ipv6');
+       }
+if ($Form{'query'} eq '6')
+       {
+       sh_ip_bgp_sum('ipv6');
+       }
+if ($Form{'query'} eq '7')
+       {
+       sh_ip_route('ipv6');
+       }
+}
+############################################################
+sub sh_ip_bgp
+############################################################
+{
+my $protocol = shift(@_);
+$port = $bgpd;
+if ($protocol ne 'ip' && $protocol ne 'ipv6')
+       {
+       print "Invalid protocol: $protocol\n";
+       print "protocol must be 'ip' or 'ipv6'\n\n";
+       return;
+       }
+$command = "show $protocol bgp $Form{'arg'}";
+if ($Form{'arg'} eq '')
+       {
+       if ($full_tables eq '1')
+               {
+               execute_command();
+               }
+       else
+               {
+               print "Sorry.  Displaying the FULL routing table would put too much load on the router!\n\n";
+               }
+       }
+else
+       {
+       execute_command();
+       }
+}
+
+############################################################
+sub sh_ip_bgp_sum
+############################################################
+{
+       my $protocol = shift(@_);
+       $port = $bgpd;
+       if ($protocol ne 'ip' && $protocol ne 'ipv6')
+               {
+               print "Invalid protocol: $protocol\n";
+               print "protocol must be 'ip' or 'ipv6'\n\n";
+               return;
+               }
+       $command = "show $protocol bgp summary";
+       execute_command();
+}
+
+############################################################
+sub sh_ip_route
+############################################################
+{
+
+if ($zebra eq '')
+       {
+       print "Sorry. The <b>show ip route</b> command is disabled for this router."
+       }
+else
+       {
+
+       $port = $zebra;
+       my $protocol = shift(@_);
+       if ($protocol ne 'ip' && $protocol ne 'ipv6')
+               {
+               print "Invalid protocol: $protocol\n";
+               print "protocol must be 'ip' or 'ipv6'\n\n";
+               return;
+               }
+       $command = "show $protocol route $Form{'arg'}";
+       if ($Form{'arg'} eq '')
+               {
+               if ($full_tables eq '1')
+                       {
+                       execute_command();
+                       }
+               else
+                       {
+                       print "Sorry.  Displaying the FULL routing table would put too much load on the router!\n\n";
+                       }
+               }
+       else
+               {
+               execute_command();
+               }
+       }
+}
+
+############################################################
+sub sh_int
+############################################################
+{
+if ($zebra eq '')
+       {
+       print "Sorry. The <b>show interface</b> command is disabled for this router."
+       }
+else
+       {
+       $port = $zebra;
+       $command = "show interface $Form{'arg'}";
+       execute_command();
+       }
+}
+
+
+
+############################################################
+sub execute_command
+############################################################
+## This code is based on:
+##
+## Zebra interactive console
+## Copyright (C) 2000 Vladimir B. Grebenschikov <vova@express.ru>
+##
+
+
+{
+
+print "Executing command = $command";
+
+#  my $port = ($opt_z ? 'zebra' : 0) ||
+#             ($opt_b ? 'bgpd' : 0) ||
+#             ($opt_o ? 'ospfd' : 0) ||
+#           ($opt_r ? 'ripd' : 0) || 'bgpd';
+
+my $cmd = $command;
+
+
+  my $t = new Net::Telnet (Timeout => 10,
+                          Prompt  => '/[\>\#] $/',
+                          Port    => $port);
+
+  $t->open ($server);
+
+  $t->cmd ($login_pass);
+
+  if ($cmd)
+    {
+      docmd ($t, $cmd);
+    }
+
+}
+
+############################################################
+sub docmd
+############################################################
+{
+  my ($t, $cmd) = @_;
+  my @lines = $t->cmd ($cmd);
+  print "<pre>\n";
+  print join ('', grep (!/[\>\#] $/, @lines)), "\n";
+  print "</pre>";
+}
+
+
+
diff --git a/tools/rrcheck.pl b/tools/rrcheck.pl
new file mode 100644 (file)
index 0000000..5e5a983
--- /dev/null
@@ -0,0 +1,135 @@
+#! /bin/perl
+##
+## Read BGPd logfile and lookup RR's whois database.
+##
+##   Copyright (c) 1997 Kunihiro Ishiguro
+##
+use Socket;
+
+## Configuration variables
+$whois_host = "whois.jpix.ad.jp";
+
+#$logfile = "/usr/local/sbin/logfile"
+$logfile = shift || die "Please specify filename";
+
+## mail routine
+{
+    local ($prefix, $origin);
+
+    open (LOG, $logfile) || die "can't open $logfile";
+    
+    $index = '';
+    while ($index) {
+       $index = <LOG>;
+       if ($index =~ /[bgpd]/) {
+           break;
+       }
+    }
+
+    while (<LOG>) {
+       if (/([\d\.\/]+)\s+([\d\.]+)\s+(\d+)\s+(\d+)\s+([\d ]+)\s+[ie\?]/) {
+           $prefix = $1;
+           $nexthop = $2;
+           $med = $3;
+           $dummy = $4;
+           $aspath = $5;
+           ($origin) = ($aspath =~ /([\d]+)$/);
+
+           print "$nexthop [$origin] $prefix $aspath ";
+
+           $ret = &whois_check ($prefix, $origin);
+           if ($ret == 0) {
+               print "Check OK\n";
+           } elsif ($ret == 1){
+               print "AS orgin mismatch\n";
+           } else {
+               print "prefix doesn't exist \n";
+           }
+       }
+    }
+}
+
+sub whois_check
+{
+    local ($prefix, $origin) = @_;
+    local ($rr_prefix, $rr_origin) = ();
+    local (@result);
+
+    $origin = "AS" . $origin;
+
+    @result = &whois ($prefix);
+
+    $prefix_match = 0;
+    foreach (@result) {
+        if (/^route:.*\s([\d\.\/]+)$/) {
+            $rr_prefix = $1;
+        }
+        if (/^origin:.*\s(AS[\d]+)$/) {
+            $rr_origin = $1;
+
+            if ($prefix eq $rr_prefix and $origin eq $rr_origin) {
+                return 0;
+            } elsif ($prefix eq $rr_prefix) {
+               $prefix_match = 1;
+           }
+        }
+    }
+#    alarm_mail ($prefix, $origin, @result);
+    if ($prefix_match) {
+       return 1;
+    } else {
+       return 2;
+    }
+}
+
+## get port of whois
+sub get_whois_port 
+{
+    local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp");
+    return ($port, $proto);
+}
+
+## whois lookup
+sub whois 
+{
+    local ($query) = @_;
+    local ($port, $proto) = &get_whois_port;
+    local (@result);
+
+    if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) {
+       $address = pack ("C4",split(/\./,$host));
+    } else {
+       $address = (gethostbyname ($whois_host))[4];
+    }
+
+    socket (SOCKET, PF_INET, SOCK_STREAM, $proto);
+
+    if (connect (SOCKET, sockaddr_in ($port, $address))) {
+        local ($oldhandle) = select (SOCKET);
+        $| = 1;
+        select($oldhandle);
+
+        print SOCKET "$query\r\n";
+
+        @result = <SOCKET>;
+        return @result;
+    }
+}
+
+##
+sub alarm_mail 
+{
+    local ($prefix, $origin, @result) = @_;
+
+    open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer";
+    
+    print MAIL "From: root\@rr1.jpix.ad.jp\n";
+    print MAIL "Subject: RR $origin $prefix\n";
+    print MAIL "MIME-Version: 1.0\n";
+    print MAIL "Content-Type: text/plain; charset=us-ascii \n\n";
+    print MAIL "RR Lookup Error Report\n";
+    print MAIL "======================\n";
+    print MAIL "Announced route : $prefix from $origin\n\n";
+    print MAIL "@result";
+    close MAIL;
+}
diff --git a/tools/rrlookup.pl b/tools/rrlookup.pl
new file mode 100644 (file)
index 0000000..2c14e73
--- /dev/null
@@ -0,0 +1,123 @@
+#! /usr/local/bin/perl
+##
+## Read BGPd logfile and lookup RR's whois database.
+##
+##   Copyright (c) 1997 Kunihiro Ishiguro
+##
+use Socket;
+
+## Configuration variables
+$whois_host = "whois.jpix.ad.jp";
+
+#$mail_address = "toshio\@iri.co.jp";
+$mail_address = "kunihiro\@zebra.org";
+$mailer = "/usr/sbin/sendmail -oi";
+
+#$logfile = "/usr/local/sbin/logfile"
+$logfile = "logfile";
+$lookuplog = "lookuplog";
+
+## mail routine
+{
+    local ($prefix, $origin);
+
+    open (LOG, $logfile) || die "can't open $logfile";
+    open (LOOKUP, ">$lookuplog") || die "can't open $lookuplog";
+    
+    for (;;) {
+    while (<LOG>) {
+        if (/Update\S+ ([\d\.\/]+) .* (\d+) [ie\?]/) {
+            $prefix = $1;
+            $origin = $2;
+            $ret = &whois_check ($prefix, $origin);
+            if ($ret) {
+                print LOOKUP "$prefix AS$origin : Check OK\n";
+            } else {
+                print LOOKUP "$prefix AS$origin : Error\n";
+            }
+#        fflush (LOOKUP);
+        }
+    }
+    sleep (3);
+    }
+}
+
+sub whois_check
+{
+    local ($prefix, $origin) = @_;
+    local ($rr_prefix, $rr_origin) = ();
+    local (@result);
+
+    $origin = "AS" . $origin;
+
+#    print "$prefix $origin\n";
+
+    @result = &whois ($prefix);
+
+    foreach (@result) {
+        if (/^route:.*\s([\d\.\/]+)$/) {
+            $rr_prefix = $1;
+        }
+        if (/^origin:.*\s(AS[\d]+)$/) {
+            $rr_origin = $1;
+
+            if ($prefix eq $rr_prefix and $origin eq $rr_origin) {
+                return 1;
+            }
+        }
+    }
+    alarm_mail ($prefix, $origin, @result);
+    return 0;
+}
+
+## get port of whois
+sub get_whois_port 
+{
+    local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp");
+    return ($port, $proto);
+}
+
+## whois lookup
+sub whois 
+{
+    local ($query) = @_;
+    local ($port, $proto) = &get_whois_port;
+    local (@result);
+
+    if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) {
+       $address = pack ("C4",split(/\./,$host));
+    } else {
+       $address = (gethostbyname ($whois_host))[4];
+    }
+
+    socket (SOCKET, PF_INET, SOCK_STREAM, $proto);
+
+    if (connect (SOCKET, sockaddr_in ($port, $address))) {
+        local ($oldhandle) = select (SOCKET);
+        $| = 1;
+        select($oldhandle);
+
+        print SOCKET "$query\r\n";
+
+        @result = <SOCKET>;
+        return @result;
+    }
+}
+
+##
+sub alarm_mail 
+{
+    local ($prefix, $origin, @result) = @_;
+
+    open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer";
+    
+    print MAIL "From: root\@rr1.jpix.ad.jp\n";
+    print MAIL "Subject: RR $origin $prefix\n";
+    print MAIL "MIME-Version: 1.0\n";
+    print MAIL "Content-Type: text/plain; charset=us-ascii \n\n";
+    print MAIL "RR Lookup Error Report\n";
+    print MAIL "======================\n";
+    print MAIL "Announced route : $prefix from $origin\n\n";
+    print MAIL "@result";
+    close MAIL;
+}
diff --git a/tools/zc.pl b/tools/zc.pl
new file mode 100755 (executable)
index 0000000..026e8fe
--- /dev/null
@@ -0,0 +1,111 @@
+#! /usr/bin/perl
+##
+## Zebra interactive console
+## Copyright (C) 2000 Vladimir B. Grebenschikov <vova@express.ru>
+##
+## This file is part of GNU Zebra.
+##
+## GNU Zebra is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by the
+## Free Software Foundation; either version 2, or (at your option) any
+## later version.
+##
+## GNU Zebra is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with GNU Zebra; see the file COPYING.  If not, write to the
+## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+## Boston, MA 02111-1307, USA.
+
+use Net::Telnet ();
+use Getopt::Std;
+
+#use strict;
+
+my $host = `hostname -s`; $host =~ s/\s//g;
+my $port = 'zebra';
+my $server = 'localhost';
+
+# Check arguments
+&getopts ('l:e:czborh');
+
+&usage () if $opt_h;
+
+# main 
+{
+  my $login_pass = $opt_l || $ENV{ZEBRA_PASSWORD} || 'zebra';
+  my $enable_pass = $opt_e || $ENV{ZEBRA_ENABLE} || '';
+
+  my $port = ($opt_z ? 'zebra' : 0) ||
+            ($opt_b ? 'bgpd' : 0) ||
+             ($opt_o ? 'ospfd' : 0) ||
+            ($opt_r ? 'ripd' : 0) || 'zebra';
+
+  my $cmd = join (' ', @ARGV);
+
+  my $t = new Net::Telnet (Timeout => 10,
+                          Prompt  => '/[\>\#] $/',
+                          Port    => $port);
+
+  $t->open ($server);
+
+  $t->cmd ($login_pass);
+  if ($enable_pass) {
+      $t->cmd (String => 'en',
+              Prompt => '/Password: /');
+      $t->cmd ($enable_pass);
+  }
+  $t->cmd ('conf t') if "$opt_c";
+
+  if ($cmd)
+    {
+      docmd ($t, $cmd);
+      exit (0); 
+    }
+
+  my $prompt = sprintf ("%s%s# ", $host,
+                       ($port eq 'zebra') ? '' : "/$port");
+
+  print "\nZEBRA interactive console ($port)\n\n" if -t STDIN;
+
+  while (1)
+    {
+      $| = 1;
+      print $prompt if -t STDIN;
+      chomp ($cmd = <>);
+      if (!defined ($cmd))
+        {
+         print "\n" if -t STDIN;
+         exit(0);
+        }
+      exit (0) if ($cmd eq 'q' || $cmd eq 'quit');
+      docmd ($t, $cmd) if $cmd !~ /^\s*$/;
+    }
+
+  exit(0);
+}
+
+sub docmd
+{
+  my ($t, $cmd) = @_;
+  my @lines = $t->cmd ($cmd);
+  print join ('', grep (!/[\>\#] $/, @lines)), "\n";
+}
+
+sub usage
+{
+  print "USAGE: $0 [-l LOGIN_PASSWORD] [-e ENABLE_PASSWORD] [-z|-b|-o|-r|-h] [<cmd>]\n",
+        "\t-l - specify login password\n",
+        "\t-e - specify enable password\n",
+        "\t-c - execute command in configure mode\n",
+        "\t-z - connect to zebra daemon\n",
+        "\t-b - connect to bgpd  daemon\n",
+        "\t-o - connect to ospfd daemon\n",
+        "\t-r - connect to ripd  daemon\n",
+        "\t-h - help\n";
+  exit (1);
+}
diff --git a/tools/zebra.el b/tools/zebra.el
new file mode 100644 (file)
index 0000000..01ff09f
--- /dev/null
@@ -0,0 +1,108 @@
+;; -*- lisp -*-
+;;; zebra-mode.el -- major mode for editing zebra configuration file.
+
+;; Copyright (C) 1998 Kunihiro Ishiguro
+
+;; Author:     1998 Kunihiro Ishiguro
+;;                  SeonMeyong HEO
+;; Maintainer: kunihiro@zebra.org
+;;             seirios@Matrix.IRI.Co.JP
+;; Created:    Jan 28 1998
+;; Version:    Alpha 0.2
+;; Keywords:   zebra bgpd ripd ripngd languages
+
+;; You can get the latest version of zebra from
+;;
+;;    http://www.zebra.org/
+;;
+;; Install this Emacs Lisp code
+;;
+;; Compile zebra.el
+;;   % $(EMACS) -batch -f batch-byte-compile zebra.el
+;; Install zebra.el,zebra.elc to Emacs-load-path
+;;   % cp zebra.el zebra.elc $(emacs-load-path)
+;; Add .emacs or (site-load.el | site-start.el)
+;;   (auto-load 'zebra-mode "zebra" nil t)
+;;   (auto-load 'bgp-mode "zebra" nil t)
+;;   (auto-load 'rip-mode "zebra" nil t)
+;;
+
+;;; Code:
+
+;; Set keywords
+
+(defvar zebra-font-lock-keywords
+  (list
+   '("#.*$" . font-lock-comment-face)
+   '("!.*$" . font-lock-comment-face)
+   '("no\\|interface" . font-lock-type-face)
+   '("ip6\\|ip\\|route\\|address" . font-lock-function-name-face)
+   '("ipforward\\|ipv6forward" . font-lock-keyword-face)
+   '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face))
+  "Default value to highlight in zebra mode.")
+
+(defvar bgp-font-lock-keywords
+  (list
+   '("#.*$" . font-lock-comment-face)
+   '("!.*$" . font-lock-comment-face)
+   '("no\\|router" . font-lock-type-face)
+   '("bgp\\|router-id\\|neighbor\\|network" . font-lock-function-name-face)
+   '("ebgp\\|multihop\\|next\\|zebra\\|remote-as" . font-lock-keyword-face)
+   '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face))
+  "Default value to highlight in bgp mode.")
+
+(defvar rip-font-lock-keywords
+  (list
+   '("#.*$" . font-lock-comment-face)
+   '("!.*$" . font-lock-comment-face)
+   '("no\\|router\\|interface\\|ipv6\\|ip6\\|ip" . font-lock-type-face)
+   '("ripng\\|rip\\|recive\\|advertize\\|accept" . font-lock-function-name-face)
+   '("version\\|network" . font-lock-function-name-face)
+   '("default\\|none\\|zebra" . font-lock-keyword-face)
+   '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face))
+  "Default value to highlight in bgp mode.")
+
+;; set font-lock-mode
+
+(defun zebra-font-lock ()
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(zebra-font-lock-keywords nil t)))
+
+(defun bgp-font-lock ()
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(bgp-font-lock-keywords nil t)))
+
+(defun rip-font-lock ()
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(rip-font-lock-keywords nil t)))
+
+;; define Major mode
+
+(defun major-mode-define ()
+  (interactive)
+  (progn
+    (setq comment-start "[#!]"
+         comment-end ""
+         comment-start-skip "!+ ")
+    (run-hooks 'zebra-mode-hook)
+    (cond
+     ((string< "20" emacs-version)
+      (font-lock-mode)))))
+
+(defun zebra-mode ()
+  (progn
+    (setq mode-name "zebra")
+    (zebra-font-lock))
+  (major-mode-define))
+
+(defun bgp-mode ()
+  (progn
+    (setq mode-name "bgp") 
+    (bgp-font-lock))
+  (major-mode-define))
+
+(defun rip-mode ()
+  (progn
+    (setq mode-name "rip")
+    (rip-font-lock))
+  (major-mode-define))
diff --git a/update-autotools b/update-autotools
new file mode 100755 (executable)
index 0000000..1eaeb39
--- /dev/null
@@ -0,0 +1,14 @@
+#! /bin/sh
+#
+# When local system does not have the latest autoconf/automake
+#        -- Kunihiro Ishiguro <kunihiro@zebra.org>
+#
+rm -f config.cache
+rm -f Makefile.in
+rm -f aclocal.m4
+rm -f config.h.in
+rm -f configure
+aclocal
+autoheader
+autoconf
+automake --foreign
diff --git a/vtysh/.cvsignore b/vtysh/.cvsignore
new file mode 100644 (file)
index 0000000..a71b4c5
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+*.o
+vtysh
+tags
+TAGS
+.deps
diff --git a/vtysh/ChangeLog b/vtysh/ChangeLog
new file mode 100644 (file)
index 0000000..5818d5c
--- /dev/null
@@ -0,0 +1,173 @@
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.93 released.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-02-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (vtysh_client_config): Do not set bufsz to 120.
+       Suggested by: Matthew Grant <grantma@anathoth.gen.nz>.
+
+2001-02-15  Hideto Yamakawa <yamakawa@dml.com>
+
+       * vtysh.c (vtysh_client_execute): Call fflush after fprintf.
+
+       * vtysh_config.c (vtysh_config_dump): Use VTYSH_PAGER if defined.
+
+2001-02-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (vtysh_execute_func): Add fflush before pclose.
+
+2001-02-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c: VTY shell pager name.  When environment variable
+       VTYSH_PAGER is defined, use it as VTY shell pager.
+
+2001-02-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (vtysh_execute_func): Add pager argument for test of
+       pager invocation.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * extract.pl: Add -DHAVE_CONFIG_H option to cpp.
+
+2001-02-08  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * vtysh.c (vtysh_client_config): Use sysconf to determine output
+       buffer size.
+       (vtysh_write_memory): Set umask 0077.
+       (vtysh_connect): Check permission to the socket.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.91 is released.
+
+2001-01-31  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * vtysh.c (new_completion): Fix problem of appending space when
+       completion is executed.
+
+2001-01-23  Akihiro Mizutani <mizutani@dml.com>
+
+       * vtysh.c (vtysh_write_terminal): "write terminal" to all node.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (vtysh_execute): Fix unconditional lock by other VTY.
+       Suggested by Hideto Yamakawa <yamakawa@dml.com>.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+2001-01-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.h (ZEBRA_PATH): Fix new vtysh path.  Reported by "Matt
+       Ranney" <mjr@ranney.com>
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (DEFUNSH): Add "address-family vpnv4" DEFUNSH.
+
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (execute_command): Add two arguemnt support for
+       executing child process.
+       (vtysh_telnet_port): New command "telnet WORD PORT" is added.
+
+2000-10-23  Akihiro Mizutani <mizutani@dml.com>
+
+       * vtysh.c (vtysh_write_memory): Display [OK] when configuration is
+       saved without problem.
+
+2000-10-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (vtysh_config_from_file): "key chain" command with -b
+       flag problem is fixed.
+
+2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh_user.c: Change to use linklist.c.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (noinst_HEADERS): Add vtysh_user.h.
+
+       * zebra-0.89 is released.
+
+2000-09-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh_main.c: Declare thread master.
+
+2000-08-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh_main.c (main): Add missing --help procudure.  Reported by
+       Patrick Rother <krd@roka.net>.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (DEFUNSH): "interface IFNAME" works.
+
+2000-08-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh_user.c: Change name from vtysh_pam.c.
+
+       * vtysh.conf.sample: New file for vtysh configuration.
+
+2000-08-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh_pam.c (vtysh_pam): New file for PAM.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (vtysh_LDADD): Remove -lreadline and -lncurses.
+
+       * vtysh.c (vtysh_connect): Use AF_UNIX instead of AF_LOCAL for
+       backward compatibility.
+
+2000-07-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * extract.pl: Change regexp to match DEFUN and ALIAS at the same
+       time.
+
+2000-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (signal_init): Ignore SIGPIPE signal.
+
+2000-07-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * extract.pl: ALIAS command can be extracted by extract.pl.
+
+2000-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * extract.pl: Fix scalar and array semantics.
+
+       * vtysh.c (vtysh_telnet): Add "telnet" client command.
+
+2000-07-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c (main): Add -e flag for passing command from arugment.
+       (vtysh_ping): Add "ping" command for test of command execution.
+       (init_node): Add "traceroute" command.
+       (vtysh_start_shell): Add "start-shell", "start-shell bash",
+       "start-shell zsh".
+       (sigint): Add check for execute_flag for avoid duplicate prompt.
+
+2000-06-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vtysh.c: New file for vty shell.
+       * vtysh.h: Likewise.
+       * extract.pl: Likewise.
+       * vtysh_cmd.c: Generate by extract.pl.
diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am
new file mode 100644 (file)
index 0000000..4327379
--- /dev/null
@@ -0,0 +1,22 @@
+## Process this file with Automake to create Makefile.in
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+
+LIBS = @LIBS@ @CURSES@ @LIBPAM@
+
+bin_PROGRAMS = vtysh
+
+vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_cmd.c vtysh_user.c vtysh_config.c
+noinst_HEADERS = vtysh.h vtysh_user.h
+vtysh_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = vtysh.conf.sample
+
+EXTRA_DIST = extract.pl vtysh.conf.sample
+
+rebuild4:
+       ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >vtysh_cmd.c
+
+rebuild:
+       ./extract.pl ../zebra/*.c ../ripd/*.c ../ripngd/*.c ../ospfd/*.c ../ospf6d/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >vtysh_cmd.c
diff --git a/vtysh/Makefile.in b/vtysh/Makefile.in
new file mode 100644 (file)
index 0000000..71eb6b4
--- /dev/null
@@ -0,0 +1,453 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+
+LIBS = @LIBS@ @CURSES@ @LIBPAM@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+
+bin_PROGRAMS = vtysh
+
+vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_cmd.c vtysh_user.c vtysh_config.c
+noinst_HEADERS = vtysh.h vtysh_user.h
+vtysh_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = vtysh.conf.sample
+
+EXTRA_DIST = extract.pl vtysh.conf.sample
+subdir = vtysh
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+bin_PROGRAMS = vtysh$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+
+am_vtysh_OBJECTS = vtysh_main.$(OBJEXT) vtysh.$(OBJEXT) \
+       vtysh_cmd.$(OBJEXT) vtysh_user.$(OBJEXT) vtysh_config.$(OBJEXT)
+vtysh_OBJECTS = $(am_vtysh_OBJECTS)
+vtysh_DEPENDENCIES = ../lib/libzebra.a
+vtysh_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/vtysh.Po ./$(DEPDIR)/vtysh_cmd.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/vtysh_config.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/vtysh_main.Po ./$(DEPDIR)/vtysh_user.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(vtysh_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(vtysh_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  vtysh/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
+         rm -f $(DESTDIR)$(bindir)/$$f; \
+       done
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+vtysh$(EXEEXT): $(vtysh_OBJECTS) $(vtysh_DEPENDENCIES) 
+       @rm -f vtysh$(EXEEXT)
+       $(LINK) $(vtysh_LDFLAGS) $(vtysh_OBJECTS) $(vtysh_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_cmd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_user.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+uninstall-info-am:
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f="`echo $$p | sed -e 's|^.*/||'`"; \
+         echo " $(sysconfDATA_INSTALL) $$d$$p $(DESTDIR)$(sysconfdir)/$$f"; \
+         $(sysconfDATA_INSTALL) $$d$$p $(DESTDIR)$(sysconfdir)/$$f; \
+       done
+
+uninstall-sysconfDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         f="`echo $$p | sed -e 's|^.*/||'`"; \
+         echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \
+         rm -f $(DESTDIR)$(sysconfdir)/$$f; \
+       done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+           dir="/$$dir"; \
+           $(mkinstalldirs) "$(distdir)$$dir"; \
+         else \
+           dir=''; \
+         fi; \
+         if test -d $$d/$$file; then \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+       $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+       distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+       clean-generic ctags distclean distclean-compile \
+       distclean-depend distclean-generic distclean-tags distdir dvi \
+       dvi-am info info-am install install-am install-binPROGRAMS \
+       install-data install-data-am install-exec install-exec-am \
+       install-info install-info-am install-man install-strip \
+       install-sysconfDATA installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am uninstall-binPROGRAMS \
+       uninstall-info-am uninstall-sysconfDATA
+
+
+rebuild4:
+       ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >vtysh_cmd.c
+
+rebuild:
+       ./extract.pl ../zebra/*.c ../ripd/*.c ../ripngd/*.c ../ospfd/*.c ../ospf6d/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >vtysh_cmd.c
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/vtysh/extract.pl b/vtysh/extract.pl
new file mode 100755 (executable)
index 0000000..4a45901
--- /dev/null
@@ -0,0 +1,171 @@
+#! /usr/bin/perl
+##
+## Virtual terminal interface shell command extractor.
+## Copyright (C) 2000 Kunihiro Ishiguro
+## 
+## This file is part of GNU Zebra.
+## 
+## GNU Zebra is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by the
+## Free Software Foundation; either version 2, or (at your option) any
+## later version.
+## 
+## GNU Zebra is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with GNU Zebra; see the file COPYING.  If not, write to the Free
+## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+## 02111-1307, USA.  
+##
+
+print <<EOF;
+#include <zebra.h>
+#include "command.h"
+#include "vtysh.h"
+
+EOF
+
+$ignore{'"interface IFNAME"'} = "ignore";
+$ignore{'"ip vrf NAME"'} = "ignore";
+$ignore{'"router rip"'} = "ignore";
+$ignore{'"router ripng"'} = "ignore";
+$ignore{'"router ospf"'} = "ignore";
+$ignore{'"router ospf <0-65535>"'} = "ignore";
+$ignore{'"router ospf6"'} = "ignore";
+$ignore{'"router bgp <1-65535>"'} = "ignore";
+$ignore{'"router bgp <1-65535> view WORD"'} = "ignore";
+$ignore{'"address-family ipv4"'} = "ignore";
+$ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore";
+$ignore{'"address-family ipv6"'} = "ignore";
+$ignore{'"address-family ipv6 unicast"'} = "ignore";
+$ignore{'"address-family vpnv4"'} = "ignore";
+$ignore{'"address-family vpnv4 unicast"'} = "ignore";
+$ignore{'"address-family ipv4 vrf NAME"'} = "ignore";
+$ignore{'"exit-address-family"'} = "ignore";
+$ignore{'"key chain WORD"'} = "ignore";
+$ignore{'"key <0-2147483647>"'} = "ignore";
+$ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore";
+$ignore{'"show route-map"'} = "ignore";
+
+foreach (@ARGV) {
+    $file = $_;
+
+    open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -I. -I.. -I../lib $file |");
+    local $/; undef $/;
+    $line = <FH>;
+    close (FH);
+
+    @defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg);
+    @install = ($line =~ /install_element \(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg);
+
+    # $protocol is VTYSH_PROTO format for redirection of user input
+    if ($file =~ /lib/) {
+       if ($file =~ /keychain.c/) {
+           $protocol = "VTYSH_RIPD";
+       }
+       if ($file =~ /routemap.c/) {
+           $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD";
+       }
+       if ($file =~ /filter.c/) {
+           $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD";
+       }
+       if ($file =~ /plist.c/) {
+           $protocol = "VTYSH_RIPD|VTYSH_BGPD";
+       }
+    } else {
+       ($protocol) = ($file =~ /\/([a-z0-9]+)/);
+       $protocol = "VTYSH_" . uc $protocol;
+    }
+
+    # DEFUN process
+    foreach (@defun) {
+       my (@defun_array);
+       @defun_array = split (/,/);
+       $defun_array[0] = '';
+
+
+       # Actual input command string.
+       $str = "$defun_array[2]";
+       $str =~ s/^\s+//g;
+       $str =~ s/\s+$//g;
+
+       # Get VTY command structure.  This is needed for searching
+       # install_element() command.
+       $cmd = "$defun_array[1]";
+       $cmd =~ s/^\s+//g;
+       $cmd =~ s/\s+$//g;
+
+       # Append _vtysh to structure then build DEFUN again
+       $defun_array[1] = $cmd . "_vtysh";
+       $defun_body = join (", ", @defun_array);
+
+       # $cmd -> $str hash for lookup
+       $cmd2str{$cmd} = $str;
+       $cmd2defun{$cmd} = $defun_body;
+       $cmd2proto{$cmd} = $protocol;
+    }
+
+    # install_element() process
+    foreach (@install) {
+       my (@element_array);
+       @element_array = split (/,/);
+
+       # Install node
+       $enode = $element_array[0];
+       $enode =~ s/^\s+//g;
+       $enode =~ s/\s+$//g;
+       ($enode) = ($enode =~ /([0-9A-Z_]+)$/);
+
+       # VTY command structure.
+       ($ecmd) = ($element_array[1] =~ /&([^\)]+)/);
+       $ecmd =~ s/^\s+//g;
+       $ecmd =~ s/\s+$//g;
+
+       # Register $ecmd
+       if (defined ($cmd2str{$ecmd})
+           && ! defined ($ignore{$cmd2str{$ecmd}})) {
+           my ($key);
+           $key = $enode . "," . $cmd2str{$ecmd};
+           $ocmd{$key} = $ecmd;
+           $odefun{$key} = $cmd2defun{$ecmd};
+           push (@{$oproto{$key}}, $cmd2proto{$ecmd});
+       }
+    }
+}
+
+# Check finaly alive $cmd;
+foreach (keys %odefun) {
+    my ($node, $str) = (split (/,/));
+    my ($cmd) = $ocmd{$_};
+    $live{$cmd} = $_;
+}
+
+# Output DEFSH
+foreach (keys %live) {
+    my ($proto);
+    my ($key);
+    $key = $live{$_};
+    $proto = join ("|", @{$oproto{$key}});
+    printf "DEFSH ($proto$odefun{$key})\n\n";
+}
+
+# Output install_element
+print <<EOF;
+void
+vtysh_init_cmd ()
+{
+EOF
+
+foreach (keys %odefun) {
+    my ($node, $str) = (split (/,/));
+    $cmd = $ocmd{$_};
+    $cmd =~ s/_cmd/_cmd_vtysh/;
+    printf "  install_element ($node, &$cmd);\n";
+}
+
+print <<EOF
+}
+EOF
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
new file mode 100644 (file)
index 0000000..965eb39
--- /dev/null
@@ -0,0 +1,1803 @@
+/* Virtual terminal interface shell.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include <sys/un.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "command.h"
+#include "memory.h"
+#include "vtysh/vtysh.h"
+
+/* Struct VTY. */
+struct vty *vty;
+
+/* VTY shell pager name. */
+char *vtysh_pager_name = NULL;
+
+/* VTY shell client structure. */
+struct vtysh_client
+{
+  int fd;
+} vtysh_client[VTYSH_INDEX_MAX];
+\f
+/* When '^Z' is received from vty, move down to the enable mode. */
+int
+vtysh_end ()
+{
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      /* Nothing to do. */
+      break;
+    default:
+      vty->node = ENABLE_NODE;
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        vtysh_end_all,
+        vtysh_end_all_cmd,
+        "end",
+        "End current mode and down to previous mode\n")
+{
+  return vtysh_end (vty);
+}
+
+DEFUNSH (VTYSH_ALL,
+        vtysh_log_stdout,
+        vtysh_log_stdout_cmd,
+        "log stdout",
+        "Logging control\n"
+        "Logging goes to stdout\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        no_vtysh_log_stdout,
+        no_vtysh_log_stdout_cmd,
+        "no log stdout",
+        NO_STR
+        "Logging control\n"
+        "Logging goes to stdout\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+       vtysh_log_file,
+       vtysh_log_file_cmd,
+       "log file FILENAME",
+       "Logging control\n"
+       "Logging to file\n"
+       "Logging filename\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+       no_vtysh_log_file,
+       no_vtysh_log_file_cmd,
+       "no log file [FILENAME]",
+       NO_STR
+       "Logging control\n"
+       "Cancel logging to file\n"
+       "Logging file name\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        vtysh_log_syslog,
+        vtysh_log_syslog_cmd,
+        "log syslog",
+        "Logging control\n"
+        "Logging goes to syslog\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        no_vtysh_log_syslog,
+        no_vtysh_log_syslog_cmd,
+        "no log syslog",
+        NO_STR
+        "Logging control\n"
+        "Cancel logging to syslog\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        vtysh_log_trap,
+        vtysh_log_trap_cmd,
+        "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
+        "Logging control\n"
+        "Limit logging to specifed level\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        no_vtysh_log_trap,
+        no_vtysh_log_trap_cmd,
+        "no log trap",
+        NO_STR
+        "Logging control\n"
+        "Permit all logging information\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        vtysh_log_record_priority,
+        vtysh_log_record_priority_cmd,
+        "log record-priority",
+        "Logging control\n"
+        "Log the priority of the message within the message\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        no_vtysh_log_record_priority,
+        no_vtysh_log_record_priority_cmd,
+        "no log record-priority",
+        NO_STR
+        "Logging control\n"
+        "Do not log the priority of the message within the message\n")
+{
+  return CMD_SUCCESS;
+}
+
+void
+vclient_close (struct vtysh_client *vclient)
+{
+  if (vclient->fd > 0)
+    close (vclient->fd);
+  vclient->fd = -1;
+}
+
+
+/* Following filled with debug code to trace a problematic condition
+   under load - it SHOULD handle it.
+*/
+#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): "
+int
+vtysh_client_config (struct vtysh_client *vclient, char *line)
+{
+  int ret;
+  char *buf;
+  size_t bufsz;
+  char *pbuf;
+  size_t left;
+  char *eoln;
+  int nbytes;
+  int i;
+  int readln;
+
+  if (vclient->fd < 0)
+    return CMD_SUCCESS;
+
+  ret = write (vclient->fd, line, strlen (line) + 1);
+  if (ret <= 0)
+    {
+      vclient_close (vclient);
+      return CMD_SUCCESS;
+    }
+       
+  /* Allow enough room for buffer to read more than a few pages from socket
+   */
+  bufsz = 5 * sysconf(_SC_PAGESIZE) + 1;
+  buf = XMALLOC(MTYPE_TMP, bufsz);
+  memset(buf, 0, bufsz);
+  pbuf = buf;
+
+  while (1)
+    {
+      if (pbuf >= ((buf + bufsz) -1))
+       {
+         fprintf (stderr, ERR_WHERE_STRING \
+                  "warning - pbuf beyond buffer end.\n");
+         return CMD_WARNING;
+       }
+
+      readln = (buf + bufsz) - pbuf - 1;
+      nbytes = read (vclient->fd, pbuf, readln);
+
+      if (nbytes <= 0)
+       {
+
+         if (errno == EINTR)
+           continue;
+
+         fprintf(stderr, ERR_WHERE_STRING "(%u)", errno);
+         perror("");
+
+         if (errno == EAGAIN || errno == EIO)
+           continue;
+
+         vclient_close (vclient);
+         XFREE(MTYPE_TMP, buf);
+         return CMD_SUCCESS;
+       }
+
+      pbuf[nbytes] = '\0';
+
+      if (nbytes >= 4)
+       {
+         i = nbytes - 4;
+         if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0')
+           {
+             ret = pbuf[i + 3];
+             break;
+           }
+       }
+      pbuf += nbytes;
+
+      /* See if a line exists in buffer, if so parse and consume it, and
+        reset read position */
+      if ((eoln = strrchr(buf, '\n')) == NULL)
+       continue;
+
+      if (eoln >= ((buf + bufsz) - 1))
+       {
+         fprintf (stderr, ERR_WHERE_STRING \
+                  "warning - eoln beyond buffer end.\n");
+       }
+      vtysh_config_parse(buf);
+
+      eoln++;
+      left = (size_t)(buf + bufsz - eoln);
+      memmove(buf, eoln, left);
+      buf[bufsz-1] = '\0';
+      pbuf = buf + strlen(buf);
+    }
+
+  /* parse anything left in the buffer */
+  vtysh_config_parse (buf);
+
+  XFREE(MTYPE_TMP, buf);
+  return ret;
+}
+
+int
+vtysh_client_execute (struct vtysh_client *vclient, char *line, FILE *fp)
+{
+  int ret;
+  char buf[1001];
+  int nbytes;
+  int i;
+
+  if (vclient->fd < 0)
+    return CMD_SUCCESS;
+
+  ret = write (vclient->fd, line, strlen (line) + 1);
+  if (ret <= 0)
+    {
+      vclient_close (vclient);
+      return CMD_SUCCESS;
+    }
+       
+  while (1)
+    {
+      nbytes = read (vclient->fd, buf, sizeof(buf)-1);
+
+      if (nbytes <= 0 && errno != EINTR)
+       {
+         vclient_close (vclient);
+         return CMD_SUCCESS;
+       }
+
+      if (nbytes > 0)
+       {
+         buf[nbytes] = '\0';
+         fprintf (fp, "%s", buf);
+         fflush (fp);
+
+         if (nbytes >= 4)
+           {
+             i = nbytes - 4;
+             if (buf[i] == '\0' && buf[i + 1] == '\0' && buf[i + 2] == '\0')
+               {
+                 ret = buf[i + 3];
+                 break;
+               }
+           }
+       }
+    }
+  return ret;
+}
+
+void
+vtysh_exit_ripd_only ()
+{
+  vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], "exit", stdout);
+}
+
+
+void
+vtysh_pager_init ()
+{
+  vtysh_pager_name = getenv ("VTYSH_PAGER");
+  if (! vtysh_pager_name)
+    vtysh_pager_name = "more";
+}
+
+/* Command execution over the vty interface. */
+void
+vtysh_execute_func (char *line, int pager)
+{
+  int ret, cmd_stat;
+  vector vline;
+  struct cmd_element *cmd;
+  FILE *fp = NULL;
+
+  /* Split readline string up into the vector */
+  vline = cmd_make_strvec (line);
+
+  if (vline == NULL)
+    return;
+
+  ret = cmd_execute_command (vline, vty, &cmd);
+
+  cmd_free_strvec (vline);
+
+  switch (ret)
+    {
+    case CMD_WARNING:
+      if (vty->type == VTY_FILE)
+       printf ("Warning...\n");
+      break;
+    case CMD_ERR_AMBIGUOUS:
+      printf ("%% Ambiguous command.\n");
+      break;
+    case CMD_ERR_NO_MATCH:
+      printf ("%% Unknown command.\n");
+      break;
+    case CMD_ERR_INCOMPLETE:
+      printf ("%% Command incomplete.\n");
+      break;
+    case CMD_SUCCESS_DAEMON:
+      {
+       if (pager && vtysh_pager_name)
+         {
+           fp = popen ("more", "w");
+           if (fp == NULL)
+             {
+               perror ("popen");
+               exit (1);
+             }
+         }
+       else
+         fp = stdout;
+
+       if (! strcmp(cmd->string,"configure terminal"))
+         {
+           cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA],
+                                            line, fp);
+           if (cmd_stat != CMD_WARNING)
+             cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP],
+                                              line, fp);
+           if (cmd_stat != CMD_WARNING)
+             cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp);
+           if (cmd_stat != CMD_WARNING)
+             cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF],
+                                              line, fp);
+           if (cmd_stat != CMD_WARNING)
+             cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp);
+           if (cmd_stat != CMD_WARNING)
+             cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP],
+                                              line, fp);
+           if (cmd_stat)
+             {
+                line = "end";
+                vline = cmd_make_strvec (line);
+
+                if (vline == NULL)
+                 {
+                   if (pager && vtysh_pager_name && fp)
+                     {
+                       if (pclose (fp) == -1)
+                         {
+                           perror ("pclose");
+                           exit (1);
+                         }
+                       fp = NULL;
+                     }
+                   return;
+                 }
+
+                ret = cmd_execute_command (vline, vty, &cmd);
+                cmd_free_strvec (vline);
+                if (ret != CMD_SUCCESS_DAEMON)
+                  break;
+             }
+           else
+             if (cmd->func)
+               {
+                 (*cmd->func) (cmd, vty, 0, NULL);
+                 break;
+                }
+         }
+
+       if (cmd->daemon & VTYSH_ZEBRA)
+         if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], line, fp)
+             != CMD_SUCCESS)
+           break;
+       if (cmd->daemon & VTYSH_RIPD)
+         if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], line, fp)
+             != CMD_SUCCESS)
+           break;
+       if (cmd->daemon & VTYSH_RIPNGD)
+         if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp)
+             != CMD_SUCCESS)
+           break;
+       if (cmd->daemon & VTYSH_OSPFD)
+         if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], line, fp)
+             != CMD_SUCCESS)
+           break;
+       if (cmd->daemon & VTYSH_OSPF6D)
+         if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp)
+             != CMD_SUCCESS)
+           break;
+       if (cmd->daemon & VTYSH_BGPD)
+         if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], line, fp)
+             != CMD_SUCCESS)
+           break;
+       if (cmd->func)
+         (*cmd->func) (cmd, vty, 0, NULL);
+      }
+    }
+  if (pager && vtysh_pager_name && fp)
+    {
+      if (pclose (fp) == -1)
+       {
+         perror ("pclose");
+         exit (1);
+       }
+      fp = NULL;
+    }
+}
+
+void
+vtysh_execute_no_pager (char *line)
+{
+  vtysh_execute_func (line, 0);
+}
+
+void
+vtysh_execute (char *line)
+{
+  vtysh_execute_func (line, 1);
+}
+
+/* Configration make from file. */
+int
+vtysh_config_from_file (struct vty *vty, FILE *fp)
+{
+  int ret;
+  vector vline;
+  struct cmd_element *cmd;
+
+  while (fgets (vty->buf, VTY_BUFSIZ, fp))
+    {
+      if (vty->buf[0] == '!' || vty->buf[1] == '#')
+       continue;
+
+      vline = cmd_make_strvec (vty->buf);
+
+      /* In case of comment line */
+      if (vline == NULL)
+       continue;
+
+      /* Execute configuration command : this is strict match */
+      ret = cmd_execute_command_strict (vline, vty, &cmd);
+
+      /* Try again with setting node to CONFIG_NODE */
+      if (ret != CMD_SUCCESS 
+         && ret != CMD_SUCCESS_DAEMON
+         && ret != CMD_WARNING)
+       {
+         if (vty->node == KEYCHAIN_KEY_NODE)
+           {
+             vty->node = KEYCHAIN_NODE;
+             vtysh_exit_ripd_only ();
+             ret = cmd_execute_command_strict (vline, vty, &cmd);
+
+             if (ret != CMD_SUCCESS 
+                 && ret != CMD_SUCCESS_DAEMON 
+                 && ret != CMD_WARNING)
+               {
+                 vtysh_exit_ripd_only ();
+                 vty->node = CONFIG_NODE;
+                 ret = cmd_execute_command_strict (vline, vty, &cmd);
+               }
+           }
+         else
+           {
+             vtysh_execute ("end");
+             vtysh_execute ("configure terminal");
+             vty->node = CONFIG_NODE;
+             ret = cmd_execute_command_strict (vline, vty, &cmd);
+           }
+       }         
+
+      cmd_free_strvec (vline);
+
+      switch (ret)
+       {
+       case CMD_WARNING:
+         if (vty->type == VTY_FILE)
+           printf ("Warning...\n");
+         break;
+       case CMD_ERR_AMBIGUOUS:
+         printf ("%% Ambiguous command.\n");
+         break;
+       case CMD_ERR_NO_MATCH:
+         printf ("%% Unknown command: %s", vty->buf);
+         break;
+       case CMD_ERR_INCOMPLETE:
+         printf ("%% Command incomplete.\n");
+         break;
+       case CMD_SUCCESS_DAEMON:
+         {
+           if (cmd->daemon & VTYSH_ZEBRA)
+             if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA],
+                                       vty->buf, stdout) != CMD_SUCCESS)
+               break;
+           if (cmd->daemon & VTYSH_RIPD)
+             if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP],
+                                       vty->buf, stdout) != CMD_SUCCESS)
+               break;
+           if (cmd->daemon & VTYSH_RIPNGD)
+             if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG],
+                                       vty->buf, stdout) != CMD_SUCCESS)
+               break;
+           if (cmd->daemon & VTYSH_OSPFD)
+             if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF],
+                                       vty->buf, stdout) != CMD_SUCCESS)
+               break;
+           if (cmd->daemon & VTYSH_OSPF6D)
+             if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6],
+                                       vty->buf, stdout) != CMD_SUCCESS)
+               break;
+           if (cmd->daemon & VTYSH_BGPD)
+             if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP],
+                                       vty->buf, stdout) != CMD_SUCCESS)
+               break;
+           if (cmd->func)
+             (*cmd->func) (cmd, vty, 0, NULL);
+         }
+       }
+    }
+  return CMD_SUCCESS;
+}
+
+/* We don't care about the point of the cursor when '?' is typed. */
+int
+vtysh_rl_describe ()
+{
+  int ret;
+  int i;
+  vector vline;
+  vector describe;
+  int width;
+  struct desc *desc;
+
+  vline = cmd_make_strvec (rl_line_buffer);
+
+  /* In case of '> ?'. */
+  if (vline == NULL)
+    {
+      vline = vector_init (1);
+      vector_set (vline, '\0');
+    }
+  else 
+    if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1]))
+      vector_set (vline, '\0');
+
+  describe = cmd_describe_command (vline, vty, &ret);
+
+  printf ("\n");
+
+  /* Ambiguous and no match error. */
+  switch (ret)
+    {
+    case CMD_ERR_AMBIGUOUS:
+      cmd_free_strvec (vline);
+      printf ("%% Ambiguous command.\n");
+      rl_on_new_line ();
+      return 0;
+      break;
+    case CMD_ERR_NO_MATCH:
+      cmd_free_strvec (vline);
+      printf ("%% There is no matched command.\n");
+      rl_on_new_line ();
+      return 0;
+      break;
+    }  
+
+  /* Get width of command string. */
+  width = 0;
+  for (i = 0; i < vector_max (describe); i++)
+    if ((desc = vector_slot (describe, i)) != NULL)
+      {
+       int len;
+
+       if (desc->cmd[0] == '\0')
+         continue;
+
+       len = strlen (desc->cmd);
+       if (desc->cmd[0] == '.')
+         len--;
+
+       if (width < len)
+         width = len;
+      }
+
+  for (i = 0; i < vector_max (describe); i++)
+    if ((desc = vector_slot (describe, i)) != NULL)
+      {
+       if (desc->cmd[0] == '\0')
+         continue;
+
+       if (! desc->str)
+         printf ("  %-s\n",
+                 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd);
+       else
+         printf ("  %-*s  %s\n",
+                 width,
+                 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+                 desc->str);
+      }
+
+  cmd_free_strvec (vline);
+  vector_free (describe);
+
+  rl_on_new_line();
+
+  return 0;
+}
+
+/* result of cmd_complete_command() call will be stored here
+   and used in new_completion() in order to put the space in
+   correct places only */
+int complete_status;
+
+char *
+command_generator (char *text, int state)
+{
+  vector vline;
+  static char **matched = NULL;
+  static int index = 0;
+
+  /* First call. */
+  if (! state)
+    {
+      index = 0;
+
+      if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+       return NULL;
+
+      vline = cmd_make_strvec (rl_line_buffer);
+      if (vline == NULL)
+       return NULL;
+
+      if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1]))
+       vector_set (vline, '\0');
+
+      matched = cmd_complete_command (vline, vty, &complete_status);
+    }
+
+  if (matched && matched[index])
+    return matched[index++];
+
+  return NULL;
+}
+
+char **
+new_completion (char *text, int start, int end)
+{
+  char **matches;
+
+  matches = completion_matches (text, command_generator);
+
+  if (matches)
+    {
+      rl_point = rl_end;
+      if (complete_status == CMD_COMPLETE_FULL_MATCH)
+       rl_pending_input = ' ';
+    }
+
+  return matches;
+}
+
+char **
+vtysh_completion (char *text, int start, int end)
+{
+  int ret;
+  vector vline;
+  char **matched = NULL;
+
+  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+    return NULL;
+
+  vline = cmd_make_strvec (rl_line_buffer);
+  if (vline == NULL)
+    return NULL;
+
+  /* In case of 'help \t'. */
+  if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1]))
+    vector_set (vline, '\0');
+
+  matched = cmd_complete_command (vline, vty, &ret);
+
+  cmd_free_strvec (vline);
+
+  return (char **) matched;
+}
+
+/* BGP node structure. */
+struct cmd_node bgp_node =
+{
+  BGP_NODE,
+  "%s(config-router)# ",
+};
+
+/* BGP node structure. */
+struct cmd_node rip_node =
+{
+  RIP_NODE,
+  "%s(config-router)# ",
+};
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+};
+
+DEFUNSH (VTYSH_BGPD,
+        router_bgp,
+        router_bgp_cmd,
+        "router bgp <1-65535>",
+        ROUTER_STR
+        BGP_STR
+        AS_STR)
+{
+  vty->node = BGP_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
+        address_family_vpnv4,
+        address_family_vpnv4_cmd,
+        "address-family vpnv4",
+        "Enter Address Family command mode\n"
+        "Address family\n")
+{
+  vty->node = BGP_VPNV4_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
+        address_family_vpnv4_unicast,
+        address_family_vpnv4_unicast_cmd,
+        "address-family vpnv4 unicast",
+        "Enter Address Family command mode\n"
+        "Address family\n"
+        "Address Family Modifier\n")
+{
+  vty->node = BGP_VPNV4_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
+        address_family_ipv4_unicast,
+        address_family_ipv4_unicast_cmd,
+        "address-family ipv4 unicast",
+        "Enter Address Family command mode\n"
+        "Address family\n"
+        "Address Family Modifier\n")
+{
+  vty->node = BGP_IPV4_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
+        address_family_ipv4_multicast,
+        address_family_ipv4_multicast_cmd,
+        "address-family ipv4 multicast",
+        "Enter Address Family command mode\n"
+        "Address family\n"
+        "Address Family Modifier\n")
+{
+  vty->node = BGP_IPV4M_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
+        address_family_ipv6,
+        address_family_ipv6_cmd,
+        "address-family ipv6",
+        "Enter Address Family command mode\n"
+        "Address family\n")
+{
+  vty->node = BGP_IPV6_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
+        address_family_ipv6_unicast,
+        address_family_ipv6_unicast_cmd,
+        "address-family ipv6 unicast",
+        "Enter Address Family command mode\n"
+        "Address family\n"
+        "Address Family Modifier\n")
+{
+  vty->node = BGP_IPV6_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_RIPD,
+        key_chain,
+        key_chain_cmd,
+        "key chain WORD",
+        "Authentication key management\n"
+        "Key-chain management\n"
+        "Key-chain name\n")
+{
+  vty->node = KEYCHAIN_NODE;
+  return CMD_SUCCESS;
+}       
+
+DEFUNSH (VTYSH_RIPD,
+        key,
+        key_cmd,
+        "key <0-2147483647>",
+        "Configure a key\n"
+        "Key identifier number\n")
+{
+  vty->node = KEYCHAIN_KEY_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_RIPD,
+        router_rip,
+        router_rip_cmd,
+        "router rip",
+        ROUTER_STR
+        "RIP")
+{
+  vty->node = RIP_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_RIPNGD,
+        router_ripng,
+        router_ripng_cmd,
+        "router ripng",
+        ROUTER_STR
+        "RIPng")
+{
+  vty->node = RIPNG_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_OSPFD,
+        router_ospf,
+        router_ospf_cmd,
+        "router ospf",
+        "Enable a routing process\n"
+        "Start OSPF configuration\n")
+{
+  vty->node = OSPF_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_OSPF6D,
+        router_ospf6,
+        router_ospf6_cmd,
+        "router ospf6",
+        OSPF6_ROUTER_STR
+        OSPF6_STR)
+{
+  vty->node = OSPF6_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_RMAP,
+        route_map,
+        route_map_cmd,
+        "route-map WORD (deny|permit) <1-65535>",
+        "Create route-map or enter route-map command mode\n"
+        "Route map tag\n"
+        "Route map denies set operations\n"
+        "Route map permits set operations\n"
+        "Sequence to insert to/delete from existing route-map entry\n")
+{
+  vty->node = RMAP_NODE;
+  return CMD_SUCCESS;
+}
+
+/* Enable command */
+DEFUNSH (VTYSH_ALL,
+        vtysh_enable, 
+        vtysh_enable_cmd,
+        "enable",
+        "Turn on privileged mode command\n")
+{
+  vty->node = ENABLE_NODE;
+  return CMD_SUCCESS;
+}
+
+/* Disable command */
+DEFUNSH (VTYSH_ALL,
+        vtysh_disable, 
+        vtysh_disable_cmd,
+        "disable",
+        "Turn off privileged mode command\n")
+{
+  if (vty->node == ENABLE_NODE)
+    vty->node = VIEW_NODE;
+  return CMD_SUCCESS;
+}
+
+/* Configration from terminal */
+DEFUNSH (VTYSH_ALL,
+        vtysh_config_terminal,
+        vtysh_config_terminal_cmd,
+        "configure terminal",
+        "Configuration from vty interface\n"
+        "Configuration terminal\n")
+{
+  vty->node = CONFIG_NODE;
+  return CMD_SUCCESS;
+}
+
+int
+vtysh_exit (struct vty *vty)
+{
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      exit (0);
+      break;
+    case CONFIG_NODE:
+      vty->node = ENABLE_NODE;
+      break;
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case BGP_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case MASC_NODE:
+    case RMAP_NODE:
+    case VTY_NODE:
+    case KEYCHAIN_NODE:
+      vty->node = CONFIG_NODE;
+      break;
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+      vty->node = BGP_NODE;
+      break;
+    case KEYCHAIN_KEY_NODE:
+      vty->node = KEYCHAIN_NODE;
+      break;
+    default:
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ALL,
+        vtysh_exit_all,
+        vtysh_exit_all_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_all,
+       vtysh_quit_all_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUNSH (VTYSH_BGPD,
+        exit_address_family,
+        exit_address_family_cmd,
+        "exit-address-family",
+        "Exit from Address Family configuration mode\n")
+{
+  if (vty->node == BGP_IPV4_NODE
+      || vty->node == BGP_IPV4M_NODE
+      || vty->node == BGP_VPNV4_NODE
+      || vty->node == BGP_IPV6_NODE)
+    vty->node = BGP_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_ZEBRA,
+        vtysh_exit_zebra,
+        vtysh_exit_zebra_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_zebra,
+       vtysh_quit_zebra_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUNSH (VTYSH_RIPD,
+        vtysh_exit_ripd,
+        vtysh_exit_ripd_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_ripd,
+       vtysh_quit_ripd_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUNSH (VTYSH_RMAP,
+        vtysh_exit_rmap,
+        vtysh_exit_rmap_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_rmap,
+       vtysh_quit_rmap_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUNSH (VTYSH_BGPD,
+        vtysh_exit_bgpd,
+        vtysh_exit_bgpd_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_bgpd,
+       vtysh_quit_bgpd_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUNSH (VTYSH_OSPFD,
+        vtysh_exit_ospfd,
+        vtysh_exit_ospfd_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_ospfd,
+       vtysh_quit_ospfd_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUNSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD,
+        vtysh_interface,
+        vtysh_interface_cmd,
+        "interface IFNAME",
+        "Select an interface to configure\n"
+        "Interface's name\n")
+{
+  vty->node = INTERFACE_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD,
+       set_ip_nexthop_cmd,
+       "set ip next-hop A.B.C.D",
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+DEFSH (VTYSH_RMAP,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+
+DEFUNSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD,
+        vtysh_exit_interface,
+        vtysh_exit_interface_cmd,
+        "exit",
+        "Exit current mode and down to previous mode\n")
+{
+  return vtysh_exit (vty);
+}
+
+ALIAS (vtysh_exit_interface,
+       vtysh_quit_interface_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+
+DEFUN (vtysh_write_terminal,
+       vtysh_write_terminal_cmd,
+       "write terminal",
+       "Write running configuration to memory, network, or terminal\n"
+       "Write to terminal\n")
+{
+  int ret;
+  char line[] = "write terminal\n";
+  FILE *fp = NULL;
+
+  if (vtysh_pager_name)
+    {
+      fp = popen ("more", "w");
+      if (fp == NULL)
+       {
+         perror ("popen");
+         exit (1);
+       }
+    }
+  else
+    fp = stdout;
+
+  vty_out (vty, "Building configuration...%s", VTY_NEWLINE);
+  vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+          VTY_NEWLINE);
+
+  vtysh_config_write (fp);
+
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_ZEBRA], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIP], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIPNG], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF6], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_BGP], line);
+
+  vtysh_config_dump (fp);
+
+  if (vtysh_pager_name && fp)
+    {
+      fflush (fp);
+      if (pclose (fp) == -1)
+       {
+         perror ("pclose");
+         exit (1);
+       }
+      fp = NULL;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_write_memory,
+       vtysh_write_memory_cmd,
+       "write memory",
+       "Write running configuration to memory, network, or terminal\n"
+       "Write configuration to the file (same as write file)\n")
+{
+  int ret;
+  mode_t old_umask;
+  char line[] = "write terminal\n";
+  FILE *fp;
+  char *integrate_sav = NULL;
+
+  /* config files have 0600 perms... */ 
+  old_umask = umask (0077);
+
+  integrate_sav = malloc (strlen (integrate_default) 
+                           + strlen (CONF_BACKUP_EXT) + 1);
+  strcpy (integrate_sav, integrate_default);
+  strcat (integrate_sav, CONF_BACKUP_EXT);
+
+
+  printf ("Building Configuration...\n");
+
+  /* Move current configuration file to backup config file */
+  unlink (integrate_sav);
+  rename (integrate_default, integrate_sav);
+
+  fp = fopen (integrate_default, "w");
+  if (fp == NULL)
+    {
+      printf ("%% Can't open configuration file %s.\n", integrate_default);
+      umask (old_umask);
+      return CMD_SUCCESS;
+    }
+  else
+    printf ("[OK]\n");
+         
+
+  vtysh_config_write (fp);
+
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_ZEBRA], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIP], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIPNG], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF6], line);
+  ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_BGP], line);
+
+  vtysh_config_dump (fp);
+
+  fclose (fp);
+
+  umask (old_umask);
+  return CMD_SUCCESS;
+}
+
+ALIAS (vtysh_write_memory,
+       vtysh_copy_runningconfig_startupconfig_cmd,
+       "copy running-config startup-config",  
+       "Copy from one file to another\n"
+       "Copy from current system configuration\n"
+       "Copy to startup configuration\n")
+
+ALIAS (vtysh_write_memory,
+       vtysh_write_file_cmd,
+       "write file",
+       "Write running configuration to memory, network, or terminal\n"
+       "Write configuration to the file (same as write memory)\n")
+
+ALIAS (vtysh_write_terminal,
+       vtysh_show_running_config_cmd,
+       "show running-config",
+       SHOW_STR
+       "Current operating configuration\n")
+\f
+/* Execute command in child process. */
+int
+execute_command (char *command, int argc, char *arg1, char *arg2)
+{
+  int ret;
+  pid_t pid;
+  int status;
+
+  /* Call fork(). */
+  pid = fork ();
+
+  if (pid < 0)
+    {
+      /* Failure of fork(). */
+      fprintf (stderr, "Can't fork: %s\n", strerror (errno));
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      /* This is child process. */
+      switch (argc)
+       {
+       case 0:
+         ret = execlp (command, command, NULL);
+         break;
+       case 1:
+         ret = execlp (command, command, arg1, NULL);
+         break;
+       case 2:
+         ret = execlp (command, command, arg1, arg2, NULL);
+         break;
+       }
+
+      /* When execlp suceed, this part is not executed. */
+      fprintf (stderr, "Can't execute %s: %s\n", command, strerror (errno));
+      exit (1);
+    }
+  else
+    {
+      /* This is parent. */
+      execute_flag = 1;
+      ret = wait4 (pid, &status, 0, NULL);
+      execute_flag = 0;
+    }
+  return 0;
+}
+
+DEFUN (vtysh_ping,
+       vtysh_ping_cmd,
+       "ping WORD",
+       "send echo messages\n"
+       "Ping destination address or hostname\n")
+{
+  execute_command ("ping", 1, argv[0], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_traceroute,
+       vtysh_traceroute_cmd,
+       "traceroute WORD",
+       "Trace route to destination\n"
+       "Trace route to destination address or hostname\n")
+{
+  execute_command ("traceroute", 1, argv[0], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_telnet,
+       vtysh_telnet_cmd,
+       "telnet WORD",
+       "Open a telnet connection\n"
+       "IP address or hostname of a remote system\n")
+{
+  execute_command ("telnet", 1, argv[0], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_telnet_port,
+       vtysh_telnet_port_cmd,
+       "telnet WORD PORT",
+       "Open a telnet connection\n"
+       "IP address or hostname of a remote system\n"
+       "TCP Port number\n")
+{
+  execute_command ("telnet", 2, argv[0], argv[1]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_start_shell,
+       vtysh_start_shell_cmd,
+       "start-shell",
+       "Start UNIX shell\n")
+{
+  execute_command ("sh", 0, NULL, NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_start_bash,
+       vtysh_start_bash_cmd,
+       "start-shell bash",
+       "Start UNIX shell\n"
+       "Start bash\n")
+{
+  execute_command ("bash", 0, NULL, NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vtysh_start_zsh,
+       vtysh_start_zsh_cmd,
+       "start-shell zsh",
+       "Start UNIX shell\n"
+       "Start Z shell\n")
+{
+  execute_command ("zsh", 0, NULL, NULL);
+  return CMD_SUCCESS;
+}
+\f
+/* Route map node structure. */
+struct cmd_node rmap_node =
+{
+  RMAP_NODE,
+  "%s(config-route-map)# "
+};
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-router)# "
+};
+
+struct cmd_node bgp_vpnv4_node =
+{
+  BGP_VPNV4_NODE,
+  "%s(config-router-af)# "
+};
+
+struct cmd_node bgp_ipv4_node =
+{
+  BGP_IPV4_NODE,
+  "%s(config-router-af)# "
+};
+
+struct cmd_node bgp_ipv4m_node =
+{
+  BGP_IPV4M_NODE,
+  "%s(config-router-af)# "
+};
+
+struct cmd_node bgp_ipv6_node =
+{
+  BGP_IPV6_NODE,
+  "%s(config-router-af)# "
+};
+
+struct cmd_node ospf_node =
+{
+  OSPF_NODE,
+  "%s(config-router)# "
+};
+
+/* RIPng node structure. */
+struct cmd_node ripng_node =
+{
+  RIPNG_NODE,
+  "%s(config-router)# "
+};
+
+/* OSPF6 node structure. */
+struct cmd_node ospf6_node =
+{
+  OSPF6_NODE,
+  "%s(config-ospf6)# "
+};
+
+struct cmd_node keychain_node =
+{
+  KEYCHAIN_NODE,
+  "%s(config-keychain)# "
+};
+
+struct cmd_node keychain_key_node =
+{
+  KEYCHAIN_KEY_NODE,
+  "%s(config-keychain-key)# "
+};
+\f
+void
+vtysh_install_default (enum node_type node)
+{
+  install_element (node, &config_list_cmd);
+}
+
+/* Making connection to protocol daemon. */
+int
+vtysh_connect (struct vtysh_client *vclient, char *path)
+{
+  int ret;
+  int sock, len;
+  struct sockaddr_un addr;
+  struct stat s_stat;
+  uid_t euid;
+  gid_t egid;
+
+  memset (vclient, 0, sizeof (struct vtysh_client));
+  vclient->fd = -1;
+
+  /* Stat socket to see if we have permission to access it. */
+  euid = geteuid();
+  egid = getegid();
+  ret = stat (path, &s_stat);
+  if (ret < 0 && errno != ENOENT)
+    {
+      fprintf  (stderr, "vtysh_connect(%s): stat = %s\n", 
+               path, strerror(errno)); 
+      exit(1);
+    }
+  
+  if (ret >= 0)
+    {
+      if (! S_ISSOCK(s_stat.st_mode))
+       {
+         fprintf (stderr, "vtysh_connect(%s): Not a socket\n",
+                  path);
+         exit (1);
+       }
+      
+      if (euid != s_stat.st_uid 
+         || !(s_stat.st_mode & S_IWUSR)
+         || !(s_stat.st_mode & S_IRUSR))
+       {
+         fprintf (stderr, "vtysh_connect(%s): No permission to access socket\n",
+                  path);
+         exit (1);
+       }
+    }
+
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+#ifdef DEBUG
+      fprintf(stderr, "vtysh_connect(%s): socket = %s\n", path, strerror(errno));
+#endif /* DEBUG */
+      return -1;
+    }
+
+  memset (&addr, 0, sizeof (struct sockaddr_un));
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+  len = addr.sun_len = SUN_LEN(&addr);
+#else
+  len = sizeof (addr.sun_family) + strlen (addr.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+  ret = connect (sock, (struct sockaddr *) &addr, len);
+  if (ret < 0)
+    {
+#ifdef DEBUG
+      fprintf(stderr, "vtysh_connect(%s): connect = %s\n", path, strerror(errno));
+#endif /* DEBUG */
+      close (sock);
+      return -1;
+    }
+  vclient->fd = sock;
+
+  return 0;
+}
+
+void
+vtysh_connect_all()
+{
+  /* Clear each daemons client structure. */
+  vtysh_connect (&vtysh_client[VTYSH_INDEX_ZEBRA], ZEBRA_PATH);
+  vtysh_connect (&vtysh_client[VTYSH_INDEX_RIP], RIP_PATH);
+  vtysh_connect (&vtysh_client[VTYSH_INDEX_RIPNG], RIPNG_PATH);
+  vtysh_connect (&vtysh_client[VTYSH_INDEX_OSPF], OSPF_PATH);
+  vtysh_connect (&vtysh_client[VTYSH_INDEX_OSPF6], OSPF6_PATH);
+  vtysh_connect (&vtysh_client[VTYSH_INDEX_BGP], BGP_PATH);
+}
+
+
+/* To disable readline's filename completion */
+int
+vtysh_completion_entry_fucntion (int ignore, int invoking_key)
+{
+  return 0;
+}
+
+void
+vtysh_readline_init ()
+{
+  /* readline related settings. */
+  rl_bind_key ('?', vtysh_rl_describe);
+  rl_completion_entry_function = vtysh_completion_entry_fucntion;
+  rl_attempted_completion_function = (CPPFunction *)new_completion;
+  /* do not append space after completion. It will be appended
+     in new_completion() function explicitly */
+  rl_completion_append_character = '\0';
+}
+
+char *
+vtysh_prompt ()
+{
+  struct utsname names;
+  static char buf[100];
+  const char*hostname;
+  extern struct host host;
+
+  hostname = host.name;
+
+  if (!hostname)
+    {
+      uname (&names);
+      hostname = names.nodename;
+    }
+
+  snprintf (buf, sizeof buf, cmd_prompt (vty->node), hostname);
+
+  return buf;
+}
+
+void
+vtysh_init_vty ()
+{
+  /* Make vty structure. */
+  vty = vty_new ();
+  vty->type = VTY_SHELL;
+  vty->node = VIEW_NODE;
+
+  /* Initialize commands. */
+  cmd_init (0);
+
+  /* Install nodes. */
+  install_node (&bgp_node, NULL);
+  install_node (&rip_node, NULL);
+  install_node (&interface_node, NULL);
+  install_node (&rmap_node, NULL);
+  install_node (&zebra_node, NULL);
+  install_node (&bgp_vpnv4_node, NULL);
+  install_node (&bgp_ipv4_node, NULL);
+  install_node (&bgp_ipv4m_node, NULL);
+/* #ifdef HAVE_IPV6 */
+  install_node (&bgp_ipv6_node, NULL);
+/* #endif */
+  install_node (&ospf_node, NULL);
+/* #ifdef HAVE_IPV6 */
+  install_node (&ripng_node, NULL);
+  install_node (&ospf6_node, NULL);
+/* #endif */
+  install_node (&keychain_node, NULL);
+  install_node (&keychain_key_node, NULL);
+
+  vtysh_install_default (VIEW_NODE);
+  vtysh_install_default (ENABLE_NODE);
+  vtysh_install_default (CONFIG_NODE);
+  vtysh_install_default (BGP_NODE);
+  vtysh_install_default (RIP_NODE);
+  vtysh_install_default (INTERFACE_NODE);
+  vtysh_install_default (RMAP_NODE);
+  vtysh_install_default (ZEBRA_NODE);
+  vtysh_install_default (BGP_VPNV4_NODE);
+  vtysh_install_default (BGP_IPV4_NODE);
+  vtysh_install_default (BGP_IPV4M_NODE);
+  vtysh_install_default (BGP_IPV6_NODE);
+  vtysh_install_default (OSPF_NODE);
+  vtysh_install_default (RIPNG_NODE);
+  vtysh_install_default (OSPF6_NODE);
+  vtysh_install_default (KEYCHAIN_NODE);
+  vtysh_install_default (KEYCHAIN_KEY_NODE);
+
+  install_element (VIEW_NODE, &vtysh_enable_cmd);
+  install_element (ENABLE_NODE, &vtysh_config_terminal_cmd);
+  install_element (ENABLE_NODE, &vtysh_disable_cmd);
+
+  /* "exit" command. */
+  install_element (VIEW_NODE, &vtysh_exit_all_cmd);
+  install_element (VIEW_NODE, &vtysh_quit_all_cmd);
+  install_element (CONFIG_NODE, &vtysh_exit_all_cmd);
+  /* install_element (CONFIG_NODE, &vtysh_quit_all_cmd); */
+  install_element (ENABLE_NODE, &vtysh_exit_all_cmd);
+  install_element (ENABLE_NODE, &vtysh_quit_all_cmd);
+  install_element (RIP_NODE, &vtysh_exit_ripd_cmd);
+  install_element (RIP_NODE, &vtysh_quit_ripd_cmd);
+  install_element (OSPF_NODE, &vtysh_exit_ospfd_cmd);
+  install_element (OSPF_NODE, &vtysh_quit_ospfd_cmd);
+  install_element (BGP_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_VPNV4_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (KEYCHAIN_NODE, &vtysh_exit_ripd_cmd);
+  install_element (KEYCHAIN_NODE, &vtysh_quit_ripd_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &vtysh_exit_ripd_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &vtysh_quit_ripd_cmd);
+  install_element (RMAP_NODE, &vtysh_exit_rmap_cmd);
+  install_element (RMAP_NODE, &vtysh_quit_rmap_cmd);
+
+  /* "end" command. */
+  install_element (CONFIG_NODE, &vtysh_end_all_cmd);
+  install_element (ENABLE_NODE, &vtysh_end_all_cmd);
+  install_element (RIP_NODE, &vtysh_end_all_cmd);
+  install_element (RIPNG_NODE, &vtysh_end_all_cmd);
+  install_element (OSPF_NODE, &vtysh_end_all_cmd);
+  install_element (OSPF6_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
+  install_element (KEYCHAIN_NODE, &vtysh_end_all_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
+  install_element (RMAP_NODE, &vtysh_end_all_cmd);
+
+  install_element (INTERFACE_NODE, &vtysh_end_all_cmd);
+  install_element (INTERFACE_NODE, &vtysh_exit_interface_cmd);
+  install_element (INTERFACE_NODE, &vtysh_quit_interface_cmd);
+  install_element (CONFIG_NODE, &router_rip_cmd);
+#ifdef HAVE_IPV6
+  install_element (CONFIG_NODE, &router_ripng_cmd);
+#endif
+  install_element (CONFIG_NODE, &router_ospf_cmd);
+#ifdef HAVE_IPV6
+  install_element (CONFIG_NODE, &router_ospf6_cmd);
+#endif
+  install_element (CONFIG_NODE, &router_bgp_cmd);
+  install_element (BGP_NODE, &address_family_vpnv4_cmd);
+  install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd);
+  install_element (BGP_NODE, &address_family_ipv4_unicast_cmd);
+  install_element (BGP_NODE, &address_family_ipv4_multicast_cmd);
+#ifdef HAVE_IPV6
+  install_element (BGP_NODE, &address_family_ipv6_cmd);
+  install_element (BGP_NODE, &address_family_ipv6_unicast_cmd);
+#endif
+  install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
+  install_element (CONFIG_NODE, &key_chain_cmd);
+  install_element (CONFIG_NODE, &route_map_cmd);
+  install_element (KEYCHAIN_NODE, &key_cmd);
+  install_element (KEYCHAIN_NODE, &key_chain_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd);
+  install_element (CONFIG_NODE, &vtysh_interface_cmd);
+  install_element (ENABLE_NODE, &vtysh_show_running_config_cmd);
+  install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd);
+  install_element (ENABLE_NODE, &vtysh_write_file_cmd);
+
+  /* write terminal command */
+  install_element (ENABLE_NODE, &vtysh_write_terminal_cmd);
+  install_element (CONFIG_NODE, &vtysh_write_terminal_cmd);
+  install_element (BGP_NODE, &vtysh_write_terminal_cmd);
+  install_element (BGP_VPNV4_NODE, &vtysh_write_terminal_cmd);
+  install_element (BGP_IPV4_NODE, &vtysh_write_terminal_cmd);
+  install_element (BGP_IPV4M_NODE, &vtysh_write_terminal_cmd);
+  install_element (BGP_IPV6_NODE, &vtysh_write_terminal_cmd);
+  install_element (RIP_NODE, &vtysh_write_terminal_cmd);
+  install_element (RIPNG_NODE, &vtysh_write_terminal_cmd);
+  install_element (OSPF_NODE, &vtysh_write_terminal_cmd);
+  install_element (OSPF6_NODE, &vtysh_write_terminal_cmd);
+  install_element (INTERFACE_NODE, &vtysh_write_terminal_cmd);
+  install_element (RMAP_NODE, &vtysh_write_terminal_cmd);
+  install_element (KEYCHAIN_NODE, &vtysh_write_terminal_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &vtysh_write_terminal_cmd);
+
+  /* write memory command */
+  install_element (ENABLE_NODE, &vtysh_write_memory_cmd);
+  install_element (CONFIG_NODE, &vtysh_write_memory_cmd);
+  install_element (BGP_NODE, &vtysh_write_memory_cmd);
+  install_element (BGP_VPNV4_NODE, &vtysh_write_memory_cmd);
+  install_element (BGP_IPV4_NODE, &vtysh_write_memory_cmd);
+  install_element (BGP_IPV4M_NODE, &vtysh_write_memory_cmd);
+  install_element (BGP_IPV6_NODE, &vtysh_write_memory_cmd);
+  install_element (RIP_NODE, &vtysh_write_memory_cmd);
+  install_element (RIPNG_NODE, &vtysh_write_memory_cmd);
+  install_element (OSPF_NODE, &vtysh_write_memory_cmd);
+  install_element (OSPF6_NODE, &vtysh_write_memory_cmd);
+  install_element (INTERFACE_NODE, &vtysh_write_memory_cmd);
+  install_element (RMAP_NODE, &vtysh_write_memory_cmd);
+  install_element (KEYCHAIN_NODE, &vtysh_write_memory_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &vtysh_write_memory_cmd);
+
+  install_element (VIEW_NODE, &vtysh_ping_cmd);
+  install_element (VIEW_NODE, &vtysh_traceroute_cmd);
+  install_element (VIEW_NODE, &vtysh_telnet_cmd);
+  install_element (VIEW_NODE, &vtysh_telnet_port_cmd);
+  install_element (ENABLE_NODE, &vtysh_ping_cmd);
+  install_element (ENABLE_NODE, &vtysh_traceroute_cmd);
+  install_element (ENABLE_NODE, &vtysh_telnet_cmd);
+  install_element (ENABLE_NODE, &vtysh_telnet_port_cmd);
+  install_element (ENABLE_NODE, &vtysh_start_shell_cmd);
+  install_element (ENABLE_NODE, &vtysh_start_bash_cmd);
+  install_element (ENABLE_NODE, &vtysh_start_zsh_cmd);
+
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+
+  install_element (CONFIG_NODE, &vtysh_log_stdout_cmd);
+  install_element (CONFIG_NODE, &no_vtysh_log_stdout_cmd);
+  install_element (CONFIG_NODE, &vtysh_log_file_cmd);
+  install_element (CONFIG_NODE, &no_vtysh_log_file_cmd);
+  install_element (CONFIG_NODE, &vtysh_log_syslog_cmd);
+  install_element (CONFIG_NODE, &no_vtysh_log_syslog_cmd);
+  install_element (CONFIG_NODE, &vtysh_log_trap_cmd);
+  install_element (CONFIG_NODE, &no_vtysh_log_trap_cmd);
+  install_element (CONFIG_NODE, &vtysh_log_record_priority_cmd);
+  install_element (CONFIG_NODE, &no_vtysh_log_record_priority_cmd);
+}
diff --git a/vtysh/vtysh.conf.sample b/vtysh/vtysh.conf.sample
new file mode 100644 (file)
index 0000000..29d6808
--- /dev/null
@@ -0,0 +1,4 @@
+!
+! vtysh sample configuratin file
+!
+!username kunihiro nopassword
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
new file mode 100644 (file)
index 0000000..193f46e
--- /dev/null
@@ -0,0 +1,83 @@
+/* Virtual terminal interface shell.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef VTYSH_H
+#define VTYSH_H
+
+#define VTYSH_ZEBRA  0x01
+#define VTYSH_RIPD   0x02
+#define VTYSH_RIPNGD 0x04
+#define VTYSH_OSPFD  0x08
+#define VTYSH_OSPF6D 0x10
+#define VTYSH_BGPD   0x20
+#define VTYSH_ALL    VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD
+#define VTYSH_RMAP   VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD
+
+#define VTYSH_INDEX_ZEBRA 0
+#define VTYSH_INDEX_RIP   1
+#define VTYSH_INDEX_RIPNG 2
+#define VTYSH_INDEX_OSPF  3
+#define VTYSH_INDEX_OSPF6 4
+#define VTYSH_INDEX_BGP   5
+#define VTYSH_INDEX_MAX   6
+
+/* UNIX domain socket path. */
+#define ZEBRA_PATH "/tmp/.zebra"
+#define RIP_PATH "/tmp/.ripd"
+#define RIPNG_PATH "/tmp/.ripngd"
+#define OSPF_PATH "/tmp/.ospfd"
+#define OSPF6_PATH "/tmp/.ospf6d"
+#define BGP_PATH "/tmp/.bgpd"
+
+/* vtysh local configuration file. */
+#define VTYSH_DEFAULT_CONFIG "vtysh.conf"
+
+void vtysh_init_vty ();
+void vtysh_init_cmd ();
+void vtysh_connect_all ();
+void vtysh_readline_init ();
+void vtysh_user_init ();
+
+void vtysh_execute (char *);
+void vtysh_execute_no_pager (char *);
+
+char *vtysh_prompt ();
+
+void vtysh_config_write ();
+
+int vtysh_config_from_file (struct vty *, FILE *);
+
+void vtysh_read_config (char *, char *, char *);
+
+void vtysh_config_parse (char *);
+
+void vtysh_config_dump (FILE *);
+
+void vtysh_config_init ();
+
+void vtysh_pager_init ();
+
+/* Child process execution flag. */
+extern int execute_flag;
+
+extern struct vty *vty;
+
+#endif /* VTYSH_H */
diff --git a/vtysh/vtysh_cmd.c b/vtysh/vtysh_cmd.c
new file mode 100644 (file)
index 0000000..f71a79a
--- /dev/null
@@ -0,0 +1,14710 @@
+#include <zebra.h>
+#include "command.h"
+#include "vtysh.h"
+
+DEFSH (VTYSH_BGPD, neighbor_version_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "version (4|4-)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Neighbor's BGP version\n"
+       "Border Gateway Protocol 4\n"
+       "Multiprotocol Extensions for BGP-4(Old Draft)\n")
+
+DEFSH (VTYSH_BGPD, no_set_aspath_prepend_cmd_vtysh, 
+       "no set as-path prepend", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "Prepend string for a BGP AS-path attribute\n"
+       "Prepend to the as-path\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ipv6_prefix_list_cmd_vtysh, 
+       "clear ipv6 prefix-list", 
+       "Reset functions\n"
+       "IPv6 information\n"
+       "Build a prefix list\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh, 
+       "clear ip bgp A.B.C.D vpnv4 unicast soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_any_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Any destination host\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_description_cmd_vtysh, 
+       "ip prefix-list WORD description .LINE", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_cmd_vtysh, 
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_inter_external_cmd_vtysh, 
+       "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+
+DEFSH (VTYSH_OSPFD, area_default_cost_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the summary-default cost of a NSSA or stub area\n"
+       "Stub's advertised default summary cost\n")
+
+DEFSH (VTYSH_RIPNGD, default_information_originate_cmd_vtysh, 
+       "default-information originate", 
+       "Default route information\n"
+       "Distribute default route\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_update_source_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Source of routing updates\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_route_cmd_vtysh, 
+       "show bgp ipv6 X:X::X:X", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_ZEBRA, no_bandwidth_if_cmd_vtysh, 
+       "no bandwidth", 
+       "Negate a command or set its defaults\n"
+       "Set bandwidth informational parameter\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_any_cmd_vtysh, 
+       "access-list (<1-99>|<1300-1999>) (deny|permit) any", 
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any source host\n")
+
+DEFSH (VTYSH_BGPD, no_match_ipv6_next_hop_cmd_vtysh, 
+       "no match ipv6 next-hop X:X::X:X", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IPv6 information\n"
+       "Match IPv6 next-hop address of route\n"
+       "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_out_cmd_vtysh, 
+       "clear bgp external out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_le_cmd_vtysh, 
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_summary_cmd_vtysh, 
+       "show ip bgp view WORD summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "View name\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_metric_routemap_cmd_vtysh, 
+       "redistribute kernel metric <0-16> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance_source_cmd_vtysh, 
+       "no distance <1-255> A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n")
+
+DEFSH (VTYSH_OSPF6D, no_ospf6_redistribute_cmd_vtysh, 
+       "no redistribute (static|kernel|connected|ripng|bgp)", 
+       "Negate a command or set its defaults\n"
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+
+DEFSH (VTYSH_RIPNGD, ripng_aggregate_address_cmd_vtysh, 
+       "aggregate-address X:X::X:X/M", 
+       "Set aggregate RIPng route announcement\n"
+       "Aggregate network\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_duration_month_day_cmd_vtysh, 
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_ge_cmd_vtysh, 
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_cmd_vtysh, 
+       "clear ip bgp dampening", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear route flap dampening information\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_zebra_cmd_vtysh, 
+       "debug ripng zebra", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng and zebra communication\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_cmd_vtysh, 
+       "no redistribute static", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community3_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_all_cmd_vtysh, 
+       "show ipv6 bgp community", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_prefix_list_val_cmd_vtysh, 
+       "no match ip next-hop prefix-list WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf6|ripng|static)", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_local_as_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Specify a local-as number\n")
+
+DEFSH (VTYSH_OSPFD, ospf_network_cmd_vtysh, 
+       "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", 
+       "OSPF interface commands\n"
+       "Network type\n"
+       "Specify OSPF broadcast multi-access network\n"
+       "Specify OSPF NBMA network\n"
+       "Specify OSPF point-to-multipoint network\n"
+       "Specify OSPF point-to-point network\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_set_metric_cmd_vtysh, 
+       "no set metric", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "Metric value for destination routing protocol\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_filter_list_cmd_vtysh, 
+       "show ip bgp filter-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_advertise_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "OSPF area range for route advertise (default)\n"
+       "area range prefix\n"
+       "advertise this range\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_ge_cmd_vtysh, 
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_timers_cmd_vtysh, 
+       "no timers bgp", 
+       "Negate a command or set its defaults\n"
+       "Adjust routing timers\n"
+       "BGP timers\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_enforce_first_as_cmd_vtysh, 
+       "no bgp enforce-first-as", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Enforce the first AS for EBGP routes\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_mode_cmd_vtysh, 
+       "no ip rip authentication mode", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_cmd_vtysh, 
+       "distance ospf intra-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_BGPD, match_ipv6_address_cmd_vtysh, 
+       "match ipv6 address WORD", 
+       "Match values from routing table\n"
+       "IPv6 information\n"
+       "Match IPv6 address of route\n"
+       "IPv6 access-list name\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_cmd_vtysh, 
+       "redistribute static", 
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_in_cmd_vtysh, 
+       "clear ip bgp * soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_routemap_cmd_vtysh, 
+       "no redistribute ospf6 metric <0-16> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD, no_router_rip_cmd_vtysh, 
+       "no router rip", 
+       "Negate a command or set its defaults\n"
+       "Enable a routing process\n"
+       "Routing Information Protocol (RIP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_summary_name_cmd_vtysh, 
+       "show ip prefix-list summary WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Summary of prefix lists\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_cmd_vtysh, 
+       "clear bgp *", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_strict_capability_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Strict capability negotiation match\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community2_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_set_metric_val_cmd_vtysh, 
+       "no set metric <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_in_cmd_vtysh, 
+       "clear ip bgp * in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_out_cmd_vtysh, 
+       "clear ip bgp peer-group WORD out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_network_area_cmd_vtysh, 
+       "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", 
+       "Negate a command or set its defaults\n"
+       "Enable routing on an IP network\n"
+       "OSPF network prefix\n"
+       "Set the OSPF area ID\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n")
+
+DEFSH (VTYSH_OSPFD, neighbor_pollinterval_cmd_vtysh, 
+       "neighbor A.B.C.D poll-interval <1-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor IP address\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, neighbor_activate_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "activate", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Enable the Address Family for this Neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_route_map_cmd_vtysh, 
+       "show ip bgp flap-statistics route-map WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+
+DEFSH (VTYSH_OSPF6D|VTYSH_BGPD, no_match_ipv6_address_prefix_list_cmd_vtysh, 
+       "no match ipv6 address prefix-list WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IPv6 information\n"
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_any_cmd_vtysh, 
+       "no ipv6 access-list WORD (deny|permit) any", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any prefixi to match\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_reachable_time_cmd_vtysh, 
+       "ipv6 nd reachable-time MILLISECONDS", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Reachable time\n"
+       "Reachable time in milliseconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_ge_le_cmd_vtysh, 
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_cmd_vtysh, 
+       "aggregate-address A.B.C.D A.B.C.D", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_metric_cmd_vtysh, 
+       "redistribute static metric <0-16>", 
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_cmd_vtysh, 
+       "ip ospf authentication", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_authkey_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(authentication-key|) AUTH_KEY", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n"
+       "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_OSPFD, no_ospf_compatible_rfc1583_cmd_vtysh, 
+       "no compatible rfc1583", 
+       "Negate a command or set its defaults\n"
+       "OSPF compatibility list\n"
+       "compatible with RFC 1583\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_ism_cmd_vtysh, 
+       "debug ospf ism", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine\n")
+
+DEFSH (VTYSH_RIPD, rip_split_horizon_cmd_vtysh, 
+       "ip split-horizon", 
+       "IP information\n"
+       "Perform split horizon\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_list_exact_cmd_vtysh, 
+       "show ipv6 mbgp community-list WORD exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_routemap_cmd_vtysh, 
+       "default-information originate always route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_cmd_vtysh, 
+       "clear bgp ipv6 external soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_sequence_number_cmd_vtysh, 
+       "ip prefix-list sequence-number", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_hello_interval_cmd_vtysh, 
+       "no ip ospf hello-interval", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_received_routes_cmd_vtysh, 
+       "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_cost_cmd_vtysh, 
+       "no ip ospf cost", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community4_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_ge_le_cmd_vtysh, 
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_in_cmd_vtysh, 
+       "clear bgp peer-group WORD soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_as_set_cmd_vtysh, 
+       "no aggregate-address A.B.C.D/M as-set", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh, 
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_set_local_pref_cmd_vtysh, 
+       "no set local-preference", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP local preference path attribute\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_BGPD, old_no_ipv6_bgp_network_cmd_vtysh, 
+       "no ipv6 bgp network X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_send_ra_cmd_vtysh, 
+       "ipv6 nd send-ra", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Send Router Advertisement\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_normal_cmd_vtysh, 
+       "debug bgp", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_routemap_cmd_vtysh, 
+       "no redistribute static metric <0-16> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_ZEBRA, no_bandwidth_if_val_cmd_vtysh, 
+       "no bandwidth <1-10000000>", 
+       "Negate a command or set its defaults\n"
+       "Set bandwidth informational parameter\n"
+       "Bandwidth in kilobits\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_id_adv_router_dump_cmd_vtysh, 
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*) (A.B.C.D|*) (A.B.C.D|*) (dump|summary|)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Link State ID\n"
+       "All Link State ID\n"
+       "Advertising Router\n"
+       "All Advertising Router\n"
+       "Dump raw LSA data in Hex\n"
+       "show summary of LSA\n"
+       )
+
+DEFSH (VTYSH_BGPD, no_bgp_router_id_val_cmd_vtysh, 
+       "no bgp router-id A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Override configured router identifier\n"
+       "Manually configured router identifier\n")
+
+DEFSH (VTYSH_RIPD, no_rip_offset_list_cmd_vtysh, 
+       "no offset-list WORD (in|out) <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_detail_all_cmd_vtysh, 
+       "show ip ospf neighbor detail all", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Neighbor list\n"
+       "detail of all neighbors\n"
+       "include down status neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_cmd_vtysh, 
+       "show bgp ipv6 X:X::X:X/M", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_BGPD, no_dump_bgp_routes_cmd_vtysh, 
+       "no dump bgp routes-mrt [PATH] [INTERVAL]", 
+       "Negate a command or set its defaults\n"
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump whole BGP routing table\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_external_cmd_vtysh, 
+       "distance ospf inter-area <1-255> external <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_event_cmd_vtysh, 
+       "debug ospf event", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF event information\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_retransmit_interval_cmd_vtysh, 
+       "no ospf retransmit-interval", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n")
+
+DEFSH (VTYSH_BGPD, set_community_none_cmd_vtysh, 
+       "set community none", 
+       "Set values in destination routing protocol\n"
+       "BGP community attribute\n"
+       "No community attribute\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_filter_cmd_vtysh, 
+       "debug bgp filters", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP filters\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_routemap_set_forwarding_cmd_vtysh, 
+       "set forwarding-address X:X::X:X", 
+       "Set value\n"
+       "Forwarding Address\n"
+       "IPv6 Address\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_compare_router_id_cmd_vtysh, 
+       "no bgp bestpath compare-routerid", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "Compare router-id for identical EBGP paths\n")
+
+DEFSH (VTYSH_RIPD, no_match_ip_address_val_cmd_vtysh, 
+       "no match ip address WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match address of route\n"
+       "IP access-list name\n")
+
+DEFSH (VTYSH_ZEBRA, bandwidth_if_cmd_vtysh, 
+       "bandwidth <1-10000000>", 
+       "Set bandwidth informational parameter\n"
+       "Bandwidth in kilobits\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_metric_cmd_vtysh, 
+       "default-metric <0-16777214>", 
+       "Set metric of redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_allowas_in_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "allow local ASN appears in aspath attribute\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_default_metric_cmd_vtysh, 
+       "no default-metric", 
+       "Negate a command or set its defaults\n"
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_OSPF6D, reload_cmd_vtysh, 
+       "reload", 
+       "Reloads\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_spf_tree_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D spf tree", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Shortest Path First caculation\n"
+       "Displays spf tree\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_unset2_cmd_vtysh, 
+       "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", 
+       "Negate a command or set its defaults\n"
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n"
+       "Half-life time for the penalty\n"
+       "Value to start reusing a route\n"
+       "Value to start suppressing a route\n"
+       "Maximum duration to suppress a stable route\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_authentication_key_addr_cmd_vtysh, 
+       "ip ospf authentication-key AUTH_KEY A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "The OSPF password (key)\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD, ip_rip_send_version_2_cmd_vtysh, 
+       "ip rip send version 2 1", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 2\n"
+       "RIP version 1\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_ifname_cmd_vtysh, 
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_all_cmd_vtysh, 
+       "show bgp community", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n")
+
+DEFSH (VTYSH_BGPD, neighbor_port_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Neighbor's BGP port\n"
+       "TCP port number\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_prefix_cmd_vtysh, 
+       "clear ip bgp dampening A.B.C.D/M", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear route flap dampening information\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_out_cmd_vtysh, 
+       "clear bgp ipv6 * soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_community_list_cmd_vtysh, 
+       "show ip community-list", 
+       "Show running system information\n"
+       "IP information\n"
+       "List community-list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_mask_host_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "A single destination host\n"
+       "Destination address\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_ra_lifetime_cmd_vtysh, 
+       "ipv6 nd ra-lifetime SECONDS", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Router lifetime\n"
+       "Router lifetime in seconds\n")
+
+DEFSH (VTYSH_BGPD, set_ecommunity_soo_cmd_vtysh, 
+       "set extcommunity soo .ASN:nn_or_IP-address:nn", 
+       "Set values in destination routing protocol\n"
+       "BGP extended community attribute\n"
+       "Site-of-Origin extended community\n"
+       "VPN extended community\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community4_exact_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_originator_id_cmd_vtysh, 
+       "no set originator-id", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP originator ID attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_prefix_cmd_vtysh, 
+       "show ip prefix-list WORD A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_infinite_day_month_cmd_vtysh, 
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Never expires")
+
+DEFSH (VTYSH_BGPD, no_neighbor_description_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Neighbor specific description\n"
+       "Up to 80 characters describing this neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_suppress_ra_cmd_vtysh, 
+       "ipv6 nd suppress-ra", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Suppress Router Advertisement\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_default_originate_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "default-originate", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Originate default route to this neighbor\n")
+
+DEFSH (VTYSH_RIPD, no_rip_passive_interface_cmd_vtysh, 
+       "no passive-interface IFNAME", 
+       "Negate a command or set its defaults\n"
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_remark_arg_cmd_vtysh, 
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_as_set_cmd_vtysh, 
+       "aggregate-address A.B.C.D/M as-set", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_cmd_vtysh, 
+       "interface IFNAME area A.B.C.D", 
+       "Enable routing on an IPv6 interface\n"
+       "Interface name(e.g. ep0)\n"
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+      )
+
+DEFSH (VTYSH_BGPD, no_neighbor_send_community_type_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Send Community attribute to this neighbor\n"
+       "Send Standard and Extended Community attributes\n"
+       "Send Extended Community attributes\n"
+       "Send Standard Community attributes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_hello_interval_cmd_vtysh, 
+       "ospf hello-interval <1-65535>", 
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_all_cmd_vtysh, 
+       "show ip ospf neighbor all", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Neighbor list\n"
+       "include down status neighbor\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_cost_cmd_vtysh, 
+       "ipv6 ospf6 cost COST", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Interface cost\n"
+       "<1-65535> Cost\n"
+       )
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_out_cmd_vtysh, 
+       "clear ip bgp external out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD, match_interface_cmd_vtysh, 
+       "match interface WORD", 
+       "Match values from routing table\n"
+       "Match first hop interface of route\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_kernel_cmd_vtysh, 
+       "debug zebra kernel", 
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra between kernel interface\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_cmd_vtysh, 
+       "no aggregate-address A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_forwarding_cmd_vtysh, 
+       "show ipv6 forwarding", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Forwarding status\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_prefix_advertisement_cmd_vtysh, 
+       "no ipv6 nd prefix-advertisement IPV6PREFIX", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_instance_cmd_vtysh, 
+       "ipv6 ospf6 instance-id INSTANCE", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Instance ID\n"
+       "<0-255> Instance ID\n"
+       )
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_as_set_summary_cmd_vtysh, 
+       "no aggregate-address A.B.C.D/M as-set summary-only", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_capability_dynamic_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Advertise capability to the peer\n"
+       "Advertise dynamic capability to this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_retransmit_interval_cmd_vtysh, 
+       "ospf retransmit-interval <3-65535>", 
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_confederation_identifier_cmd_vtysh, 
+       "bgp confederation identifier <1-65535>", 
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "AS number\n"
+       "Set routing domain confederation AS\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_cmd_vtysh, 
+       "clear ip bgp <1-65535> vpnv4 unicast soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged4_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_nsm_cmd_vtysh, 
+       "no debug ospf nsm", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Neighbor State Machine")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh, 
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_mask_cmd_vtysh, 
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, no_match_ipv6_address_cmd_vtysh, 
+       "no match ipv6 address WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IPv6 information\n"
+       "Match IPv6 address of route\n"
+       "IPv6 access-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_set_cmd_vtysh, 
+       "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", 
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n"
+       "Half-life time for the penalty\n"
+       "Value to start reusing a route\n"
+       "Value to start suppressing a route\n"
+       "Maximum duration to suppress a stable route\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_timers_arg_cmd_vtysh, 
+       "no timers bgp <0-65535> <0-65535>", 
+       "Negate a command or set its defaults\n"
+       "Adjust routing timers\n"
+       "BGP timers\n"
+       "Keepalive interval\n"
+       "Holdtime\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_month_day_month_day_cmd_vtysh, 
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community4_exact_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighborlist_cmd_vtysh, 
+       "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Link State summary list\n"
+       "Link State request list\n"
+       "Link State retransmission list\n"
+       "Link State Description list (Used to retrans DbDesc)\n"
+       )
+
+DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_external_inter_cmd_vtysh, 
+       "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_BGPD, no_set_atomic_aggregate_cmd_vtysh, 
+       "no set atomic-aggregate", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP atomic aggregate attribute\n" )
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_cmd_vtysh, 
+       "clear bgp ipv6 external", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n")
+
+DEFSH (VTYSH_OSPFD, network_area_cmd_vtysh, 
+       "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", 
+       "Enable routing on an IP network\n"
+       "OSPF network prefix\n"
+       "Set the OSPF area ID\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|)", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_aspath_ignore_cmd_vtysh, 
+       "bgp bestpath as-path ignore", 
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "AS-path attribute\n"
+       "Ignore as-path length in selecting a route\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_address_cmd_vtysh, 
+       "clear ip bgp dampening A.B.C.D", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear route flap dampening information\n"
+       "Network to clear damping information\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_metric_cmd_vtysh, 
+       "redistribute kernel metric <0-16>", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_any_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_med_cmd_vtysh, 
+       "bgp bestpath med (confed|missing-as-worst)", 
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_all_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp peer-group WORD in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_cmd_vtysh, 
+       "show ipv6 mbgp", 
+       "Show running system information\n"
+       "IP information\n"
+       "MBGP information\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_unsuppress_map_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Route-map to selectively unsuppress suppressed routes\n"
+       "Name of route map\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_routemap_cmd_vtysh, 
+       "no redistribute ospf6 route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, no_area_default_cost_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the summary-default cost of a NSSA or stub area\n"
+       "Stub's advertised default summary cost\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_summary_cmd_vtysh, 
+       "show ip prefix-list summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Summary of prefix lists\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_id_cmd_vtysh, 
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*) (A.B.C.D|*|dump|summary)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Link State ID\n"
+       "All Link State ID\n"
+       "Dump raw LSA data in Hex\n"
+       "show summary of LSA\n"
+       )
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_summary_name_cmd_vtysh, 
+       "show ipv6 prefix-list summary WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Summary of prefix lists\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, set_aggregator_as_cmd_vtysh, 
+       "set aggregator as <1-65535> A.B.C.D", 
+       "Set values in destination routing protocol\n"
+       "BGP aggregator attribute\n"
+       "AS number of aggregator\n"
+       "AS number\n"
+       "IP address of aggregator\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_address_prefix_list_cmd_vtysh, 
+       "match ip address prefix-list WORD", 
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_backdoor_cmd_vtysh, 
+       "no network A.B.C.D mask A.B.C.D backdoor", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_BGPD, no_match_origin_val_cmd_vtysh, 
+       "no match origin (egp|igp|incomplete)", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+
+DEFSH (VTYSH_RIPD, rip_network_cmd_vtysh, 
+       "network (A.B.C.D/M|WORD)", 
+       "Enable routing on an IP network\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_cost_cmd_vtysh, 
+       "ip ospf cost <1-65535>", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Cost")
+
+DEFSH (VTYSH_BGPD, ipv6_aggregate_address_cmd_vtysh, 
+       "aggregate-address X:X::X:X/M", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_cmd_vtysh, 
+       "clear bgp <1-65535>", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_intra_inter_cmd_vtysh, 
+       "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_cost_cmd_vtysh, 
+       "ospf cost <1-65535>", 
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Cost")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_cmd_vtysh, 
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_metric_routemap_cmd_vtysh, 
+       "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, area_range_subst_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "configure OSPF area range for route summarization\n"
+       "area range prefix\n"
+       "announce area range as another prefix\n"
+       "network prefix to be announced instead of range\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_cmd_vtysh, 
+       "show ipv6 mbgp X:X::X:X/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "MBGP information\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_other_config_flag_cmd_vtysh, 
+       "no ipv6 nd other-config-flag", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Other statefull configuration flag\n")
+
+DEFSH (VTYSH_RIPD, no_key_cmd_vtysh, 
+       "no key <0-2147483647>", 
+       "Negate a command or set its defaults\n"
+       "Delete a key\n"
+       "Key identifier number\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_ge_cmd_vtysh, 
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged4_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_zebra_cmd_vtysh, 
+       "no debug ripng zebra", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng and zebra communication\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_weight_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Set default weight for routes from this neighbor\n"
+       "default weight\n")
+
+DEFSH (VTYSH_RIPD, no_rip_default_information_originate_cmd_vtysh, 
+       "no default-information originate", 
+       "Negate a command or set its defaults\n"
+       "Control distribution of default route\n"
+       "Distribute a default route\n")
+
+DEFSH (VTYSH_BGPD, match_community_exact_cmd_vtysh, 
+       "match community (<1-99>|<100-199>|WORD) exact-match", 
+       "Match values from routing table\n"
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n"
+       "Do exact matching of communities\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_in_cmd_vtysh, 
+       "clear bgp <1-65535> in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_host_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "A single destination host\n"
+       "Destination address\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_network_cmd_vtysh, 
+       "network X:X::X:X/M", 
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_preference_cmd_vtysh, 
+
+       "ip irdp preference <0-2147483647>", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n"
+       "Set default preference level for this interface\n"
+       "Preference level\n")
+
+DEFSH (VTYSH_BGPD, bgp_fast_external_failover_cmd_vtysh, 
+       "bgp fast-external-failover", 
+       "BGP information\n"
+       "Immediately reset session if a link to a directly connected external peer goes down\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_list_cmd_vtysh, 
+       "show ipv6 mbgp prefix-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the prefix-list\n"
+       "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_cmd_vtysh, 
+       "network A.B.C.D mask A.B.C.D", 
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_md5_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(message-digest-key|) <1-255> md5 KEY", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n"
+       "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, show_bgp_cmd_vtysh, 
+       "show bgp", 
+       "Show running system information\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_backdoor_cmd_vtysh, 
+       "network A.B.C.D mask A.B.C.D backdoor", 
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_authentication_string_cmd_vtysh, 
+       "ip rip authentication string LINE", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n"
+       "Authentication string\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_cmd_vtysh, 
+       "show ipv6 ospf6 interface", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Interface infomation\n"
+       )
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_pref_cmd_vtysh, 
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Distance value for this route\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_none_cmd_vtysh, 
+       "no set community none", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP community attribute\n"
+       "No community attribute\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_instance_summary_cmd_vtysh, 
+       "show bgp view WORD summary", 
+       "Show running system information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "View name\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_all_cmd_vtysh, 
+       "no ip extcommunity-list (<1-99>|<100-199>)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Extended Community list number (standard)\n"
+       "Extended Community list number (expanded)\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_network_route_map_cmd_vtysh, 
+       "network X:X::X:X/M route-map WORD", 
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_metric_cmd_vtysh, 
+       "redistribute connected metric <0-16>", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_ge_le_cmd_vtysh, 
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_authentication_key_cmd_vtysh, 
+       "ip ospf authentication-key AUTH_KEY", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "The OSPF password (key)")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_other_config_flag_cmd_vtysh, 
+       "ipv6 nd other-config-flag", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Other statefull configuration flag\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_advertised_route_cmd_vtysh, 
+       "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_addr_cmd_vtysh, 
+       "ip ospf authentication A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ip_prefix_list_name_prefix_cmd_vtysh, 
+       "clear ip prefix-list WORD A.B.C.D/M", 
+       "Reset functions\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_client_to_client_reflection_cmd_vtysh, 
+       "bgp client-to-client reflection", 
+       "BGP specific commands\n"
+       "Configure client to client route reflection\n"
+       "reflection of routes allowed\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_soft_in_cmd_vtysh, 
+       "clear bgp external soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_routemap_cmd_vtysh, 
+       "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_summary_as_set_cmd_vtysh, 
+       "no aggregate-address A.B.C.D A.B.C.D summary-only as-set", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_tags_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Display BGP tags for prefixes\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_soo_cmd_vtysh, 
+       "no set extcommunity soo", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP extended community attribute\n"
+       "Site-of-Origin extended community\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_exact_cmd_vtysh, 
+       "access-list WORD (deny|permit) A.B.C.D/M exact-match", 
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n"
+       "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_route_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_cmd_vtysh, 
+       "clear bgp ipv6 *", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, bgp_confederation_peers_cmd_vtysh, 
+       "bgp confederation peers .<1-65535>", 
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "Peer ASs in BGP confederation\n"
+       "AS number\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_soo_val_cmd_vtysh, 
+       "no set extcommunity soo .ASN:nn_or_IP-address:nn", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP extended community attribute\n"
+       "Site-of-Origin extended community\n"
+       "VPN extended community\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_routemap_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_cost_addr_cmd_vtysh, 
+       "ip ospf cost <1-65535> A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Cost\n"
+       "Address of interface")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_in_cmd_vtysh, 
+       "clear bgp ipv6 external soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, show_ip_rip_cmd_vtysh, 
+       "show ip rip", 
+       "Show running system information\n"
+       "IP information\n"
+       "Show RIP routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_in_cmd_vtysh, 
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, show_debugging_rip_cmd_vtysh, 
+       "show debugging rip", 
+       "Show running system information\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_route_map_cmd_vtysh, 
+       "no network A.B.C.D mask A.B.C.D route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, set_local_pref_cmd_vtysh, 
+       "set local-preference <0-4294967295>", 
+       "Set values in destination routing protocol\n"
+       "BGP local preference path attribute\n"
+       "Preference value\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_activate_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "activate", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Enable the Address Family for this Neighbor\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_metric_cmd_vtysh, 
+       "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_ZEBRA, no_debug_zebra_kernel_cmd_vtysh, 
+       "no debug zebra kernel", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra between kernel interface\n")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_global_val_cmd_vtysh, 
+       "no set ipv6 next-hop global X:X::X:X", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "IPv6 information\n"
+       "IPv6 next-hop address\n"
+       "IPv6 global address\n"
+       "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_in_cmd_vtysh, 
+       "clear bgp ipv6 * soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community4_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_RIPD, no_rip_split_horizon_cmd_vtysh, 
+       "no ip split-horizon", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Perform split horizon\n")
+
+DEFSH (VTYSH_BGPD, neighbor_local_as_no_prepend_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535> no-prepend", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Specify a local-as number\n"
+       "AS number used as local AS\n"
+       "Do not prepend local-as to updates from ebgp peers\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_routemap_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_as_set_cmd_vtysh, 
+       "no aggregate-address A.B.C.D A.B.C.D as-set", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_inter_cmd_vtysh, 
+       "distance ospf external <1-255> inter-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_month_day_month_day_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_BGPD, no_set_originator_id_val_cmd_vtysh, 
+       "no set originator-id A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP originator ID attribute\n"
+       "IP address of originator\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh, 
+       "show ip bgp vpnv4 all neighbors A.B.C.D routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_routemap_cmd_vtysh, 
+       "no redistribute bgp metric <0-16> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_routemap_cmd_vtysh, 
+       "default-information originate route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_list_exact_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_remark_cmd_vtysh, 
+       "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", 
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_router_id_cmd_vtysh, 
+       "no bgp router-id", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Override configured router identifier\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_all_interval_cmd_vtysh, 
+       "dump bgp all PATH INTERVAL", 
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump all BGP packets\n"
+       "Output filename\n"
+       "Interval of output\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_filter_list_cmd_vtysh, 
+       "show ipv6 mbgp filter-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_updates_cmd_vtysh, 
+       "dump bgp updates PATH", 
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump BGP updates only\n"
+       "Output filename\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_backdoor_cmd_vtysh, 
+       "no network A.B.C.D/M backdoor", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh, 
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_in_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X) soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPF6D, redistribute_ospf6_cmd_vtysh, 
+       "redistribute ospf6", 
+       "Redistribute control\n"
+       "OSPF6 route\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_le_cmd_vtysh, 
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_cmd_vtysh, 
+       "no ip ospf dead-interval", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_le_cmd_vtysh, 
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPF6D, router_id_cmd_vtysh, 
+       "router-id ROUTER_ID", 
+       "Configure ospf Router-ID.\n"
+       "specify by IPv4 address notation(e.g. 0.0.0.0)\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_med2_cmd_vtysh, 
+       "bgp bestpath med confed missing-as-worst", 
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_in_cmd_vtysh, 
+       "clear bgp ipv6 * in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community3_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_standard2_cmd_vtysh, 
+       "ip extcommunity-list <1-99> (deny|permit)", 
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Extended Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFSH (VTYSH_OSPFD, passive_interface_addr_cmd_vtysh, 
+       "passive-interface IFNAME A.B.C.D", 
+       "Suppress routing updates on an interface\n"
+       "Interface's name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_ebgp_multihop_ttl_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Allow EBGP neighbors not on directly connected networks\n"
+       "maximum hop count\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_longer_cmd_vtysh, 
+       "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_peer_group_cmd_vtysh, 
+       "no neighbor WORD peer-group", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor tag\n"
+       "Configure peer-group\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_ifname_cmd_vtysh, 
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_RIPD, rip_distance_source_access_list_cmd_vtysh, 
+       "distance <1-255> A.B.C.D/M WORD", 
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_advertise_prefix_list_cmd_vtysh, 
+       "ipv6 ospf6 advertise prefix-list WORD", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Advertising options\n"
+       "Filter prefix using prefix-list\n"
+       "Prefix list name\n"
+       )
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_transmitdelay_cmd_vtysh, 
+       "ipv6 ospf6 transmit-delay TRANSMITDELAY", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Link state transmit delay\n"
+       "<1-65535> Seconds\n"
+       )
+
+DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n")
+
+DEFSH (VTYSH_BGPD, vpnv4_network_cmd_vtysh, 
+       "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", 
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Specify Route Distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "BGP tag\n"
+       "tag value\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_addr_cmd_vtysh, 
+       "show ipv6 route X:X::X:X", 
+       "Show running system information\n"
+       "IP information\n"
+       "IPv6 routing table\n"
+       "IPv6 Address\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbors_peer_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_nsm_cmd_vtysh, 
+       "debug ospf nsm", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Neighbor State Machine\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_message_digest_key_cmd_vtysh, 
+       "ip ospf message-digest-key <1-255> md5 KEY", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Use MD5 algorithm\n"
+       "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_metric_routemap_cmd_vtysh, 
+       "redistribute bgp metric <0-16> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, bgp_default_local_preference_cmd_vtysh, 
+       "bgp default local-preference <0-4294967295>", 
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "local preference (higher=more preferred)\n"
+       "Configure default local preference value\n")
+
+DEFSH (VTYSH_RIPD, rip_distance_source_cmd_vtysh, 
+       "distance <1-255> A.B.C.D/M", 
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_le_cmd_vtysh, 
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_regexp_cmd_vtysh, 
+       "show bgp regexp .LINE", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_regexp_cmd_vtysh, 
+       "show ipv6 bgp regexp .LINE", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_priority_cmd_vtysh, 
+       "no ip ospf priority", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_set_ip_nexthop_cmd_vtysh, 
+       "no set ip next-hop", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "IP information\n"
+       "Next hop address\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_dead_interval_addr_cmd_vtysh, 
+       "ip ospf dead-interval <1-65535> A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Seconds\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_name_seq_cmd_vtysh, 
+       "show ipv6 prefix-list WORD seq <1-4294967295>", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_cmd_vtysh, 
+       "ipv6 access-list WORD (deny|permit) X:X::X:X/M", 
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_cmd_vtysh, 
+       "clear ip bgp external", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n")
+
+DEFSH (VTYSH_OSPFD, no_area_authentication_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) authentication", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Enable authentication\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_ge_le_cmd_vtysh, 
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_set_aspath_prepend_val_cmd_vtysh, 
+       "no set as-path prepend .<1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "Prepend string for a BGP AS-path attribute\n"
+       "Prepend to the as-path\n"
+       "AS number\n")
+
+DEFSH (VTYSH_OSPFD, area_stub_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) stub", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_cmd_vtysh, 
+       "show ipv6 ospf6 database", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "LSA Database\n"
+       )
+
+DEFSH (VTYSH_RIPD, no_rip_default_metric_val_cmd_vtysh, 
+       "no default-metric <1-16>", 
+       "Negate a command or set its defaults\n"
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_cmd_vtysh, 
+       "show ip bgp A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_in_cmd_vtysh, 
+       "clear bgp external in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_access_list_name_cmd_vtysh, 
+       "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", 
+       "Show running system information\n"
+       "IP information\n"
+       "List IP access lists\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n")
+
+DEFSH (VTYSH_BGPD, set_community_delete_cmd_vtysh, 
+       "set comm-list (<1-99>|<100-199>|WORD) delete", 
+       "Set values in destination routing protocol\n"
+       "set BGP community list (for deletion)\n"
+       "Community-list number (standard)\n"
+       "Communitly-list number (expanded)\n"
+       "Community-list name\n"
+       "Delete matching communities\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community3_exact_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_all_cmd_vtysh, 
+       "no ip community-list (WORD|<1-99>|<100-199>)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list name\n"
+       "Community list number (standard)\n"
+       "Community list number (expanded)\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_rip_cmd_vtysh, 
+       "redistribute rip", 
+       "Redistribute information from another routing protocol\n"
+       "Routing Information Protocol (RIP)\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_hellointerval_cmd_vtysh, 
+       "ipv6 ospf6 hello-interval HELLO_INTERVAL", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Time between HELLO packets\n"
+       "<1-65535> Seconds\n"
+       )
+
+DEFSH (VTYSH_RIPNGD, no_ripng_passive_interface_cmd_vtysh, 
+       "no passive-interface IFNAME", 
+       "Negate a command or set its defaults\n"
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_backdoor_cmd_vtysh, 
+       "no network A.B.C.D backdoor", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_ZEBRA, multicast_cmd_vtysh, 
+       "multicast", 
+       "Set multicast flag to interface\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_inter_intra_cmd_vtysh, 
+       "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_type_cmd_vtysh, 
+       "redistribute (kernel|connected|static|ospf|bgp)", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_host_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "A single destination host\n"
+       "Destination address\n")
+
+DEFSH (VTYSH_BGPD, bgp_config_type_cmd_vtysh, 
+       "bgp config-type (cisco|zebra)", 
+       "BGP information\n"
+       "Configuration type\n"
+       "cisco\n"
+       "zebra\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community2_exact_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_view_cmd_vtysh, 
+       "show ip bgp view WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "BGP view name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_address_mask_cmd_vtysh, 
+       "clear ip bgp dampening A.B.C.D A.B.C.D", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear route flap dampening information\n"
+       "Network to clear damping information\n"
+       "Network mask\n")
+
+DEFSH (VTYSH_OSPFD, area_authentication_message_digest_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) authentication message-digest", 
+       "OSPF area parameters\n"
+       "Enable authentication\n"
+       "Use message-digest authentication\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_advertise_cost_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area range for route summarization\n"
+       "area range prefix\n"
+       "advertise this range\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+DEFSH (VTYSH_RIPD, no_rip_neighbor_cmd_vtysh, 
+       "no neighbor A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_metric_routemap_cmd_vtysh, 
+       "redistribute connected metric <0-16> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_deterministic_med_cmd_vtysh, 
+       "no bgp deterministic-med", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Pick the best-MED path among paths advertised from the neighboring AS\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community4_exact_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_aggregator_as_cmd_vtysh, 
+       "no set aggregator as", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP aggregator attribute\n"
+       "AS number of aggregator\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_cmd_vtysh, 
+       "clear bgp ipv6 * soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param1_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf|rip|static)", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh, 
+       "clear ip bgp external ipv4 (unicast|multicast) soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_cmd_vtysh, 
+       "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_cmd_vtysh, 
+       "clear ip bgp * vpnv4 unicast soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_keepalive_cmd_vtysh, 
+       "debug bgp keepalives", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP keepalives\n")
+
+DEFSH (VTYSH_BGPD, no_router_bgp_cmd_vtysh, 
+       "no router bgp <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Enable a routing process\n"
+       "BGP information\n"
+       "AS number\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_ifname_pref_cmd_vtysh, 
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_transmit_delay_addr_cmd_vtysh, 
+       "no ip ospf transmit-delay A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_ge_cmd_vtysh, 
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_cmd_vtysh, 
+       "distance <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n")
+
+DEFSH (VTYSH_OSPFD, area_range_advertise_cost_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area range for route summarization\n"
+       "area range prefix\n"
+       "advertise this range\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_remark_cmd_vtysh, 
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_routemap_cmd_vtysh, 
+       "no redistribute connected route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged5_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_distance_ospf_cmd_vtysh, 
+       "no distance ospf", 
+       "Negate a command or set its defaults\n"
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "OSPF Distance\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighbor_cmd_vtysh, 
+       "show ipv6 ospf6 neighbor", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Neighbor list\n"
+       )
+
+DEFSH (VTYSH_RIPD, key_string_cmd_vtysh, 
+       "key-string LINE", 
+       "Set key string\n"
+       "The key\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_enforce_multihop_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Enforce EBGP neighbors perform multihop\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_events_cmd_vtysh, 
+       "debug ripng events", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng events\n")
+
+DEFSH (VTYSH_OSPF6D, no_redistribute_ospf6_cmd_vtysh, 
+       "no redistribute ospf6", 
+       "Negate a command or set its defaults\n"
+       "Redistribute control\n"
+       "OSPF6 route\n")
+
+DEFSH (VTYSH_BGPD, neighbor_description_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Neighbor specific description\n"
+       "Up to 80 characters describing this neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_pref_cmd_vtysh, 
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_packet_send_recv_cmd_vtysh, 
+       "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", 
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail information\n")
+
+DEFSH (VTYSH_OSPFD, area_range_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area range for route summarization\n"
+       "area range prefix\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_le_ge_cmd_vtysh, 
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_mask_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_key_chain2_cmd_vtysh, 
+       "no ip rip authentication key-chain LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_cidr_only_cmd_vtysh, 
+       "show ip bgp cidr-only", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display only routes with non-natural netmasks\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_description_cmd_vtysh, 
+       "no ipv6 prefix-list WORD description", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_send_version_num_cmd_vtysh, 
+       "no ip rip send version (1|2)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "Version 1\n"
+       "Version 2\n")
+
+DEFSH (VTYSH_OSPFD, no_refresh_timer_cmd_vtysh, 
+       "no refresh timer", 
+       "Adjust refresh parameters\n"
+       "Unset refresh timer\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_routemap_cmd_vtysh, 
+       "redistribute ospf6 route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_ZEBRA, no_shutdown_if_cmd_vtysh, 
+       "no shutdown", 
+       "Negate a command or set its defaults\n"
+       "Shutdown the selected interface\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_in_cmd_vtysh, 
+       "clear ip bgp view WORD * soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_extcommunity_list_arg_cmd_vtysh, 
+       "show ip extcommunity-list (<1-199>|WORD)", 
+       "Show running system information\n"
+       "IP information\n"
+       "List extended-community list\n"
+       "Extcommunity-list number\n"
+       "Extcommunity-list name\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_exact_cmd_vtysh, 
+       "no access-list WORD (deny|permit) A.B.C.D/M exact-match", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n"
+       "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_in_cmd_vtysh, 
+       "clear ip bgp A.B.C.D soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_cost_addr_cmd_vtysh, 
+       "no ip ospf cost A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interface cost\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, rmap_onmatch_next_cmd_vtysh, 
+       "on-match next", 
+       "Exit policy on matches\n"
+       "Next clause\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_cmd_vtysh, 
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_enforce_multihop_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Enforce EBGP neighbors perform multihop\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_topology_router_cmd_vtysh, 
+       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Inter Area topology information\n"
+       "Specify Router-ID\n"
+       "Specify Router-ID\n"
+       "Detailed information\n"
+       )
+
+DEFSH (VTYSH_OSPFD, debug_ospf_packet_all_cmd_vtysh, 
+       "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp <1-65535> in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_match_aspath_cmd_vtysh, 
+       "no match as-path", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match BGP AS path list\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_events_cmd_vtysh, 
+       "no debug rip events", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP events\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_cmd_vtysh, 
+       "no network A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "Network number\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged5_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_RIPD, rip_default_information_originate_cmd_vtysh, 
+       "default-information originate", 
+       "Control distribution of default route\n"
+       "Distribute a default route\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_abr_type_cmd_vtysh, 
+       "no ospf abr-type (cisco|ibm|shortcut)", 
+       "Negate a command or set its defaults\n"
+       "OSPF specific commands\n"
+       "Set OSPF ABR type\n"
+       "Alternative ABR,  cisco implementation\n"
+       "Alternative ABR,  IBM implementation\n"
+       "Shortcut ABR\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_rmap_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_transmit_delay_cmd_vtysh, 
+       "no ospf transmit-delay", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_remark_cmd_vtysh, 
+       "ipv6 access-list WORD remark .LINE", 
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_detail_cmd_vtysh, 
+       "show ipv6 prefix-list detail", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Detail of prefix lists\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_standard_cmd_vtysh, 
+       "ip extcommunity-list <1-99> (deny|permit) .AA:NN", 
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Extended Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_reachable_time_cmd_vtysh, 
+       "no ipv6 nd reachable-time", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Reachable time\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community3_exact_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_ge_le_cmd_vtysh, 
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_cmd_vtysh, 
+       "no ip ospf retransmit-interval", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_summary_cmd_vtysh, 
+       "aggregate-address A.B.C.D A.B.C.D as-set summary-only", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_cmd_vtysh, 
+       "no aggregate-address A.B.C.D A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_longer_cmd_vtysh, 
+       "show ip bgp A.B.C.D/M longer-prefixes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_BGPD, set_metric_cmd_vtysh, 
+       "set metric (<0-4294967295>|<+/-metric>)", 
+       "Set values in destination routing protocol\n"
+       "Metric value for destination routing protocol\n"
+       "Metric value\n"
+       "Add or subtract metric\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_routes_cmd_vtysh, 
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_description_arg_cmd_vtysh, 
+       "no ip prefix-list WORD description .LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbors_cmd_vtysh, 
+       "show ip bgp neighbors", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_BGPD, neighbor_advertise_interval_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Minimum interval between sending BGP routing updates\n"
+       "time in seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_cmd_vtysh, 
+       "clear ip bgp external soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_remove_private_as_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Remove private AS number from outbound updates\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_send_version_cmd_vtysh, 
+       "no ip rip send version", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_in_prefix_filter_cmd_vtysh, 
+       "clear bgp external in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_route_cmd_vtysh, 
+       "show ip bgp A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ipv6_prefix_list_name_cmd_vtysh, 
+       "clear ipv6 prefix-list WORD", 
+       "Reset functions\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_timers_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "timers", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP per neighbor timers\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_in_cmd_vtysh, 
+       "clear ip bgp peer-group WORD soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_routemap_cmd_vtysh, 
+       "default-information originate always metric-type (1|2) route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_expanded_cmd_vtysh, 
+       "ip extcommunity-list <100-199> (deny|permit) .LINE", 
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Extended Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_exact_cmd_vtysh, 
+       "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", 
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n"
+       "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, show_ip_community_list_arg_cmd_vtysh, 
+       "show ip community-list (<1-199>|WORD)", 
+       "Show running system information\n"
+       "IP information\n"
+       "List community-list\n"
+       "Community-list number\n"
+       "Community-list name\n")
+
+DEFSH (VTYSH_BGPD, bgp_timers_cmd_vtysh, 
+       "timers bgp <0-65535> <0-65535>", 
+       "Adjust routing timers\n"
+       "BGP timers\n"
+       "Keepalive interval\n"
+       "Holdtime\n")
+
+DEFSH (VTYSH_RIPD, rip_neighbor_cmd_vtysh, 
+       "neighbor A.B.C.D", 
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_prefix_first_match_cmd_vtysh, 
+       "show ipv6 prefix-list WORD X:X::X:X/M first-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "First matched prefix\n")
+
+DEFSH (VTYSH_BGPD, neighbor_shutdown_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Administratively shut down this neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_fsm_cmd_vtysh, 
+       "no debug bgp fsm", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "Finite State Machine\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_in_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535> soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_weight_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Set default weight for routes from this neighbor\n"
+       "default weight\n")
+
+DEFSH (VTYSH_BGPD, neighbor_transparent_nexthop_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "transparent-nexthop", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Do not change nexthop even peer is EBGP peer\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_cmd_vtysh, 
+       "clear ip bgp A.B.C.D soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh, 
+       "show ip bgp vpnv4 all neighbors A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_list_cmd_vtysh, 
+       "show ipv6 bgp community-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh, 
+       "clear ip bgp A.B.C.D vpnv4 unicast soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_le_cmd_vtysh, 
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_med2_cmd_vtysh, 
+       "no bgp bestpath med confed missing-as-worst", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_priority_cmd_vtysh, 
+       "no ospf priority", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Router priority\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_natural_cmd_vtysh, 
+       "network A.B.C.D", 
+       "Specify a network to announce via BGP\n"
+       "Network number\n")
+
+DEFSH (VTYSH_OSPFD, area_stub_nosum_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) stub no-summary", 
+       "OSPF stub parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n"
+       "Do not inject inter-area routes into stub\n")
+
+DEFSH (VTYSH_BGPD, no_synchronization_cmd_vtysh, 
+       "no synchronization", 
+       "Negate a command or set its defaults\n"
+       "Perform IGP synchronization\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_not_advertise_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "OSPF area range for route DoNotAdvertise\n"
+       "area range prefix\n"
+       "do not advertise this range\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, set_ip_nexthop_cmd_vtysh, 
+       "set ip next-hop A.B.C.D", 
+       "Set values in destination routing protocol\n"
+       "IP information\n"
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+DEFSH (VTYSH_RIPD, no_rip_version_val_cmd_vtysh, 
+       "no version <1-2>", 
+       "Negate a command or set its defaults\n"
+       "Set routing protocol version\n"
+       "version\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_scan_time_cmd_vtysh, 
+       "no bgp scan-time", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Configure background scanner interval\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_cmd_vtysh, 
+       "no redistribute connected metric", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n")
+
+DEFSH (VTYSH_OSPF6D, debug_ospf6_all_cmd_vtysh, 
+       "debug ospf6 all", 
+       "Debugging functions (see also 'undebug')\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Turn on ALL OSPFv3 debugging\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_key_addr_cmd_vtysh, 
+       "no ip ospf authentication-key A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_route_cmd_vtysh, 
+       "no route IPV6ADDR", 
+       "Negate a command or set its defaults\n"
+       "Static route setup\n"
+       "Delete static RIPng route announcement\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_nsm_sub_cmd_vtysh, 
+       "debug ospf nsm (status|events|timers)", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Neighbor State Machine\n"
+       "NSM Status Information\n"
+       "NSM Event Information\n"
+       "NSM Timer Information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh, 
+       "clear ip bgp <1-65535> vpnv4 unicast soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_all_cmd_vtysh, 
+       "no debug all bgp", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "Enable all debugging\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh, 
+       "clear ip bgp * vpnv4 unicast soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance_cmd_vtysh, 
+       "no distance bgp <1-255> <1-255> <1-255>", 
+       "Negate a command or set its defaults\n"
+       "Define an administrative distance\n"
+       "BGP distance\n"
+       "Distance for routes external to the AS\n"
+       "Distance for routes internal to the AS\n"
+       "Distance for local routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh, 
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, no_rip_timers_cmd_vtysh, 
+       "no timers basic", 
+       "Negate a command or set its defaults\n"
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_passive_cmd_vtysh, 
+       "ipv6 ospf6 passive", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "passive interface: No Adjacency will be formed on this I/F\n"
+       )
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_external_intra_cmd_vtysh, 
+       "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_metric_routemap_cmd_vtysh, 
+       "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_events_cmd_vtysh, 
+       "no debug ripng events", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng events\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_duration_month_day_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_metric_routemap_cmd_vtysh, 
+       "redistribute ospf6 metric <0-16> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_match_metric_cmd_vtysh, 
+       "no match metric", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match metric of route\n")
+
+DEFSH (VTYSH_RIPD, match_ip_next_hop_cmd_vtysh, 
+       "match ip next-hop WORD", 
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match next-hop address of route\n"
+       "IP access-list name\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_cmd_vtysh, 
+       "ip irdp", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_summary_only_cmd_vtysh, 
+       "aggregate-address A.B.C.D/M summary-only", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535> in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_route_map_cmd_vtysh, 
+       "no network A.B.C.D/M route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_neighbors_peer_cmd_vtysh, 
+       "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "View name\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_cmd_vtysh, 
+       "no redistribute connected", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_summary_as_set_cmd_vtysh, 
+       "aggregate-address A.B.C.D/M summary-only as-set", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_in_cmd_vtysh, 
+       "clear ip bgp external in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_packet_direct_cmd_vtysh, 
+       "no debug rip packet (recv|send)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP packet\n"
+       "RIP option set for receive packet\n"
+       "RIP option set for send packet\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community2_exact_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_neighbor_nexthop_self_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Disable the next hop calculation for this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, area_range_not_advertise_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "OSPF area range for route DoNotAdvertise\n"
+       "area range prefix\n"
+       "do not advertise this range\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_mode_type_cmd_vtysh, 
+       "no ip rip authentication mode (md5|text)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_summary_cmd_vtysh, 
+       "show ipv6 prefix-list summary", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Summary of prefix lists\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_any_cmd_vtysh, 
+       "no access-list WORD (deny|permit) any", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_med3_cmd_vtysh, 
+       "bgp bestpath med missing-as-worst confed", 
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Treat missing MED as the least preferred one\n"
+       "Compare MED among confederation paths\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community4_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_retransmit_interval_addr_cmd_vtysh, 
+       "ip ospf retransmit-interval <3-65535> A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Seconds\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD, match_ip_address_cmd_vtysh, 
+       "match ip address WORD", 
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match address of route\n"
+       "IP access-list name\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_deadinterval_cmd_vtysh, 
+       "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Interval after which a neighbor is declared dead\n"
+       "<1-65535> Seconds\n"
+       )
+
+DEFSH (VTYSH_OSPFD, debug_ospf_zebra_sub_cmd_vtysh, 
+       "debug ospf zebra (interface|redistribute)", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Zebra information\n"
+       "Zebra interface\n"
+       "Zebra redistribute\n")
+
+DEFSH (VTYSH_BGPD, match_aspath_cmd_vtysh, 
+       "match as-path WORD", 
+       "Match values from routing table\n"
+       "Match BGP AS path list\n"
+       "AS path access-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_cidr_only_cmd_vtysh, 
+       "show ip bgp flap-statistics cidr-only", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "Display only routes with non-natural netmasks\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_description_arg_cmd_vtysh, 
+       "no ipv6 prefix-list WORD description .LINE", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_ra_interval_cmd_vtysh, 
+       "no ipv6 nd ra-interval", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_cmd_vtysh, 
+       "clear ip bgp * soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_metric_routemap_cmd_vtysh, 
+       "redistribute static metric <0-16> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_route_map_cmd_vtysh, 
+       "show bgp ipv6 route-map WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_prefix_list_cmd_vtysh, 
+       "no match ip next-hop prefix-list", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_set_peer_group_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Member of the peer-group\n"
+       "peer-group name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_routes_cmd_vtysh, 
+       "show bgp neighbors (A.B.C.D|X:X::X:X) routes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_prefix_cmd_vtysh, 
+       "show ipv6 ospf6 route (X::X|detail)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Routing table\n"
+       "match IPv6 prefix\n"
+       )
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_cmd_vtysh, 
+       "redistribute bgp", 
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_multicast_cmd_vtysh, 
+       "ip irdp multicast", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n"
+       "Send IRDP advertisement to the multicast address\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_mask_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authtype_authkey_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(authentication-key|)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n"
+       "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, debug_bgp_events_cmd_vtysh, 
+       "debug bgp events", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP events\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param1_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_cmd_vtysh, 
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_packet_cmd_vtysh, 
+       "debug ripng packet", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_out_cmd_vtysh, 
+       "clear ip bgp <1-65535> out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_cmd_vtysh, 
+       "no redistribute static metric", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n")
+
+DEFSH (VTYSH_OSPFD, no_interface_ip_ospf_authentication_cmd_vtysh, 
+       "no ip ospf authentication", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_routemap_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community2_exact_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, no_neighbor_priority_pollinterval_cmd_vtysh, 
+       "no neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Priority\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_soft_cmd_vtysh, 
+       "clear bgp external soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_aggregate_address_cmd_vtysh, 
+       "no aggregate-address X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_in_prefix_filter_cmd_vtysh, 
+       "clear bgp * in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_timers_connect_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "timers connect <0-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "BGP per neighbor timers\n"
+       "BGP connect timer\n"
+       "Connect timer\n")
+
+DEFSH (VTYSH_OSPFD, no_auto_cost_reference_bandwidth_cmd_vtysh, 
+       "no auto-cost reference-bandwidth", 
+       "Negate a command or set its defaults\n"
+       "Calculate OSPF interface cost according to bandwidth\n"
+       "Use reference bandwidth method to assign OSPF cost\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_cmd_vtysh, 
+       "show ip bgp", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_message_digest_key_addr_cmd_vtysh, 
+       "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Use MD5 algorithm\n"
+       "The OSPF password (key)"
+       "Address of interface")
+
+DEFSH (VTYSH_BGPD, show_debugging_bgp_cmd_vtysh, 
+       "show debugging bgp", 
+       "Show running system information\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_OSPFD|VTYSH_OSPF6D, ospf6_routemap_set_metric_type_cmd_vtysh, 
+       "set metric-type (type-1|type-2)", 
+       "Set value\n"
+       "Type of metric\n"
+       "OSPF6 external type 1 metric\n"
+       "OSPF6 external type 2 metric\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_summary_only_cmd_vtysh, 
+       "aggregate-address A.B.C.D A.B.C.D summary-only", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_passive_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "passive", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Don't send open messages to this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_cmd_vtysh, 
+       "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", 
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n"
+       "Wildcard bits\n")
+
+DEFSH (VTYSH_ZEBRA, no_zebra_interface_cmd_vtysh, 
+       "no interface IFNAME", 
+       "Delete a pseudo interface's configuration\n"
+       "Interface's name\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_zebra_cmd_vtysh, 
+       "debug rip zebra", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP and ZEBRA communication\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_mask_any_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_paths_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) paths", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Path information\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_metric_routemap_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_out_cmd_vtysh, 
+       "clear bgp peer-group WORD soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_area_filter_list_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Filter networks between OSPF areas\n"
+       "Filter prefixes between OSPF areas\n"
+       "Name of an IP prefix-list\n"
+       "Filter networks sent to this area\n"
+       "Filter networks sent from this area\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_route_cmd_vtysh, 
+       "show ipv6 bgp X:X::X:X", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_natural_backdoor_cmd_vtysh, 
+       "network A.B.C.D backdoor", 
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_RIPD, rip_route_cmd_vtysh, 
+       "route A.B.C.D/M", 
+       "RIP static route configuration\n"
+       "IP prefix <network>/<length>\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_cost_cmd_vtysh, 
+       "no ospf cost", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Interface cost\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_soft_out_cmd_vtysh, 
+       "clear bgp * soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_sequence_number_cmd_vtysh, 
+       "ipv6 prefix-list sequence-number", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_packet_cmd_vtysh, 
+       "no debug rip packet", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP packet\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_prefix_longer_cmd_vtysh, 
+       "show ip route A.B.C.D/M longer-prefixes", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Show route matching the specified Network/Mask pair only\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ipv6_access_list_name_cmd_vtysh, 
+       "show ipv6 access-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "List IPv6 access lists\n"
+       "IPv6 zebra access-list\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ripng_cmd_vtysh, 
+       "no redistribute ripng", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "RIPng route\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_val_cmd_vtysh, 
+       "no set community .AA:NN", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP community attribute\n"
+       "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_out_cmd_vtysh, 
+       "clear bgp peer-group WORD out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_prefix_longer_cmd_vtysh, 
+       "show ipv6 prefix-list WORD X:X::X:X/M longer", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Lookup longer prefix\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_metric_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authkey_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication-key|) AUTH_KEY", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_list_cmd_vtysh, 
+       "show ip bgp flap-statistics prefix-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "Display routes conforming to the prefix-list\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_aggregate_address_cmd_vtysh, 
+       "no aggregate-address X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "Delete aggregate RIPng route announcement\n"
+       "Aggregate network")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_retransmitinterval_cmd_vtysh, 
+       "ipv6 ospf6 retransmit-interval RXMTINTERVAL", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "<1-65535> Seconds\n"
+       )
+
+DEFSH (VTYSH_RIPD, debug_rip_packet_detail_cmd_vtysh, 
+       "debug rip packet (recv|send) detail", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP packet\n"
+       "RIP receive packet\n"
+       "RIP send packet\n"
+       "Detailed information display\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_protocol_cmd_vtysh, 
+       "show ip route (bgp|connected|kernel|ospf|rip|static)", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Connected\n"
+       "Kernel\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_client_to_client_reflection_cmd_vtysh, 
+       "no bgp client-to-client reflection", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Configure client to client route reflection\n"
+       "reflection of routes allowed\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_rmap_onmatch_next_cmd_vtysh, 
+       "no on-match next", 
+       "Negate a command or set its defaults\n"
+       "Exit policy on matches\n"
+       "Next clause\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_multiple_instance_cmd_vtysh, 
+       "no bgp multiple-instance", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "BGP multiple instance\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_nsm_sub_cmd_vtysh, 
+       "no debug ospf nsm (status|events|timers)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine\n"
+       "NSM Status Information\n"
+       "NSM Event Information\n"
+       "NSM Timer Information\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param2_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, bgp_distance_cmd_vtysh, 
+       "distance bgp <1-255> <1-255> <1-255>", 
+       "Define an administrative distance\n"
+       "BGP distance\n"
+       "Distance for routes external to the AS\n"
+       "Distance for routes internal to the AS\n"
+       "Distance for local routes\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_cmd_vtysh, 
+       "clear bgp peer-group WORD soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_any_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_attr_info_cmd_vtysh, 
+       "show ip bgp attribute-info", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "List all bgp attribute information\n")
+
+DEFSH (VTYSH_RIPNGD, no_default_information_originate_cmd_vtysh, 
+       "no default-information originate", 
+       "Negate a command or set its defaults\n"
+       "Default route information\n"
+       "Distribute default route\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_host_cmd_vtysh, 
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A single host address\n"
+       "Address to match\n")
+
+DEFSH (VTYSH_RIPD, show_ip_protocols_rip_cmd_vtysh, 
+       "show ip protocols", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing protocol process parameters and statistics\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_day_month_day_month_cmd_vtysh, 
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_topology_cmd_vtysh, 
+       "show ipv6 ospf6 topology", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Inter Area topology information\n"
+       )
+
+DEFSH (VTYSH_OSPFD, no_ospf_redistribute_source_cmd_vtysh, 
+       "no redistribute (kernel|connected|static|rip|bgp)", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_receive_version_cmd_vtysh, 
+       "ip rip receive version (1|2)", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_priority_addr_cmd_vtysh, 
+       "ip ospf priority <0-255> A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Priority\n"
+       "Address of interface")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_events_cmd_vtysh, 
+       "debug zebra events", 
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra events\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, match_metric_cmd_vtysh, 
+       "match metric <0-4294967295>", 
+       "Match values from routing table\n"
+       "Match metric of route\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_longer_cmd_vtysh, 
+       "show bgp ipv6 X:X::X:X/M longer-prefixes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_passive_cmd_vtysh, 
+       "no ipv6 ospf6 passive", 
+       "Negate a command or set its defaults\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "passive interface: No Adjacency will be formed on this I/F\n"
+       )
+
+DEFSH (VTYSH_RIPD, accept_lifetime_infinite_day_month_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Never expires")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged6_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Med attribute\n"
+       "Nexthop attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_area_import_list_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) import-list NAME", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Unset the filter for networks announced to other areas\n"
+       "Name of the access-list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_ge_cmd_vtysh, 
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_interface_ip_ospf_authentication_addr_cmd_vtysh, 
+       "no ip ospf authentication A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Address of interface")
+
+DEFSH (VTYSH_BGPD, neighbor_route_reflector_client_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Configure a neighbor as Route Reflector client\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_list_cmd_vtysh, 
+       "show bgp community-list WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ripng_cmd_vtysh, 
+       "redistribute ripng", 
+       "Redistribute information from another routing protocol\n"
+       "RIPng route\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_host_cmd_vtysh, 
+       "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", 
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A single host address\n"
+       "Address to match\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_metric_cmd_vtysh, 
+       "redistribute bgp metric <0-16>", 
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_OSPF6D|VTYSH_BGPD, match_ipv6_address_prefix_list_cmd_vtysh, 
+       "match ipv6 address prefix-list WORD", 
+       "Match values from routing table\n"
+       "IPv6 information\n"
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbor_received_prefix_filter_cmd_vtysh, 
+       "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_neighbors_cmd_vtysh, 
+       "show ip bgp view WORD neighbors", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "View name\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_OSPF6D, show_zebra_cmd_vtysh, 
+       "show zebra", 
+       "Show running system information\n"
+       "Zebra information\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_out_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X) out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_description_cmd_vtysh, 
+       "no ip prefix-list WORD description", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_forwarding_cmd_vtysh, 
+       "no ip forwarding", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Turn off IP forwarding")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_routemap_cmd_vtysh, 
+       "redistribute bgp route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_update_cmd_vtysh, 
+       "no debug bgp updates", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP updates\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_cmd_vtysh, 
+       "no redistribute ospf6", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_address_cmd_vtysh, 
+       "no ip address A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP Address (e.g. 10.0.0.1/8)")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_route_map_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) route-map WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_address_cmd_vtysh, 
+       "no ipv6 address X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IPv6 address (e.g. 3ffe:506::1/48)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_shutdown_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Administratively shut down this neighbor\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_string2_cmd_vtysh, 
+       "no ip rip authentication string LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n"
+       "Authentication string\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_network_cmd_vtysh, 
+       "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Network type\n"
+       "Specify OSPF broadcast multi-access network\n"
+       "Specify OSPF NBMA network\n"
+       "Specify OSPF point-to-multipoint network\n"
+       "Specify OSPF point-to-point network\n")
+
+DEFSH (VTYSH_BGPD, neighbor_send_community_type_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Send Community attribute to this neighbor\n"
+       "Send Standard and Extended Community attributes\n"
+       "Send Extended Community attributes\n"
+       "Send Standard Community attributes\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_cmd_vtysh, 
+       "no redistribute kernel metric", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_rmap_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf|rip|static) route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_le_cmd_vtysh, 
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp)", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_prefix_advertisement_cmd_vtysh, 
+       "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Valid lifetime in seconds\n"
+       "Preferred lifetime in seconds\n"
+       "On link flag\n"
+       "Autonomous address-configuration flag\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ipv6_access_list_cmd_vtysh, 
+       "show ipv6 access-list", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "List IPv6 access lists\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_override_capability_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Override capability negotiation result\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_update_cmd_vtysh, 
+       "undebug bgp updates", 
+       "Disable debugging functions (see also 'debug')\n"
+       "BGP information\n"
+       "BGP updates\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_packet_cmd_vtysh, 
+       "no debug ripng packet", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_pref_cmd_vtysh, 
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Distance value for this route\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_list_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes conforming to the prefix-list\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community2_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged6_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Med attribute\n"
+       "Nexthop attribute\n")
+
+DEFSH (VTYSH_OSPFD, no_timers_spf_cmd_vtysh, 
+       "no timers spf", 
+       "Negate a command or set its defaults\n"
+       "Adjust routing timers\n"
+       "OSPF SPF timers\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_filter_list_cmd_vtysh, 
+       "show ip bgp flap-statistics filter-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_routemap_cmd_vtysh, 
+       "no redistribute kernel route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_route_cmd_vtysh, 
+       "show ip bgp vpnv4 all A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_regexp_cmd_vtysh, 
+       "show bgp ipv6 regexp .LINE", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_OSPFD, no_passive_interface_addr_cmd_vtysh, 
+       "no passive-interface IFNAME A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Allow routing updates on an interface\n"
+       "Interface's name\n")
+
+DEFSH (VTYSH_OSPFD, ospf_authentication_key_cmd_vtysh, 
+       "ospf authentication-key AUTH_KEY", 
+       "OSPF interface commands\n"
+       "Authentication password (key)\n"
+       "The OSPF password (key)")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_priority_cmd_vtysh, 
+       "ipv6 ospf6 priority PRIORITY", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Router priority\n"
+       "<0-255> Priority\n"
+       )
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_md5_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(message-digest-key|) <1-255>", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPD, no_rip_distance_source_access_list_cmd_vtysh, 
+       "no distance <1-255> A.B.C.D/M WORD", 
+       "Negate a command or set its defaults\n"
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_router_id_cmd_vtysh, 
+       "no ospf router-id", 
+       "Negate a command or set its defaults\n"
+       "OSPF specific commands\n"
+       "router-id for the OSPF process\n")
+
+DEFSH (VTYSH_BGPD, bgp_bestpath_compare_router_id_cmd_vtysh, 
+       "bgp bestpath compare-routerid", 
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "Compare router-id for identical EBGP paths\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_val_cmd_vtysh, 
+       "no redistribute bgp metric <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community3_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_packet_direct_cmd_vtysh, 
+       "debug zebra packet (recv|send)", 
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_topology_router_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>|detail)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Shortest Path First tree information\n"
+       "Displays SPF topology table\n"
+       "Specify Router-ID\n"
+       "Specify Router-ID\n"
+       )
+
+DEFSH (VTYSH_OSPFD, no_router_id_cmd_vtysh, 
+       "no router-id", 
+       "Negate a command or set its defaults\n"
+       "router-id for the OSPF process\n")
+
+DEFSH (VTYSH_BGPD, set_ipv6_nexthop_global_cmd_vtysh, 
+       "set ipv6 next-hop global X:X::X:X", 
+       "Set values in destination routing protocol\n"
+       "IPv6 information\n"
+       "IPv6 next-hop address\n"
+       "IPv6 global address\n"
+       "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_RIPNGD, no_debug_ripng_packet_direct_cmd_vtysh, 
+       "no debug ripng packet (recv|send)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_infinite_month_day_cmd_vtysh, 
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Never expires")
+
+DEFSH (VTYSH_BGPD, no_set_local_pref_val_cmd_vtysh, 
+       "no set local-preference <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP local preference path attribute\n"
+       "Preference value\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_cmd_vtysh, 
+       "redistribute ospf6", 
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_any_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_local_as_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Specify a local-as number\n"
+       "AS number used as local AS\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_mask_host_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "A single destination host\n"
+       "Destination address\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_name_cmd_vtysh, 
+       "show ip prefix-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_prefix_cmd_vtysh, 
+       "show ipv6 route X:X::X:X/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "IPv6 routing table\n"
+       "IPv6 prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh, 
+       "clear ip bgp A.B.C.D vpnv4 unicast soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_cmd_vtysh, 
+       "no match ip next-hop", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match next-hop address of route\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_routemap_no_set_forwarding_cmd_vtysh, 
+       "no set forwarding-address X:X::X:X", 
+       "Negate a command or set its defaults\n"
+       "Set value\n"
+       "Forwarding Address\n"
+       "IPv6 Address\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community2_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_cost_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area range for route summarization\n"
+       "area range prefix\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_authentication_key_chain_cmd_vtysh, 
+       "ip rip authentication key-chain LINE", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_distribute_list_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Filter updates to/from this neighbor\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+
+DEFSH (VTYSH_ZEBRA, show_table_cmd_vtysh, 
+       "show table", 
+       "Show running system information\n"
+       "default routing table to use for all clients\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_metric_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authkey_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication-key|)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_cmd_vtysh, 
+       "show ipv6 prefix-list", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_prefix_longer_cmd_vtysh, 
+       "show ip prefix-list WORD A.B.C.D/M longer", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Lookup longer prefix\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_intra_external_cmd_vtysh, 
+       "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_med3_cmd_vtysh, 
+       "no bgp bestpath med missing-as-worst confed", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Treat missing MED as the least preferred one\n"
+       "Compare MED among confederation paths\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_packet_direct_cmd_vtysh, 
+       "debug ripng packet (recv|send)", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh, 
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_ZEBRA, ip_address_secondary_cmd_vtysh, 
+       "ip address A.B.C.D/M secondary", 
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Secondary IP address\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_out_cmd_vtysh, 
+       "clear ip bgp * soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh, 
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_cmd_vtysh, 
+       "clear ip bgp * ipv4 (unicast|multicast) soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh, 
+       "clear ip bgp * ipv4 (unicast|multicast) soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_day_month_day_month_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_cluster_id_cmd_vtysh, 
+       "no bgp cluster-id", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Configure Route-Reflector Cluster-id\n")
+
+DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_warning_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295> warning-only", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n"
+       "Only give warning message when limit is exceeded\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, no_area_stub_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) stub", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n")
+
+DEFSH (VTYSH_ZEBRA, no_debug_zebra_events_cmd_vtysh, 
+       "no debug zebra events", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra events\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_in_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_list_cmd_vtysh, 
+       "show ipv6 bgp prefix-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the prefix-list\n"
+       "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance2_cmd_vtysh, 
+       "no distance bgp", 
+       "Negate a command or set its defaults\n"
+       "Define an administrative distance\n"
+       "BGP distance\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_in_cmd_vtysh, 
+       "clear bgp ipv6 external WORD in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_set_aggregator_as_val_cmd_vtysh, 
+       "no set aggregator as <1-65535> A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP aggregator attribute\n"
+       "AS number of aggregator\n"
+       "AS number\n"
+       "IP address of aggregator\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_type_routemap_cmd_vtysh, 
+       "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_name_standard_cmd_vtysh, 
+       "ip community-list standard WORD (deny|permit) .AA:NN", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Add a standard community-list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_self_cmd_vtysh, 
+       "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") (self-originate|)", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n"
+       "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+       "Self-originated link states\n")
+
+DEFSH (VTYSH_BGPD, bgp_router_id_cmd_vtysh, 
+       "bgp router-id A.B.C.D", 
+       "BGP information\n"
+       "Override configured router identifier\n"
+       "Manually configured router identifier\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_forwarding_cmd_vtysh, 
+       "show ip forwarding", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP forwarding status\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_standard_cmd_vtysh, 
+       "ip community-list <1-99> (deny|permit) .AA:NN", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_ZEBRA, no_multicast_cmd_vtysh, 
+       "no multicast", 
+       "Negate a command or set its defaults\n"
+       "Unset multicast flag to interface\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_instance_ipv4_summary_cmd_vtysh, 
+       "show ip bgp view WORD ipv4 (unicast|multicast) summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X) soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_filter_list_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) filter-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_summary_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_metric_routemap_cmd_vtysh, 
+       "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_cmd_vtysh, 
+       "clear ip bgp external ipv4 (unicast|multicast) soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_out_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_route_cmd_vtysh, 
+       "show ip ospf route", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "OSPF routing table\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_args_addr_cmd_vtysh, 
+       "ip ospf authentication (null|message-digest) A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Use null authentication\n"
+       "Use message-digest authentication\n"
+       "Address of interface")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_args_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) (message-digest|null)", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_cmd_vtysh, 
+       "no network A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, no_ip_as_path_cmd_vtysh, 
+       "no ip as-path access-list WORD (deny|permit) .LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "BGP autonomous system path filter\n"
+       "Specify an access list name\n"
+       "Regular expression access list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, neighbor_distribute_list_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Filter updates to/from this neighbor\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_le_ge_cmd_vtysh, 
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_all_cmd_vtysh, 
+       "no ipv6 access-list WORD", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_name_expanded_cmd_vtysh, 
+       "ip community-list expanded WORD (deny|permit) .LINE", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Add an expanded community-list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, neighbor_timers_connect_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "timers connect <0-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "BGP per neighbor timers\n"
+       "BGP connect timer\n"
+       "Connect timer\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_address_cmd_vtysh, 
+       "ipv6 address X:X::X:X/M", 
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IPv6 address (e.g. 3ffe:506::1/48)\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_expanded_cmd_vtysh, 
+       "ip community-list <100-199> (deny|permit) .LINE", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD, rip_offset_list_ifname_cmd_vtysh, 
+       "offset-list WORD (in|out) <0-16> IFNAME", 
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n"
+       "Interface to match\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_longer_cmd_vtysh, 
+       "show ipv6 mbgp X:X::X:X/M longer-prefixes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_ism_sub_cmd_vtysh, 
+       "debug ospf ism (status|events|timers)", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine\n"
+       "ISM Status Information\n"
+       "ISM Event Information\n"
+       "ISM TImer Information\n")
+
+DEFSH (VTYSH_BGPD, neighbor_send_community_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Send Community attribute to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_route_map_cmd_vtysh, 
+       "show bgp route-map WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_route_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_route_ifname_pref_cmd_vtysh, 
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_updates_interval_cmd_vtysh, 
+       "dump bgp updates PATH INTERVAL", 
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump BGP updates only\n"
+       "Output filename\n"
+       "Interval of output\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_confederation_identifier_arg_cmd_vtysh, 
+       "no bgp confederation identifier <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "AS number\n"
+       "Set routing domain confederation AS\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_cmd_vtysh, 
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|dump|summary)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Dump raw LSA data in Hex\n"
+       "show summary of LSA\n"
+       )
+
+DEFSH (VTYSH_BGPD, no_neighbor_route_server_client_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Configure a neighbor as Route Server client\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_all_cmd_vtysh, 
+       "show ip bgp community", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n")
+
+DEFSH (VTYSH_OSPFD, ospf_message_digest_key_cmd_vtysh, 
+       "ospf message-digest-key <1-255> md5 KEY", 
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Use MD5 algorithm\n"
+       "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh, 
+       "clear ip bgp * ipv4 (unicast|multicast) soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_BGPD, no_match_community_cmd_vtysh, 
+       "no match community", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match BGP community list\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_type_metric_cmd_vtysh, 
+       "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_summary_cmd_vtysh, 
+       "show ip bgp vpnv4 all summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community2_exact_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_regexp_cmd_vtysh, 
+       "show ipv6 mbgp regexp .LINE", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the MBGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_delete_cmd_vtysh, 
+       "no set comm-list", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "set BGP community list (for deletion)\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_zebra_cmd_vtysh, 
+       "no debug ospf zebra", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Zebra information\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_packet_cmd_vtysh, 
+       "debug zebra packet", 
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_rip_cmd_vtysh, 
+       "no redistribute rip", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Routing Information Protocol (RIP)\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_type_cmd_vtysh, 
+       "default-information originate metric <0-16777214> metric-type (1|2)", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_out_cmd_vtysh, 
+       "clear ip bgp * ipv4 (unicast|multicast) out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, no_rip_version_cmd_vtysh, 
+       "no version", 
+       "Negate a command or set its defaults\n"
+       "Set routing protocol version\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_topology_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D topology", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Shortest Path First tree information\n"
+       "Displays SPF topology table\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_match_metric_val_cmd_vtysh, 
+       "no match metric <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match metric of route\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_cmd_vtysh, 
+       "show ip bgp flap-statistics A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_always_compare_med_cmd_vtysh, 
+       "bgp always-compare-med", 
+       "BGP specific commands\n"
+       "Allow comparing MED from different neighbors\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_out_cmd_vtysh, 
+       "clear bgp view WORD * soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param2_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPD, rip_offset_list_cmd_vtysh, 
+       "offset-list WORD (in|out) <0-16>", 
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_out_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535> out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_routes_cmd_vtysh, 
+       "dump bgp routes-mrt PATH", 
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump whole BGP routing table\n"
+       "Output filename\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authtype_md5_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) "
+       "(message-digest-key|)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n"
+       "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh, 
+       "no ipv6 ospf6 advertise prefix-list", 
+       "Negate a command or set its defaults\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Advertising options\n"
+       "Filter prefix using prefix-list\n"
+       )
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_route_ospf6_external_cmd_vtysh, 
+       "show ipv6 ospf6 route redistribute", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Routing Table\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "redistributing External information\n"
+       )
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh, 
+       "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPD, rip_passive_interface_cmd_vtysh, 
+       "passive-interface IFNAME", 
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_lsa_cmd_vtysh, 
+       "no debug ospf lsa", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Link State Advertisement\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_network_cmd_vtysh, 
+       "no network IF_OR_ADDR", 
+       "Negate a command or set its defaults\n"
+       "RIPng enable on specified interface or network.\n"
+       "Interface or address")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_type_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2)", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_soft_out_cmd_vtysh, 
+       "clear bgp external soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_standard_cmd_vtysh, 
+       "no ip extcommunity-list standard WORD (deny|permit) .AA:NN", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Specify standard extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_default_metric_cmd_vtysh, 
+       "no default-metric", 
+       "Negate a command or set its defaults\n"
+       "Set metric of redistributed routes\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_paths_cmd_vtysh, 
+       "show ip bgp paths", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Path information\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_advertised_route_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, match_ipv6_next_hop_cmd_vtysh, 
+       "match ipv6 next-hop X:X::X:X", 
+       "Match values from routing table\n"
+       "IPv6 information\n"
+       "Match IPv6 next-hop address of route\n"
+       "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_transmit_delay_cmd_vtysh, 
+       "ip ospf transmit-delay <1-65535>", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh, 
+       "clear ip bgp <1-65535> vpnv4 unicast soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, rip_redistribute_type_routemap_cmd_vtysh, 
+       "redistribute (kernel|connected|static|ospf|bgp) route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_filter_list_cmd_vtysh, 
+       "show ipv6 bgp filter-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_instance_ipv6_summary_cmd_vtysh, 
+       "show bgp view WORD ipv6 summary", 
+       "Show running system information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_ra_lifetime_cmd_vtysh, 
+       "no ipv6 nd ra-lifetime", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Router lifetime\n")
+
+DEFSH (VTYSH_OSPFD, no_area_export_list_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) export-list NAME", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Unset the filter for networks announced to other areas\n"
+       "Name of the access-list\n")
+
+DEFSH (VTYSH_BGPD, bgp_distance_source_cmd_vtysh, 
+       "distance <1-255> A.B.C.D/M", 
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_routes_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_set_origin_cmd_vtysh, 
+       "no set origin", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP origin code\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_delete_val_cmd_vtysh, 
+       "no set comm-list (<1-99>|<100-199>|WORD) delete", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "set BGP community list (for deletion)\n"
+       "Community-list number (standard)\n"
+       "Communitly-list number (expanded)\n"
+       "Community-list name\n"
+       "Delete matching communities\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_aspath_ignore_cmd_vtysh, 
+       "no bgp bestpath as-path ignore", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "AS-path attribute\n"
+       "Ignore as-path length in selecting a route\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_exact_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_scan_cmd_vtysh, 
+       "show ip bgp scan", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP scan status\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_suppress_ra_cmd_vtysh, 
+       "no ipv6 nd suppress-ra", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Suppress Router Advertisement\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_cluster_id_arg_cmd_vtysh, 
+       "no bgp cluster-id A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Configure Route-Reflector Cluster-id\n"
+       "Route-Reflector Cluster-id in IP address format\n")
+
+DEFSH (VTYSH_OSPFD, no_area_shortcut_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Deconfigure the area's shortcutting mode\n"
+       "Deconfigure enabled shortcutting through the area\n"
+       "Deconfigure disabled shortcutting through the area\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_passive_cmd_vtysh, 
+       "interface IFNAME area A.B.C.D passive", 
+       "Enable routing on an IPv6 interface\n"
+       "Interface name(e.g. ep0)\n"
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       "Suppress routing updates on an interface\n"
+      )
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_cmd_vtysh, 
+       "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n"
+       "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+       "Link State ID (as an IP address)\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_confederation_peers_cmd_vtysh, 
+       "no bgp confederation peers .<1-65535>", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "Peer ASs in BGP confederation\n"
+       "AS number\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_expanded_cmd_vtysh, 
+       "no ip extcommunity-list expanded WORD (deny|permit) .LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Specify expanded extcommunity-list\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_list_exact_cmd_vtysh, 
+       "show bgp community-list WORD exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_received_routes_cmd_vtysh, 
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_hello_interval_cmd_vtysh, 
+       "no ospf hello-interval", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n")
+
+DEFSH (VTYSH_BGPD, no_set_weight_cmd_vtysh, 
+       "no set weight", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP weight for routing table\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_int_detail_cmd_vtysh, 
+       "show ip ospf neighbor A.B.C.D detail", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Neighbor list\n"
+       "Interface address\n"
+       "detail of all neighbors")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_list_cmd_vtysh, 
+       "show bgp ipv6 community-list WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_in_prefix_filter_cmd_vtysh, 
+       "clear bgp peer-group WORD in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, set_ecommunity_rt_cmd_vtysh, 
+       "set extcommunity rt .ASN:nn_or_IP-address:nn", 
+       "Set values in destination routing protocol\n"
+       "BGP extended community attribute\n"
+       "Route Target extened communityt\n"
+       "VPN extended community\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_description_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Neighbor specific description\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_le_cmd_vtysh, 
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_md5_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(message-digest-key|) <1-255> md5 KEY", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_forwarding_cmd_vtysh, 
+       "no ipv6 forwarding", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Doesn't forward IPv6 protocol packet")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, ospf_router_id_cmd_vtysh, 
+       "ospf router-id A.B.C.D", 
+       "OSPF specific commands\n"
+       "router-id for the OSPF process\n"
+       "OSPF router-id in IP address format\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community_exact_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_neighbor_capability_orf_prefix_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Advertise capability to the peer\n"
+       "Advertise ORF capability to the peer\n"
+       "Advertise prefixlist ORF capability to this neighbor\n"
+       "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+       "Capability to RECEIVE the ORF from this neighbor\n"
+       "Capability to SEND the ORF to this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_hello_interval_addr_cmd_vtysh, 
+       "ip ospf hello-interval <1-65535> A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Seconds\n"
+       "Address of interface")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_summary_only_cmd_vtysh, 
+       "no aggregate-address A.B.C.D A.B.C.D summary-only", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_intra_cmd_vtysh, 
+       "distance ospf external <1-255> intra-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param3_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, neighbor_soft_reconfiguration_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Per neighbor soft reconfiguration\n"
+       "Allow inbound soft reconfiguration for this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_exact_cmd_vtysh, 
+       "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n"
+       "Exact match of the prefixes\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp external in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf6|ripng|static)", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_cmd_vtysh, 
+       "show ipv6 route", 
+       "Show running system information\n"
+       "IP information\n"
+       "IPv6 routing table\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_fast_external_failover_cmd_vtysh, 
+       "no bgp fast-external-failover", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Immediately reset session if a link to a directly connected external peer goes down\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_mask_as_set_summary_cmd_vtysh, 
+       "no aggregate-address A.B.C.D A.B.C.D as-set summary-only", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_out_cmd_vtysh, 
+       "clear ip bgp external soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_summary_cmd_vtysh, 
+       "show bgp ipv6 summary", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_regexp_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) regexp .LINE", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_authtype_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_out_cmd_vtysh, 
+       "clear ip bgp * vpnv4 unicast out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_address_label_cmd_vtysh, 
+       "no ip address A.B.C.D/M label LINE", 
+       "Negate a command or set its defaults\n"
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Label of this address\n"
+       "Label\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged7_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "Med attribute\n"
+       "As-path attribute\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_bgp_network_route_map_cmd_vtysh, 
+       "no network X:X::X:X/M route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_cmd_vtysh, 
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, neighbor_ebgp_multihop_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Allow EBGP neighbors not on directly connected networks\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_key_cmd_vtysh, 
+       "no ip ospf authentication-key", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_ism_sub_cmd_vtysh, 
+       "no debug ospf ism (status|events|timers)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine\n"
+       "ISM Status Information\n"
+       "ISM Event Information\n"
+       "ISM Timer Information\n")
+
+DEFSH (VTYSH_OSPFD, refresh_timer_cmd_vtysh, 
+       "refresh timer <10-1800>", 
+       "Adjust refresh parameters\n"
+       "Set refresh timer\n"
+       "Timer value in seconds\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_managed_config_flag_cmd_vtysh, 
+       "ipv6 nd managed-config-flag", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Managed address configuration flag\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_inter_cmd_vtysh, 
+       "distance ospf intra-area <1-255> inter-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_val_cmd_vtysh, 
+       "no redistribute ospf6 metric <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_local_val_cmd_vtysh, 
+       "no set ipv6 next-hop local X:X::X:X", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "IPv6 information\n"
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n"
+       "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_name_standard2_cmd_vtysh, 
+       "ip community-list standard WORD (deny|permit)", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Add a standard community-list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_capability_route_refresh_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability route-refresh", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Advertise capability to the peer\n"
+       "Advertise route-refresh capability to this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_cmd_vtysh, 
+       "no access-list WORD (deny|permit) A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_ZEBRA, show_zebra_client_cmd_vtysh, 
+       "show zebra client", 
+       "Show running system information\n"
+       "Zebra information"
+       "Client information")
+
+DEFSH (VTYSH_BGPD, neighbor_allowas_in_arg_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in <1-10>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Accept as-path with my AS present in it\n"
+       "Number of occurances of AS number\n")
+
+DEFSH (VTYSH_BGPD, bgp_cluster_id_cmd_vtysh, 
+       "bgp cluster-id A.B.C.D", 
+       "BGP information\n"
+       "Configure Route-Reflector Cluster-id\n"
+       "Route-Reflector Cluster-id in IP address format\n")
+
+DEFSH (VTYSH_BGPD, no_router_bgp_view_cmd_vtysh, 
+       "no router bgp <1-65535> view WORD", 
+       "Negate a command or set its defaults\n"
+       "Enable a routing process\n"
+       "BGP information\n"
+       "AS number\n"
+       "BGP view\n"
+       "view name\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_send_recv_cmd_vtysh, 
+       "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail Information\n")
+
+DEFSH (VTYSH_BGPD, no_set_community_cmd_vtysh, 
+       "no set community", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP community attribute\n")
+
+DEFSH (VTYSH_OSPFD|VTYSH_OSPF6D, ospf6_routemap_no_set_metric_type_cmd_vtysh, 
+       "no set metric-type (type-1|type-2)", 
+       "Negate a command or set its defaults\n"
+       "Set value\n"
+       "Type of metric\n"
+       "OSPF6 external type 1 metric\n"
+       "OSPF6 external type 2 metric\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_name_seq_cmd_vtysh, 
+       "show ip prefix-list WORD seq <1-4294967295>", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh, 
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_rfc1583_flag_cmd_vtysh, 
+       "ospf rfc1583compatibility", 
+       "OSPF specific commands\n"
+       "Enable the RFC1583Compatibility flag\n")
+
+DEFSH (VTYSH_ZEBRA, no_debug_zebra_packet_cmd_vtysh, 
+       "no debug zebra packet", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community4_exact_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_RIPD, ip_rip_authentication_mode_cmd_vtysh, 
+       "ip rip authentication mode (md5|text)", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n")
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_send_ra_cmd_vtysh, 
+       "no ipv6 nd send-ra", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Send Router Advertisement\n")
+
+DEFSH (VTYSH_OSPFD, no_neighbor_pollinterval_cmd_vtysh, 
+       "no neighbor A.B.C.D poll-interval <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor IP address\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_exact_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_cmd_vtysh, 
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, ospf_abr_type_cmd_vtysh, 
+       "ospf abr-type (cisco|ibm|shortcut|standard)", 
+       "OSPF specific commands\n"
+       "Set OSPF ABR type\n"
+       "Alternative ABR,  cisco implementation\n"
+       "Alternative ABR,  IBM implementation\n"
+       "Shortcut ABR\n"
+       "Standard behavior (RFC2328)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Maximum number of prefix accept from this peer\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_type_cmd_vtysh, 
+       "default-information originate always metric <0-16777214> metric-type (1|2)", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_BGPD, neighbor_strict_capability_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Strict capability negotiation match\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community3_exact_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_cmd_vtysh, 
+       "clear bgp view WORD * soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_in_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X) in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_version_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "version", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Neighbor's BGP version\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_prefix_cmd_vtysh, 
+       "show ipv6 prefix-list WORD X:X::X:X/M", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+
+DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_advertised_route_cmd_vtysh, 
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_addr_cmd_vtysh, 
+       "show ip route A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n"
+       "Network in the IP routing table to display\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_le_cmd_vtysh, 
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_list_cmd_vtysh, 
+       "show ipv6 mbgp community-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community3_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged7_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "Med attribute\n"
+       "As-path attribute\n")
+
+DEFSH (VTYSH_BGPD, neighbor_default_originate_rmap_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "default-originate route-map WORD", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Originate default route to this neighbor\n"
+       "Route-map to specify criteria to originate default\n"
+       "route-map name\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_priority_cmd_vtysh, 
+       "ip ospf priority <0-255>", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Priority\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_routemap_cmd_vtysh, 
+       "no redistribute connected metric <0-16> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, neighbor_allowas_in_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Accept as-path with my AS present in it\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_out_cmd_vtysh, 
+       "clear ip bgp external ipv4 (unicast|multicast) out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_distance_source_access_list_cmd_vtysh, 
+       "distance <1-255> A.B.C.D/M WORD", 
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n"
+       "Access list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_regexp_cmd_vtysh, 
+       "show ip bgp regexp .LINE", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_in_cmd_vtysh, 
+       "clear bgp * in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPF6D, show_debug_ospf6_cmd_vtysh, 
+      "show debugging ospf6", 
+      "Show running system information\n"
+      "Debugging functions (see also 'undebug')\n"
+      "Open Shortest Path First (OSPF) for IPv6\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community4_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_summary_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_in_cmd_vtysh, 
+       "clear ip bgp A.B.C.D in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_out_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_fsm_cmd_vtysh, 
+       "debug bgp fsm", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP Finite State Machine\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_cmd_vtysh, 
+       "no redistribute bgp", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD, rip_timers_cmd_vtysh, 
+       "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", 
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n"
+       "Routing table update timer value in second. Default is 30.\n"
+       "Routing information timeout timer. Default is 180.\n"
+       "Garbage collection timer. Default is 120.\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_ge_le_cmd_vtysh, 
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, old_ipv6_aggregate_address_cmd_vtysh, 
+       "ipv6 bgp aggregate-address X:X::X:X/M", 
+       "IPv6 information\n"
+       "BGP information\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh, 
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged1_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD, no_match_interface_cmd_vtysh, 
+       "no match interface", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match first hop interface of route\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_prefix_longer_cmd_vtysh, 
+       "show ipv6 route X:X::X:X/M longer-prefixes", 
+       "Show running system information\n"
+       "IP information\n"
+       "IPv6 routing table\n"
+       "IPv6 prefix\n"
+       "Show route matching the specified Network/Mask pair only\n")
+
+DEFSH (VTYSH_OSPFD, ospf_priority_cmd_vtysh, 
+       "ospf priority <0-255>", 
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Priority\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_description_cmd_vtysh, 
+       "ipv6 prefix-list WORD description .LINE", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_all_cmd_vtysh, 
+       "show bgp ipv6 community", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_all_cmd_vtysh, 
+       "no ip extcommunity-list (standard|expanded) WORD", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Specify standard extcommunity-list\n"
+       "Specify expanded extcommunity-list\n"
+       "Extended Community list name\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_advertise_interval_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Minimum interval between sending BGP routing updates\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community3_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_duration_day_month_cmd_vtysh, 
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_cmd_vtysh, 
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_prefix_cmd_vtysh, 
+       "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_soft_cmd_vtysh, 
+       "clear bgp <1-65535> soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_cmd_vtysh, 
+       "show bgp ipv6", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_ebgp_multihop_ttl_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Allow EBGP neighbors not on directly connected networks\n"
+       "maximum hop count\n")
+
+DEFSH (VTYSH_BGPD, bgp_scan_time_cmd_vtysh, 
+       "bgp scan-time <5-60>", 
+       "BGP specific commands\n"
+       "Configure background scanner interval\n"
+       "Scanner interval (seconds)\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_message_digest_key_addr_cmd_vtysh, 
+       "no ip ospf message-digest-key <1-255> A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_name_cmd_vtysh, 
+       "show ipv6 prefix-list WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_RIPNGD, show_debugging_ripng_cmd_vtysh, 
+       "show debugging ripng", 
+       "Show running system information\n"
+       "RIPng configuration\n"
+       "Debugging information\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_standard2_cmd_vtysh, 
+       "ip community-list <1-99> (deny|permit)", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_access_list_cmd_vtysh, 
+       "show ip access-list", 
+       "Show running system information\n"
+       "IP information\n"
+       "List IP access lists\n")
+
+DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_advertised_route_cmd_vtysh, 
+       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_set_origin_val_cmd_vtysh, 
+       "no set origin (egp|igp|incomplete)", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_route_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D route", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Routing Table\n"
+       )
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_routes_cmd_vtysh, 
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_lsa_cmd_vtysh, 
+       "debug ospf lsa", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Link State Advertisement\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_dont_capability_negotiate_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Do not perform capability negotiation\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_cmd_vtysh, 
+       "clear ip bgp view WORD * soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_dead_interval_cmd_vtysh, 
+       "ip ospf dead-interval <1-65535>", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_cmd_vtysh, 
+       "distance ospf inter-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_message_digest_key_cmd_vtysh, 
+       "no ip ospf message-digest-key <1-255>", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_cmd_vtysh, 
+       "clear ip bgp peer-group WORD soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_route_ospf6_external_prefix_cmd_vtysh, 
+       "show ipv6 ospf6 route redistribute X::X", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Routing Table\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "redistributing External information\n"
+       "match IPv6 prefix\n"
+       )
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_metric_cmd_vtysh, 
+       "redistribute ospf6 metric <0-16>", 
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_cmd_vtysh, 
+       "clear ip bgp <1-65535> soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_ZEBRA, config_table_cmd_vtysh, 
+       "table TABLENO", 
+       "Configure target kernel routing table\n"
+       "TABLE integer\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_zebra_sub_cmd_vtysh, 
+       "no debug ospf zebra (interface|redistribute)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Zebra information\n"
+       "Zebra interface\n"
+       "Zebra redistribute\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_cmd_vtysh, 
+       "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" "|max-age|self-originate)", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n"
+       "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+       "LSAs in MaxAge list\n"
+       "Self-originated link states\n")
+
+DEFSH (VTYSH_BGPD, neighbor_prefix_list_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Filter updates to/from this neighbor\n"
+       "Name of a prefix list\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_cmd_vtysh, 
+       "no ip prefix-list WORD", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_nomask_cmd_vtysh, 
+       "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", 
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n")
+
+DEFSH (VTYSH_BGPD, neighbor_default_originate_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "default-originate", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Originate default route to this neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_cmd_vtysh, 
+       "default-information originate always metric <0-16777214>", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n")
+
+DEFSH (VTYSH_RIPD, no_rip_route_cmd_vtysh, 
+       "no route A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "RIP static route configuration\n"
+       "IP prefix <network>/<length>\n")
+
+DEFSH (VTYSH_RIPD, rip_default_metric_cmd_vtysh, 
+       "default-metric <1-16>", 
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_addr_cmd_vtysh, 
+       "no ip ospf dead-interval A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, show_ipv6_ripng_cmd_vtysh, 
+       "show ipv6 ripng", 
+       "Show running system information\n"
+       "IP information\n"
+       "Show RIPng routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_compatible_rfc1583_cmd_vtysh, 
+       "compatible rfc1583", 
+       "OSPF compatibility list\n"
+       "compatible with RFC 1583\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_routemap_cmd_vtysh, 
+       "no redistribute static route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged1_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_routes_interval_cmd_vtysh, 
+       "dump bgp routes-mrt PATH INTERVAL", 
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump whole BGP routing table\n"
+       "Output filename\n"
+       "Interval of output\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_routemap_cmd_vtysh, 
+       "redistribute kernel route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community4_exact_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_soft_out_cmd_vtysh, 
+       "clear bgp <1-65535> soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_OSPFD, interface_ip_ospf_authentication_args_cmd_vtysh, 
+       "ip ospf authentication (null|message-digest)", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable authentication on this interface\n"
+       "Use null authentication\n"
+       "Use message-digest authentication\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_timers_cmd_vtysh, 
+       "no timers basic", 
+       "Negate a command or set its defaults\n"
+       "RIPng timers setup\n"
+       "Basic timer\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_cmd_vtysh, 
+       "show ip prefix-list", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n")
+
+DEFSH (VTYSH_BGPD, no_match_community_val_cmd_vtysh, 
+       "no match community (<1-99>|<100-199>|WORD)", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_set_ip_nexthop_val_cmd_vtysh, 
+       "no set ip next-hop A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "IP information\n"
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_sequence_number_cmd_vtysh, 
+       "no ip prefix-list sequence-number", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_in_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535> in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_receive_version_cmd_vtysh, 
+       "no ip rip receive version", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_cmd_vtysh, 
+       "default-information originate always", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_in_cmd_vtysh, 
+       "clear ip bgp * vpnv4 unicast in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_advertise_force_prefix_cmd_vtysh, 
+       "no ipv6 ospf6 advertise force-prefix", 
+       "Negate a command or set its defaults\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Advertising options\n"
+       "Force to advertise prefix,  applicable if Loopback or P-to-P\n"
+       )
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_normal_cmd_vtysh, 
+       "no debug bgp", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_out_cmd_vtysh, 
+       "clear ip bgp A.B.C.D vpnv4 unicast out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_routemap_cmd_vtysh, 
+       "default-information originate always metric <0-16777214> route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_cmd_vtysh, 
+       "default-information originate metric <0-16777214>", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_summary_cmd_vtysh, 
+       "show ipv6 mbgp summary", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_OSPFD, no_refresh_timer_val_cmd_vtysh, 
+       "no refresh timer <10-1800>", 
+       "Adjust refresh parameters\n"
+       "Unset refresh timer\n"
+       "Timer value in seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_cmd_vtysh, 
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n"
+       "Wildcard bits\n")
+
+DEFSH (VTYSH_ZEBRA, shutdown_if_cmd_vtysh, 
+       "shutdown", 
+       "Shutdown the selected interface\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_route_reflector_client_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Configure a neighbor as Route Reflector client\n")
+
+DEFSH (VTYSH_RIPD, no_rip_distance_source_cmd_vtysh, 
+       "no distance <1-255> A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_out_cmd_vtysh, 
+       "clear ip bgp view WORD * soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_event_cmd_vtysh, 
+       "no debug ospf event", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF event information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_cmd_vtysh, 
+       "clear ip bgp (A.B.C.D|X:X::X:X)", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor IP address to clear\n"
+       "BGP IPv6 neighbor to clear\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_dampened_paths_cmd_vtysh, 
+       "show ip bgp dampened-paths", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display paths suppressed due to dampening\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_filter_cmd_vtysh, 
+       "no debug bgp filters", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP filters\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ip_prefix_list_cmd_vtysh, 
+       "clear ip prefix-list", 
+       "Reset functions\n"
+       "IP information\n"
+       "Build a prefix list\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_summary_as_set_cmd_vtysh, 
+       "no aggregate-address A.B.C.D/M summary-only as-set", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_events_cmd_vtysh, 
+       "debug rip events", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP events\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_distribute_list_out_cmd_vtysh, 
+       "no distribute-list WORD out (kernel|connected|static|rip|bgp)", 
+       "Negate a command or set its defaults\n"
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter outgoing routing updates\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_prefix_cmd_vtysh, 
+       "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_rt_cmd_vtysh, 
+       "no set extcommunity rt", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP extended community attribute\n"
+       "Route Target extened communityt\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged10_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh, 
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_normal_cmd_vtysh, 
+       "undebug bgp", 
+       "Disable debugging functions (see also 'debug')\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_addr_cmd_vtysh, 
+       "no ip ospf retransmit-interval A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_routemap_cmd_vtysh, 
+       "no redistribute bgp route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp * in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, neighbor_transparent_as_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "transparent-as", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Do not append my AS number even peer is EBGP peer\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_remark_cmd_vtysh, 
+       "no ipv6 access-list WORD remark", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n")
+
+DEFSH (VTYSH_BGPD, no_match_community_exact_cmd_vtysh, 
+       "no match community (<1-99>|<100-199>|WORD) exact-match", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n"
+       "Do exact matching of communities\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param3_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_out_cmd_vtysh, 
+       "clear bgp ipv6 external WORD out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_intra_cmd_vtysh, 
+       "distance ospf inter-area <1-255> intra-area <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_out_cmd_vtysh, 
+       "clear ip bgp <1-65535> vpnv4 unicast out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_summary_cmd_vtysh, 
+       "show bgp summary", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, bgp_deterministic_med_cmd_vtysh, 
+       "bgp deterministic-med", 
+       "BGP specific commands\n"
+       "Pick the best-MED path among paths advertised from the neighboring AS\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_le_ge_cmd_vtysh, 
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_filter_cmd_vtysh, 
+       "undebug bgp filters", 
+       "Disable debugging functions (see also 'debug')\n"
+       "BGP information\n"
+       "BGP filters\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_cmd_vtysh, 
+       "show ipv6 ospf6", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh, 
+       "clear bgp ipv6 external in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_spf_node_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D spf node", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Shortest Path First caculation\n"
+       "vertex infomation\n"
+       )
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf|rip|static)", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_BGPD, neighbor_filter_list_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Establish BGP filters\n"
+       "AS path access-list name\n"
+       "Filter incoming routes\n"
+       "Filter outgoing routes\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged10_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ip_prefix_list_name_cmd_vtysh, 
+       "clear ip prefix-list WORD", 
+       "Reset functions\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_cmd_vtysh, 
+       "show ip route", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_cmd_vtysh, 
+       "redistribute connected", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ip_community_list_cmd_vtysh, 
+       "ip community-list WORD (deny|permit) .AA:NN", 
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_in_prefix_filter_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_external_cmd_vtysh, 
+       "distance ospf intra-area <1-255> external <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+
+DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_received_routes_cmd_vtysh, 
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_type_routemap_cmd_vtysh, 
+       "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_cmd_vtysh, 
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_plist_passive_cmd_vtysh, 
+       "interface IFNAME area A.B.C.D prefix-list WORD passive", 
+       "Enable routing on an IPv6 interface\n"
+       "Interface name(e.g. ep0)\n"
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       "Advertise I/F Address only match entries of prefix-list\n"
+       "IPv6 prefix-list name\n"
+       "IPv6 prefix-list name\n"
+       "Suppress routing updates on an interface\n"
+      )
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_seq_le_ge_cmd_vtysh, 
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh, 
+       "clear bgp ipv6 * in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh, 
+       "show ip bgp vpnv4 all neighbors", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbors_cmd_vtysh, 
+       "show bgp ipv6 neighbors", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_routemap_cmd_vtysh, 
+       "no redistribute kernel metric <0-16> route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, old_no_ipv6_aggregate_address_summary_only_cmd_vtysh, 
+       "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_summary_cmd_vtysh, 
+       "show ipv6 bgp summary", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp view WORD * in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_standard_cmd_vtysh, 
+       "no ip extcommunity-list <1-99> (deny|permit) .AA:NN", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Extended Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distribute_list_out_cmd_vtysh, 
+       "distribute-list WORD out (kernel|connected|static|rip|bgp)", 
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter outgoing routing updates\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_remark_arg_cmd_vtysh, 
+       "no ipv6 access-list WORD remark .LINE", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_statistics_cmd_vtysh, 
+       "show ip bgp flap-statistics", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_supernets_cmd_vtysh, 
+       "show ip route supernets-only", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n"
+       "Show supernet entries only\n")
+
+DEFSH (VTYSH_BGPD, set_ipv6_nexthop_local_cmd_vtysh, 
+       "set ipv6 next-hop local X:X::X:X", 
+       "Set values in destination routing protocol\n"
+       "IPv6 information\n"
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n"
+       "IPv6 address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_rfc1583_flag_cmd_vtysh, 
+       "no ospf rfc1583compatibility", 
+       "Negate a command or set its defaults\n"
+       "OSPF specific commands\n"
+       "Disable the RFC1583Compatibility flag\n")
+
+DEFSH (VTYSH_BGPD, neighbor_route_map_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Apply route map to neighbor\n"
+       "Name of route map\n"
+       "Apply map to incoming routes\n"
+       "Apply map to outbound routes\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_keepalive_cmd_vtysh, 
+       "no debug bgp keepalives", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP keepalives\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community3_exact_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_topology_router_lsid_cmd_vtysh, 
+       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Inter Area topology information\n"
+       "Specify Router-ID\n"
+       "Specify Router-ID\n"
+       "Specify Link State ID\n"
+       "Specify Link State ID\n"
+       )
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_route_map_cmd_vtysh, 
+       "no network A.B.C.D route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_all_cmd_vtysh, 
+       "show ipv6 mbgp community", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_route_map_cmd_vtysh, 
+       "no route-map WORD (deny|permit) <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n"
+       "Route map denies set operations\n"
+       "Route map permits set operations\n"
+       "Sequence to insert to/delete from existing route-map entry\n")
+
+DEFSH (VTYSH_ZEBRA, ip_address_cmd_vtysh, 
+       "ip address A.B.C.D/M", 
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_ge_cmd_vtysh, 
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_sequence_number_cmd_vtysh, 
+       "no ipv6 prefix-list sequence-number", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Include/exclude sequence numbers in NVGEN\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_host_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "A single destination host\n"
+       "Destination address\n")
+
+DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_routes_cmd_vtysh, 
+       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_param4_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_expanded_cmd_vtysh, 
+       "no ip extcommunity-list <100-199> (deny|permit) .LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Extended Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_key_chain_cmd_vtysh, 
+       "no ip rip authentication key-chain", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_mask_pref_cmd_vtysh, 
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <1-255>", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Distance value for this route\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_default_information_originate_cmd_vtysh, 
+       "no default-information originate", 
+       "Negate a command or set its defaults\n"
+       "Control distribution of default information\n"
+       "Distribute a default route\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_bestpath_med_cmd_vtysh, 
+       "no bgp bestpath med (confed|missing-as-worst)", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Change the default bestpath selection\n"
+       "MED attribute\n"
+       "Compare MED among confederation paths\n"
+       "Treat missing MED as the least preferred one\n")
+
+DEFSH (VTYSH_BGPD, neighbor_unsuppress_map_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Route-map to selectively unsuppress suppressed routes\n"
+       "Name of route map\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_route_cmd_vtysh, 
+       "route IPV6ADDR", 
+       "Static route setup\n"
+       "Set static RIPng route announcement\n")
+
+DEFSH (VTYSH_ZEBRA, ip_route_cmd_vtysh, 
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE)", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_damp_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the dampened routes received from neighbor\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_month_day_day_month_cmd_vtysh, 
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_route_map_all_cmd_vtysh, 
+       "no route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n")
+
+DEFSH (VTYSH_RIPD, no_rip_network_cmd_vtysh, 
+       "no network (A.B.C.D/M|WORD)", 
+       "Negate a command or set its defaults\n"
+       "Enable routing on an IP network\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_route_map_cmd_vtysh, 
+       "network A.B.C.D mask A.B.C.D route-map WORD", 
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, set_vpnv4_nexthop_cmd_vtysh, 
+       "set vpnv4 next-hop A.B.C.D", 
+       "Set values in destination routing protocol\n"
+       "VPNv4 information\n"
+       "VPNv4 next-hop address\n"
+       "IP address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_send_recv_detail_cmd_vtysh, 
+       "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail Information\n")
+
+DEFSH (VTYSH_RIPD, no_rip_default_metric_cmd_vtysh, 
+       "no default-metric", 
+       "Negate a command or set its defaults\n"
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_out_cmd_vtysh, 
+       "clear ip bgp peer-group WORD soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_route_cmd_vtysh, 
+       "show ipv6 mbgp X:X::X:X", 
+       "Show running system information\n"
+       "IP information\n"
+       "MBGP information\n"
+       "Network in the MBGP routing table to display\n")
+
+DEFSH (VTYSH_OSPFD, neighbor_cmd_vtysh, 
+       "neighbor A.B.C.D", 
+       "Specify neighbor router\n"
+       "Neighbor IP address\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_in_cmd_vtysh, 
+       "clear ip bgp external ipv4 (unicast|multicast) in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, area_range_advertise_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "OSPF area range for route advertise (default)\n"
+       "area range prefix\n"
+       "advertise this range\n")
+
+DEFSH (VTYSH_OSPFD, timers_spf_cmd_vtysh, 
+       "timers spf <0-4294967295> <0-4294967295>", 
+       "Adjust routing timers\n"
+       "OSPF SPF timers\n"
+       "Delay between receiving a change to SPF calculation\n"
+       "Hold time between consecutive SPF calculations\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_route_pref_cmd_vtysh, 
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", 
+       "IP information\n"
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Distance value for this prefix\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_default_local_preference_val_cmd_vtysh, 
+       "no bgp default local-preference <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "local preference (higher=more preferred)\n"
+       "Configure default local preference value\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_timers_cmd_vtysh, 
+       "timers basic <0-65535> <0-65535> <0-65535>", 
+       "RIPng timers setup\n"
+       "Basic timer\n"
+       "Routing table update timer value in second. Default is 30.\n"
+       "Routing information timeout timer. Default is 180.\n"
+       "Garbage collection timer. Default is 120.\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged8_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community2_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_OSPFD, no_set_metric_type_cmd_vtysh, 
+       "no set metric-type", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "Type of metric for destination routing protocol\n")
+
+DEFSH (VTYSH_BGPD, neighbor_peer_group_cmd_vtysh, 
+       "neighbor WORD peer-group", 
+       "Specify neighbor router\n"
+       "Neighbor tag\n"
+       "Configure peer-group\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_exact_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, no_area_range_subst_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Deconfigure OSPF area range for route summarization\n"
+       "area range prefix\n"
+       "Do not advertise this range\n"
+       "Announce area range as another prefix\n"
+       "Network prefix to be announced instead of range\n")
+
+DEFSH (VTYSH_BGPD, bgp_enforce_first_as_cmd_vtysh, 
+       "bgp enforce-first-as", 
+       "BGP information\n"
+       "Enforce the first AS for EBGP routes\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community3_exact_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, ospf_dead_interval_cmd_vtysh, 
+       "ospf dead-interval <1-65535>", 
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_args_md5_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) (message-digest|null) "
+       "(message-digest-key|) <1-255> md5 KEY", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n"
+       "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_BGPD, clear_bgp_external_cmd_vtysh, 
+       "clear bgp external", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all external peers\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_name_standard_cmd_vtysh, 
+       "no ip community-list standard WORD (deny|permit) .AA:NN", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Specify a standard community-list\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, neighbor_update_source_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source WORD", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Source of routing updates\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_in_cmd_vtysh, 
+       "clear ip bgp peer-group WORD in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, neighbor_priority_cmd_vtysh, 
+       "neighbor A.B.C.D priority <0-255>", 
+       "Specify neighbor router\n"
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_standard_cmd_vtysh, 
+       "ip extcommunity-list standard WORD (deny|permit) .AA:NN", 
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Specify standard extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n")
+
+DEFSH (VTYSH_BGPD, neighbor_capability_route_refresh_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability route-refresh", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Advertise capability to the peer\n"
+       "Advertise route-refresh capability to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_bgp_network_cmd_vtysh, 
+       "no network X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_val_cmd_vtysh, 
+       "no redistribute connected metric <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_receive_version_1_cmd_vtysh, 
+       "ip rip receive version 1 2", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_mask_cmd_vtysh, 
+       "no network A.B.C.D mask A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n")
+
+DEFSH (VTYSH_ZEBRA, show_interface_cmd_vtysh, 
+       "show interface [IFNAME]", 
+       "Show running system information\n"
+       "Interface status and configuration\n"
+       "Inteface name\n")
+
+DEFSH (VTYSH_OSPFD, no_router_ospf_cmd_vtysh, 
+       "no router ospf", 
+       "Negate a command or set its defaults\n"
+       "Enable a routing process\n"
+       "Start OSPF configuration\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_confederation_identifier_cmd_vtysh, 
+       "no bgp confederation identifier", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "AS confederation parameters\n"
+       "AS number\n")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_type_routemap_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2) route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_local_as_val2_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535> no-prepend", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Specify a local-as number\n"
+       "AS number used as local AS\n"
+       "Do not prepend local-as to updates from ebgp peers\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_info_cmd_vtysh, 
+       "show ip bgp community-info", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "List all bgp community information\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_metric_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_cidr_only_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) cidr-only", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display only routes with non-natural netmasks\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ipv6_access_list_any_cmd_vtysh, 
+       "ipv6 access-list WORD (deny|permit) any", 
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any prefixi to match\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_fsm_cmd_vtysh, 
+       "undebug bgp fsm", 
+       "Disable debugging functions (see also 'debug')\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "Finite State Machine\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_cmd_vtysh, 
+       "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_network_import_check_cmd_vtysh, 
+       "no bgp network import-check", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "BGP network command\n"
+       "Check BGP network route exists in IGP\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_out_cmd_vtysh, 
+       "clear ip bgp A.B.C.D soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_name_expanded_cmd_vtysh, 
+       "no ip community-list expanded WORD (deny|permit) .LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Specify an expanded community-list\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_expanded_cmd_vtysh, 
+       "ip extcommunity-list expanded WORD (deny|permit) .LINE", 
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Specify expanded extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_RIPD, no_rip_distance_cmd_vtysh, 
+       "no distance <1-255>", 
+       "Negate a command or set its defaults\n"
+       "Administrative distance\n"
+       "Distance value\n")
+
+DEFSH (VTYSH_ZEBRA, show_debugging_zebra_cmd_vtysh, 
+       "show debugging zebra", 
+       "Show running system information\n"
+       "Zebra configuration\n"
+       "Debugging information\n")
+
+DEFSH (VTYSH_OSPFD, area_authentication_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) authentication", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Enable authentication\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_list_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+DEFSH (VTYSH_RIPD, no_rip_offset_list_ifname_cmd_vtysh, 
+       "no offset-list WORD (in|out) <0-16> IFNAME", 
+       "Negate a command or set its defaults\n"
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n"
+       "Interface to match\n")
+
+DEFSH (VTYSH_ZEBRA, show_ip_route_prefix_cmd_vtysh, 
+       "show ip route A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_OSPF6D, interface_area_plist_cmd_vtysh, 
+       "interface IFNAME area A.B.C.D prefix-list WORD", 
+       "Enable routing on an IPv6 interface\n"
+       "Interface name(e.g. ep0)\n"
+       "Set the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       "Advertise I/F Address only match entries of prefix-list\n"
+       "IPv6 prefix-list name\n"
+      )
+
+DEFSH (VTYSH_OSPFD, neighbor_priority_pollinterval_cmd_vtysh, 
+       "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Priority\n"
+       "Dead Neighbor Polling interval\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, rmap_onmatch_goto_cmd_vtysh, 
+       "on-match goto <1-65535>", 
+       "Exit policy on matches\n"
+       "Goto Clause number\n"
+       "Number\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_peer_group_remote_as_cmd_vtysh, 
+       "no neighbor WORD remote-as <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor tag\n"
+       "Specify a BGP neighbor\n"
+       "AS number\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_cmd_vtysh, 
+       "aggregate-address A.B.C.D A.B.C.D as-set", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_adv_router_cmd_vtysh, 
+       "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D adv-router A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n"
+       "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+       "Link State ID (as an IP address)\n"
+       "Advertising Router link states\n"
+       "Advertising Router (as an IP address)\n")
+
+DEFSH (VTYSH_BGPD, no_dump_bgp_all_cmd_vtysh, 
+       "no dump bgp all [PATH] [INTERVAL]", 
+       "Negate a command or set its defaults\n"
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump all BGP packets\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community4_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged8_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_config_type_cmd_vtysh, 
+       "no bgp config-type", 
+       "Negate a command or set its defaults\n"
+       "BGP information\n"
+       "Display configuration type\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_view_prefix_cmd_vtysh, 
+       "show ip bgp view WORD A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "BGP view name\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_as_set_summary_cmd_vtysh, 
+       "aggregate-address A.B.C.D/M as-set summary-only", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Generate AS set path information\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_cmd_vtysh, 
+       "show ipv6 bgp", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh, 
+       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_address_secondary_cmd_vtysh, 
+       "no ip address A.B.C.D/M secondary", 
+       "Negate a command or set its defaults\n"
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Secondary IP address\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh, 
+       "clear ip bgp external ipv4 (unicast|multicast) soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_cmd_vtysh, 
+       "clear bgp view WORD *", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_port_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "port", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Neighbor's BGP port\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_prefix_list_cmd_vtysh, 
+       "no match ip address prefix-list", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match address of route\n"
+       "Match entries of prefix-lists\n")
+
+DEFSH (VTYSH_BGPD, neighbor_passive_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "passive", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Don't send open messages to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_out_cmd_vtysh, 
+       "clear bgp * out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_set2_cmd_vtysh, 
+       "bgp dampening <1-45>", 
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n"
+       "Half-life time for the penalty\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_detail_cmd_vtysh, 
+       "show ip prefix-list detail", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Detail of prefix lists\n")
+
+DEFSH (VTYSH_BGPD, neighbor_capability_dynamic_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Advertise capability to the peer\n"
+       "Advertise dynamic capability to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, neighbor_timers_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "timers <0-65535> <0-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP per neighbor timers\n"
+       "Keepalive interval\n"
+       "Holdtime\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_all_cmd_vtysh, 
+       "undebug all bgp", 
+       "Disable debugging functions (see also 'debug')\n"
+       "Enable all debugging\n"
+       "BGP information\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_prefix_list_cmd_vtysh, 
+       "show bgp prefix-list WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes conforming to the prefix-list\n"
+       "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_set_vpnv4_nexthop_val_cmd_vtysh, 
+       "no set vpnv4 next-hop A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "VPNv4 information\n"
+       "VPNv4 next-hop address\n"
+       "IP address of next hop\n")
+
+DEFSH (VTYSH_OSPFD, area_filter_list_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Filter networks between OSPF areas\n"
+       "Filter prefixes between OSPF areas\n"
+       "Name of an IP prefix-list\n"
+       "Filter networks sent to this area\n"
+       "Filter networks sent from this area\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_out_cmd_vtysh, 
+       "clear bgp ipv6 external soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_interface_cmd_vtysh, 
+       "show ip ospf interface [INTERFACE]", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Interface information\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbors_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) neighbors", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_always_compare_med_cmd_vtysh, 
+       "no bgp always-compare-med", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Allow comparing MED from different neighbors\n")
+
+DEFSH (VTYSH_BGPD, old_no_ipv6_aggregate_address_cmd_vtysh, 
+       "no ipv6 bgp aggregate-address X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_metric_cmd_vtysh, 
+       "default-information originate metric-type (1|2) metric <0-16777214>", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged2_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_packet_cmd_vtysh, 
+       "debug rip packet", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP packet\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh, 
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_default_metric_cmd_vtysh, 
+       "default-metric <1-16>", 
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_RIPD, no_rip_redistribute_type_cmd_vtysh, 
+       "no redistribute (kernel|connected|static|ospf|bgp)", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_keepalive_cmd_vtysh, 
+       "undebug bgp keepalives", 
+       "Disable debugging functions (see also 'debug')\n"
+       "BGP information\n"
+       "BGP keepalives\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_import_check_cmd_vtysh, 
+       "bgp network import-check", 
+       "BGP specific commands\n"
+       "BGP network command\n"
+       "Check BGP network route exists in IGP\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_out_cmd_vtysh, 
+       "clear ip bgp <1-65535> soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community4_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, ip_as_path_cmd_vtysh, 
+       "ip as-path access-list WORD (deny|permit) .LINE", 
+       "IP information\n"
+       "BGP autonomous system path filter\n"
+       "Specify an access list name\n"
+       "Regular expression access list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_out_cmd_vtysh, 
+       "clear ip bgp * out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, send_lifetime_day_month_month_day_cmd_vtysh, 
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", 
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPF6D, no_router_zebra_cmd_vtysh, 
+       "no router zebra", 
+       "Negate a command or set its defaults\n"
+       "Configure routing process\n"
+       "Disable connection to zebra daemon\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_authentication_string_cmd_vtysh, 
+       "no ip rip authentication string", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh, 
+       "clear bgp ipv6 peer-group WORD soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_route_map_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Apply route map to neighbor\n"
+       "Name of route map\n"
+       "Apply map to incoming routes\n"
+       "Apply map to outbound routes\n")
+
+DEFSH (VTYSH_BGPD, ipv6_aggregate_address_summary_only_cmd_vtysh, 
+       "aggregate-address X:X::X:X/M summary-only", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_transmit_delay_cmd_vtysh, 
+       "no ip ospf transmit-delay", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_le_ge_cmd_vtysh, 
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_route_map_cmd_vtysh, 
+       "network A.B.C.D/M route-map WORD", 
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_cmd_vtysh, 
+       "show ip bgp community-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_mask_cmd_vtysh, 
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_infinite_month_day_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Never expires")
+
+DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_metric_cmd_vtysh, 
+       "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Routing Information Protocol (RIP)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "OSPF exterior metric type for redistributed routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Metric for redistributed routes\n"
+       "OSPF default metric\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_out_cmd_vtysh, 
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_in_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_out_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_override_capability_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Override capability negotiation result\n")
+
+DEFSH (VTYSH_BGPD, no_dump_bgp_updates_cmd_vtysh, 
+       "no dump bgp updates [PATH] [INTERVAL]", 
+       "Negate a command or set its defaults\n"
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump BGP updates only\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_lsa_sub_cmd_vtysh, 
+       "debug ospf lsa (generate|flooding|install|refresh)", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Link State Advertisement\n"
+       "LSA Generation\n"
+       "LSA Flooding\n"
+       "LSA Install/Delete\n"
+       "LSA Refresh\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_hello_interval_cmd_vtysh, 
+       "ip ospf hello-interval <1-65535>", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_OSPF6D, passive_interface_cmd_vtysh, 
+       "passive-interface IFNAME", 
+       "Suppress routing updates on an interface\n"
+       "Interface name(e.g. ep0)\n")
+
+DEFSH (VTYSH_BGPD, neighbor_nexthop_self_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Disable the next hop calculation for this neighbor\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_month_day_day_month_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_mask_pref_cmd_vtysh, 
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <1-255>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Distance value for this route\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_longer_cmd_vtysh, 
+       "show ipv6 bgp X:X::X:X/M longer-prefixes", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_val_cmd_vtysh, 
+       "no redistribute static metric <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_BGPD, no_match_aspath_val_cmd_vtysh, 
+       "no match as-path WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match BGP AS path list\n"
+       "AS path access-list name\n")
+
+DEFSH (VTYSH_RIPD, no_key_chain_cmd_vtysh, 
+       "no key chain WORD", 
+       "Negate a command or set its defaults\n"
+       "Authentication key management\n"
+       "Key-chain management\n"
+       "Key-chain name\n")
+
+DEFSH (VTYSH_OSPF6D, show_version_ospf6_cmd_vtysh, 
+       "show version ospf6", 
+       "Show running system information\n"
+       "Displays ospf6d version\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X)", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_unset_cmd_vtysh, 
+       "no bgp dampening", 
+       "Negate a command or set its defaults\n"
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n")
+
+DEFSH (VTYSH_OSPFD, area_import_list_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) import-list NAME", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the filter for networks from other areas announced to the specified one\n"
+       "Name of the access-list\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_routemap_cmd_vtysh, 
+       "default-information originate metric <0-16777214> route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF default metric\n"
+       "OSPF metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged2_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "As-path attribute\n"
+       "Nexthop attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_in_cmd_vtysh, 
+       "clear bgp peer-group WORD in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_dead_interval_cmd_vtysh, 
+       "no ospf dead-interval", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Interval after which a neighbor is declared dead\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_all_cmd_vtysh, 
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_ge_cmd_vtysh, 
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_set_ecommunity_rt_val_cmd_vtysh, 
+       "no set extcommunity rt .ASN:nn_or_IP-address:nn", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP extended community attribute\n"
+       "Route Target extened communityt\n"
+       "VPN extended community\n")
+
+DEFSH (VTYSH_BGPD, set_atomic_aggregate_cmd_vtysh, 
+       "set atomic-aggregate", 
+       "Set values in destination routing protocol\n"
+       "BGP atomic aggregate attribute\n" )
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_any_cmd_vtysh, 
+       "access-list WORD (deny|permit) any", 
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535> soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_update_cmd_vtysh, 
+       "debug bgp updates", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP updates\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_cmd_vtysh, 
+       "no ip community-list WORD (deny|permit) .AA:NN", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_advertise_interval_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Minimum interval between sending BGP routing updates\n"
+       "time in seconds\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_metric_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_prefix_cmd_vtysh, 
+       "show bgp X:X::X:X/M", 
+       "Show running system information\n"
+       "BGP information\n"
+       "IPv6 prefix <network>/<length>\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_cmd_vtysh, 
+       "show ipv6 bgp X:X::X:X/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_out_cmd_vtysh, 
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPF6D, ipv6_ospf6_advertise_force_prefix_cmd_vtysh, 
+       "ipv6 ospf6 advertise force-prefix", 
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Advertising options\n"
+       "Force advertising prefix,  applicable if Loopback or P-to-P\n"
+       )
+
+DEFSH (VTYSH_BGPD, show_bgp_filter_list_cmd_vtysh, 
+       "show bgp filter-list WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_in_cmd_vtysh, 
+       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_out_cmd_vtysh, 
+       "clear bgp (A.B.C.D|X:X::X:X) soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_RIPD, rip_distance_cmd_vtysh, 
+       "distance <1-255>", 
+       "Administrative distance\n"
+       "Distance value\n")
+
+DEFSH (VTYSH_BGPD, set_origin_cmd_vtysh, 
+       "set origin (egp|igp|incomplete)", 
+       "Set values in destination routing protocol\n"
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+
+DEFSH (VTYSH_OSPFD, ospf_transmit_delay_cmd_vtysh, 
+       "ospf transmit-delay <1-65535>", 
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_port_val_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Neighbor's BGP port\n"
+       "TCP port number\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ipv6_access_list_cmd_vtysh, 
+       "no ipv6 access-list WORD (deny|permit) X:X::X:X/M", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_database_type_id_adv_router_cmd_vtysh, 
+       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*) (A.B.C.D|*) (A.B.C.D|*|dump|summary)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "LSA Database\n"
+       "Router-LSA\n"
+       "Network-LSA\n"
+       "AS-External-LSA\n"
+       "Intra-Area-Prefix-LSA\n"
+       "Inter-Area-Router-LSA\n"
+       "Inter-Area-Prefix-LSA\n"
+       "Link-LSA\n"
+       "All LS Type\n"
+       "Link State ID\n"
+       "All Link State ID\n"
+       "Advertising Router\n"
+       "All Advertising Router\n"
+       "Dump raw LSA data in Hex\n"
+       "show summary of LSA\n"
+       )
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_exact_cmd_vtysh, 
+       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_weight_val_cmd_vtysh, 
+       "no set weight <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "BGP weight for routing table\n"
+       "Weight value\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_ebgp_multihop_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Allow EBGP neighbors not on directly connected networks\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_prefix_advertisement_no_val_cmd_vtysh, 
+       "ipv6 nd prefix-advertisement IPV6PREFIX", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n")
+
+DEFSH (VTYSH_BGPD, dump_bgp_all_cmd_vtysh, 
+       "dump bgp all PATH", 
+       "Dump packet\n"
+       "BGP packet dump\n"
+       "Dump all BGP packets\n"
+       "Output filename\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh, 
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_route_prefix_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D route (X::X|detail)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Routing Table\n"
+       "Specify IPv6 address\n"
+       "Detailed information\n"
+       )
+
+DEFSH (VTYSH_RIPNGD, ripng_passive_interface_cmd_vtysh, 
+       "passive-interface IFNAME", 
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbors_peer_cmd_vtysh, 
+       "show bgp neighbors (A.B.C.D|X:X::X:X)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_all_cmd_vtysh, 
+       "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ipv6_prefix_list_seq_cmd_vtysh, 
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", 
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_cmd_vtysh, 
+       "no redistribute kernel", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n")
+
+DEFSH (VTYSH_BGPD, set_weight_cmd_vtysh, 
+       "set weight <0-4294967295>", 
+       "Set values in destination routing protocol\n"
+       "BGP weight for routing table\n"
+       "Weight value\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_routemap_cmd_vtysh, 
+       "default-information originate metric-type (1|2) route-map WORD", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_cmd_vtysh, 
+       "no redistribute bgp metric", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_network_cmd_vtysh, 
+       "network IF_OR_ADDR", 
+       "RIPng enable on specified interface or network.\n"
+       "Interface or address")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ip_prefix_list_seq_le_ge_cmd_vtysh, 
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_default_metric_val_cmd_vtysh, 
+       "no default-metric <0-16777214>", 
+       "Negate a command or set its defaults\n"
+       "Set metric of redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_cmd_vtysh, 
+       "distance ospf external <1-255>", 
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_scan_time_val_cmd_vtysh, 
+       "no bgp scan-time <5-60>", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Configure background scanner interval\n"
+       "Scanner interval (seconds)\n")
+
+DEFSH (VTYSH_BGPD, old_ipv6_aggregate_address_summary_only_cmd_vtysh, 
+       "ipv6 bgp aggregate-address X:X::X:X/M summary-only", 
+       "IPv6 information\n"
+       "BGP information\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_route_cmd_vtysh, 
+       "show bgp X:X::X:X", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_adv_router_cmd_vtysh, 
+       "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") adv-router A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n"
+       "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+       "Advertising Router link states\n"
+       "Advertising Router (as an IP address)\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_name_all_cmd_vtysh, 
+       "no ip community-list (standard|expanded) WORD", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Add a standard community-list entry\n"
+       "Add an expanded community-list entry\n"
+       "Community list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh, 
+       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_in_cmd_vtysh, 
+       "clear ip bgp <1-65535> in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_send_version_cmd_vtysh, 
+       "ip rip send version (1|2)", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_authentication_key_cmd_vtysh, 
+       "no ospf authentication-key", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Authentication password (key)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_host_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "A single destination host\n"
+       "Destination address\n")
+
+DEFSH (VTYSH_BGPD, neighbor_dont_capability_negotiate_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Do not perform capability negotiation\n")
+
+DEFSH (VTYSH_OSPFD, no_area_vlink_param4_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval) "
+       "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n"
+       "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp A.B.C.D in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Soft reconfig inbound update\n"
+       "Push out the existing ORF prefix-list\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_weight_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Set default weight for routes from this neighbor\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, clear_ipv6_prefix_list_name_prefix_cmd_vtysh, 
+       "clear ipv6 prefix-list WORD X:X::X:X/M", 
+       "Reset functions\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_address_preference_cmd_vtysh, 
+       "ip irdp address A.B.C.D <0-2147483647>", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n"
+       "Specify IRDP address and preference to proxy-advertise\n"
+       "Set IRDP address for proxy-advertise\n"
+       "Preference level\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_in_cmd_vtysh, 
+       "clear ip bgp external soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all external peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_set_vpnv4_nexthop_cmd_vtysh, 
+       "no set vpnv4 next-hop", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "VPNv4 information\n"
+       "VPNv4 next-hop address\n")
+
+DEFSH (VTYSH_BGPD, bgp_multiple_instance_cmd_vtysh, 
+       "bgp multiple-instance", 
+       "BGP information\n"
+       "Enable bgp multiple instance\n")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_global_cmd_vtysh, 
+       "no set ipv6 next-hop global", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "IPv6 information\n"
+       "IPv6 next-hop address\n"
+       "IPv6 global address\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_neighbors_cmd_vtysh, 
+       "show bgp neighbors", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n")
+
+DEFSH (VTYSH_RIPD, no_match_ip_next_hop_val_cmd_vtysh, 
+       "no match ip next-hop WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match next-hop address of route\n"
+       "IP access-list name\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_community2_cmd_vtysh, 
+       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_list_cmd_vtysh, 
+       "show bgp ipv6 prefix-list WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes conforming to the prefix-list\n"
+       "IPv6 prefix-list name\n")
+
+DEFSH (VTYSH_OSPFD, no_area_stub_nosum_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) stub no-summary", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area as stub\n"
+       "Do not inject inter-area routes into area\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X)", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n")
+
+DEFSH (VTYSH_OSPFD, area_shortcut_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure the area's shortcutting mode\n"
+       "Set default shortcutting behavior\n"
+       "Enable shortcutting through the area\n"
+       "Disable shortcutting through the area\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_cmd_vtysh, 
+       "redistribute kernel", 
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_ge_le_cmd_vtysh, 
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_default_local_preference_cmd_vtysh, 
+       "no bgp default local-preference", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "local preference (higher=more preferred)\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh, 
+       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_rmap_cmd_vtysh, 
+       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_cmd_vtysh, 
+       "show ipv6 ospf6 route", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Routing table\n"
+       )
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_mask_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPF6D, router_zebra_cmd_vtysh, 
+       "router zebra", 
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_cmd_vtysh, 
+       "clear ip bgp view WORD *", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_default_originate_rmap_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "default-originate route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Originate default route to this neighbor\n"
+       "Route-map to specify criteria to originate default\n"
+       "route-map name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_cmd_vtysh, 
+       "no ipv6 prefix-list WORD", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_OSPFD, area_vlink_authtype_args_authkey_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D "
+       "(authentication|) (message-digest|null) "
+       "(authentication-key|) AUTH_KEY", 
+       "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n"
+       "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n"
+       "Authentication password (key)\n" "The OSPF password (key)")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_routemap_cmd_vtysh, 
+       "redistribute static route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_day_month_month_day_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+
+DEFSH (VTYSH_OSPF6D, no_debug_ospf6_all_cmd_vtysh, 
+       "no debug ospf6 all", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Turn off ALL OSPFv3 debugging\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_metric_cmd_vtysh, 
+       "default-information originate always metric-type (1|2) metric <0-16777214>", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n"
+       "OSPF default metric\n"
+       "OSPF metric\n")
+
+DEFSH (VTYSH_BGPD, neighbor_route_server_client_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Configure a neighbor as Route Server client\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_exact_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_bgp_prefix_longer_cmd_vtysh, 
+       "show bgp X:X::X:X/M longer-prefixes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_cmd_vtysh, 
+       "default-information originate metric-type (1|2)", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_OSPFD, no_neighbor_priority_cmd_vtysh, 
+       "no neighbor A.B.C.D priority <0-255>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor IP address\n"
+       "Neighbor Priority\n"
+       "Priority\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_distance_source_access_list_cmd_vtysh, 
+       "no distance <1-255> A.B.C.D/M WORD", 
+       "Negate a command or set its defaults\n"
+       "Define an administrative distance\n"
+       "Administrative distance\n"
+       "IP source prefix\n"
+       "Access list name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, ip_prefix_list_seq_le_ge_cmd_vtysh, 
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", 
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, neighbor_remote_as_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "remote-as <1-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Specify a BGP neighbor\n"
+       "AS number\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_lsa_sub_cmd_vtysh, 
+       "no debug ospf lsa (generate|flooding|install|refresh)", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Link State Advertisement\n"
+       "LSA Generation\n"
+       "LSA Flooding\n"
+       "LSA Install/Delete\n"
+       "LSA Refres\n")
+
+DEFSH (VTYSH_BGPD, no_match_origin_cmd_vtysh, 
+       "no match origin", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "BGP origin code\n")
+
+DEFSH (VTYSH_BGPD, neighbor_remove_private_as_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Remove private AS number from outbound updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ipv6_prefix_list_detail_name_cmd_vtysh, 
+       "show ipv6 prefix-list detail WORD", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Detail of prefix lists\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_address_cmd_vtysh, 
+       "show ip bgp flap-statistics A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_rmap_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_peer_group_cmd_vtysh, 
+       "clear bgp peer-group WORD", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_interface_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "interface WORD", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Interface\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_in_cmd_vtysh, 
+       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "BGP neighbor address to clear\n"
+       "BGP IPv6 neighbor to clear\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_soft_cmd_vtysh, 
+       "clear bgp * soft", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community3_exact_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_received_routes_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_mask_summary_as_set_cmd_vtysh, 
+       "aggregate-address A.B.C.D A.B.C.D summary-only as-set", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate address\n"
+       "Aggregate mask\n"
+       "Filter more specific routes from updates\n"
+       "Generate AS set path information\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighbor_routerid_cmd_vtysh, 
+       "show ipv6 ospf6 neighbor A.B.C.D", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Neighbor list\n"
+       "OSPF6 neighbor Router ID in IP address format\n"
+       )
+
+DEFSH (VTYSH_BGPD, bgp_cluster_id32_cmd_vtysh, 
+       "bgp cluster-id <1-4294967295>", 
+       "BGP information\n"
+       "Configure Route-Reflector Cluster-id\n"
+       "Route-Reflector Cluster-id as 32 bit quantity\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535>", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n")
+
+DEFSH (VTYSH_OSPFD|VTYSH_OSPFD, show_ip_ospf_neighbor_id_cmd_vtysh, 
+       "show ip ospf neighbor A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Neighbor list\n"
+       "Neighbor ID\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_hello_interval_addr_cmd_vtysh, 
+       "no ip ospf hello-interval A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between HELLO packets\n"
+       "Address of interface")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_val_cmd_vtysh, 
+       "no redistribute kernel metric <0-16>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Metric\n"
+       "Metric value\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_rmap_onmatch_goto_cmd_vtysh, 
+       "no on-match goto", 
+       "Negate a command or set its defaults\n"
+       "Exit policy on matches\n"
+       "Next clause\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_redistribute_routemap_cmd_vtysh, 
+       "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", 
+       "Redistribute\n"
+       "Static routes\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+       "Route map reference\n"
+       "Route map name\n"
+      )
+
+DEFSH (VTYSH_BGPD, neighbor_local_as_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535>", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Specify a local-as number\n"
+       "AS number used as local AS\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_prefix_list_val_cmd_vtysh, 
+       "no match ip address prefix-list WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged9_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n")
+
+DEFSH (VTYSH_ZEBRA, ipv6_nd_ra_interval_cmd_vtysh, 
+       "ipv6 nd ra-interval SECONDS", 
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n"
+       "Router Advertisement interval in seconds\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_cmd_vtysh, 
+       "no redistribute ospf6 metric", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "IPv6 Open Shortest Path First (OSPFv3)\n"
+       "Metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community3_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_timers_connect_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "timers connect", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "BGP per neighbor timers\n"
+       "BGP connect timer\n")
+
+DEFSH (VTYSH_BGPD, set_community_cmd_vtysh, 
+       "set community .AA:NN", 
+       "Set values in destination routing protocol\n"
+       "BGP community attribute\n"
+       "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_exact_cmd_vtysh, 
+       "show ip bgp community-list WORD exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_cmd_vtysh, 
+       "network A.B.C.D/M", 
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_summary_cmd_vtysh, 
+       "show ip bgp summary", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Summary of BGP neighbor status\n")
+
+DEFSH (VTYSH_BGPD, no_vpnv4_network_cmd_vtysh, 
+       "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Specify Route Distinguisher\n"
+       "VPN Route Distinguisher\n"
+       "BGP tag\n"
+       "tag value\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_backdoor_cmd_vtysh, 
+       "network A.B.C.D/M backdoor", 
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Specify a BGP backdoor route\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_send_community_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Send Community attribute to this neighbor\n")
+
+DEFSH (VTYSH_ZEBRA, debug_zebra_packet_detail_cmd_vtysh, 
+       "debug zebra packet (recv|send) detail", 
+       "Debugging functions (see also 'undebug')\n"
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n"
+       "Debug option set detaied information\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_cmd_vtysh, 
+       "show ip ospf", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_filter_list_cmd_vtysh, 
+       "show bgp ipv6 filter-list WORD", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes conforming to the filter-list\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_receive_version_2_cmd_vtysh, 
+       "ip rip receive version 2 1", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 2\n"
+       "RIP version 1\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_maxadvertinterval_cmd_vtysh, 
+       "ip irdp maxadvertinterval (0|<4-1800>)", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n"
+       "Set maximum time between advertisement\n"
+       "Maximum advertisement interval in seconds\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_longer_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "Display route and more specific routes\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_all_soft_in_cmd_vtysh, 
+       "clear bgp * soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_default_ipv4_unicast_cmd_vtysh, 
+       "no bgp default ipv4-unicast", 
+       "Negate a command or set its defaults\n"
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "Activate ipv4-unicast for a peer by default\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_topology_router_lsid_cmd_vtysh, 
+       "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Area information\n"
+       "Area ID (as an IPv4 notation)\n"
+       "Shortest Path First tree information\n"
+       "Displays SPF topology table\n"
+       "Specify Router-ID\n"
+       "Specify Router-ID\n"
+       "Specify Link State ID\n"
+       "Specify Link State ID\n"
+       )
+
+DEFSH (VTYSH_ZEBRA, no_ipv6_nd_managed_config_flag_cmd_vtysh, 
+       "no ipv6 nd managed-config-flag", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Neighbor discovery\n"
+       "Managed address configuration flag\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_message_digest_key_cmd_vtysh, 
+       "no ospf message-digest-key <1-255>", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Message digest authentication password (key)\n"
+       "Key ID\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_le_cmd_vtysh, 
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_prefix_first_match_cmd_vtysh, 
+       "show ip prefix-list WORD A.B.C.D/M first-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n"
+       "First matched prefix\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_zebra_cmd_vtysh, 
+       "debug ospf zebra", 
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Zebra information\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_self_cmd_vtysh, 
+       "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D (self-originate|)", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n"
+       "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" ""
+       "Link State ID (as an IP address)\n"
+       "Self-originated link states\n"
+       "\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_flap_cmd_vtysh, 
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display flap statistics of the routes learned from neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_ip_as_path_all_cmd_vtysh, 
+       "no ip as-path access-list WORD", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "BGP autonomous system path filter\n"
+       "Specify an access list name\n"
+       "Regular expression access list name\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_in_cmd_vtysh, 
+       "clear ip bgp * ipv4 (unicast|multicast) in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_out_cmd_vtysh, 
+       "clear ip bgp A.B.C.D out", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_database_cmd_vtysh, 
+       "show ip ospf database", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Database summary\n")
+
+DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_ifname_cmd_vtysh, 
+       "show ipv6 ospf6 interface IFNAME", 
+       "Show running system information\n"
+       "IPv6 Information\n"
+       "Open Shortest Path First (OSPF) for IPv6\n"
+       "Interface infomation\n"
+       "Interface name(e.g. ep0)\n"
+       )
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_cmd_vtysh, 
+       "clear ip bgp peer-group WORD", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all members of peer-group\n"
+       "BGP peer-group name\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_val2_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "maximum-prefix <1-4294967295> warning-only", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Maximum number of prefix accept from this peer\n"
+       "maximum no. of prefix limit\n"
+       "Only give warning message when limit is exceeded\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_flap_regexp_cmd_vtysh, 
+       "show ip bgp flap-statistics regexp .LINE", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display flap statistics of routes\n"
+       "Display routes matching the AS path regular expression\n"
+       "A regular-expression to match the BGP AS paths\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_soft_in_cmd_vtysh, 
+       "clear bgp <1-65535> soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh, 
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display information received from a BGP neighbor\n"
+       "Display the prefixlist filter\n")
+
+DEFSH (VTYSH_RIPD, rip_version_cmd_vtysh, 
+       "version <1-2>", 
+       "Set routing protocol version\n"
+       "version\n")
+
+DEFSH (VTYSH_RIPD, ip_rip_send_version_1_cmd_vtysh, 
+       "ip rip send version 1 2", 
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+
+DEFSH (VTYSH_RIPD, no_debug_rip_zebra_cmd_vtysh, 
+       "no debug rip zebra", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP and ZEBRA communication\n")
+
+DEFSH (VTYSH_BGPD, set_aspath_prepend_cmd_vtysh, 
+       "set as-path prepend .<1-65535>", 
+       "Set values in destination routing protocol\n"
+       "Prepend string for a BGP AS-path attribute\n"
+       "Prepend to the as-path\n"
+       "AS number\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_received_routes_cmd_vtysh, 
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the received routes from neighbor\n")
+
+DEFSH (VTYSH_RIPNGD, debug_ripng_packet_detail_cmd_vtysh, 
+       "debug ripng packet (recv|send) detail", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIPng configuration\n"
+       "Debug option set for ripng packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n"
+       "Debug option set detaied information\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_minadvertinterval_cmd_vtysh, 
+       "ip irdp minadvertinterval <3-1800>", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n"
+       "Set minimum time between advertisement\n"
+       "Minimum advertisement interval in seconds\n")
+
+DEFSH (VTYSH_OSPF6D, no_passive_interface_cmd_vtysh, 
+       "no passive-interface IFNAME", 
+       "Negate a command or set its defaults\n"
+       "Suppress routing updates on an interface\n"
+       "Interface name(e.g. ep0)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD, no_match_interface_val_cmd_vtysh, 
+       "no match interface WORD", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "Match first hop interface of route\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_BGPD, bgp_network_mask_natural_route_map_cmd_vtysh, 
+       "network A.B.C.D route-map WORD", 
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged9_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Med attribute\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n")
+
+DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_standard2_cmd_vtysh, 
+       "ip extcommunity-list standard WORD (deny|permit)", 
+       "IP information\n"
+       "Add a extended community list entry\n"
+       "Specify standard extcommunity-list\n"
+       "Extended Community list name\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_out_cmd_vtysh, 
+       "clear bgp ipv6 <1-65535> soft out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_standard_cmd_vtysh, 
+       "no ip community-list <1-99> (deny|permit) .AA:NN", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list number (standard)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n")
+
+DEFSH (VTYSH_BGPD, debug_bgp_update_direct_cmd_vtysh, 
+       "debug bgp updates (in|out)", 
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP updates\n"
+       "Inbound updates\n"
+       "Outbound updates\n")
+
+DEFSH (VTYSH_OSPFD, show_debugging_ospf_cmd_vtysh, 
+       "show debugging ospf", 
+       "Show running system information\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_cmd_vtysh, 
+       "default-information originate", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n")
+
+DEFSH (VTYSH_OSPF6D, ospf6_redistribute_cmd_vtysh, 
+       "redistribute (static|kernel|connected|ripng|bgp)", 
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+
+DEFSH (VTYSH_OSPFD, ip_ospf_transmit_delay_addr_cmd_vtysh, 
+       "ip ospf transmit-delay <1-65535> A.B.C.D", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Link state transmit delay\n"
+       "Seconds\n"
+       "Address of interface")
+
+DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community2_exact_cmd_vtysh, 
+       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "MBGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, area_export_list_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) export-list NAME", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Set the filter for networks announced to other areas\n"
+       "Name of the access-list\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, show_ip_prefix_list_detail_name_cmd_vtysh, 
+       "show ip prefix-list detail WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "Build a prefix list\n"
+       "Detail of prefix lists\n"
+       "Name of a prefix list\n")
+
+DEFSH (VTYSH_BGPD, bgp_damp_set3_cmd_vtysh, 
+       "bgp dampening", 
+       "BGP Specific commands\n"
+       "Enable route-flap dampening\n")
+
+DEFSH (VTYSH_OSPFD, debug_ospf_packet_send_recv_detail_cmd_vtysh, 
+       "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", 
+       "Debugging functions\n"
+       "OSPF information\n"
+       "OSPF packets\n"
+       "OSPF Hello\n"
+       "OSPF Database Description\n"
+       "OSPF Link State Request\n"
+       "OSPF Link State Update\n"
+       "OSPF Link State Acknowledgment\n"
+       "OSPF all packets\n"
+       "Packet sent\n"
+       "Packet received\n"
+       "Detail Information\n")
+
+DEFSH (VTYSH_BGPD, bgp_default_ipv4_unicast_cmd_vtysh, 
+       "bgp default ipv4-unicast", 
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "Activate ipv4-unicast for a peer by default\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_prefix_list_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Filter updates to/from this neighbor\n"
+       "Name of a prefix list\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
+
+DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, 
+       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", 
+       "Negate a command or set its defaults\n"
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Kernel routes\n"
+       "Open Shurtest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n"
+       "Metric for redistributed routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh, 
+       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, area_range_cost_cmd_vtysh, 
+       "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", 
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Configure OSPF area range for route summarization\n"
+       "area range prefix\n"
+       "User specified metric for this range\n"
+       "Advertised metric for this range\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_cmd_vtysh, 
+       "clear ip bgp *", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_cmd_vtysh, 
+       "clear ip bgp <1-65535>", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n")
+
+DEFSH (VTYSH_BGPD, no_ip_community_list_expanded_cmd_vtysh, 
+       "no ip community-list <100-199> (deny|permit) .LINE", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Add a community list entry\n"
+       "Community list number (expanded)\n"
+       "Specify community to reject\n"
+       "Specify community to accept\n"
+       "An ordered list as a regular-expression\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_tags_cmd_vtysh, 
+       "show ip bgp vpnv4 all tags", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "Display BGP tags for prefixes\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged3_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_prefix_cmd_vtysh, 
+       "show ip bgp vpnv4 all A.B.C.D/M", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n"
+       "IP prefix <network>/<length>,  e.g.,  35.0.0.0/8\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_in_prefix_filter_cmd_vtysh, 
+       "clear bgp <1-65535> in prefix-filter", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_BGPD, match_origin_cmd_vtysh, 
+       "match origin (egp|igp|incomplete)", 
+       "Match values from routing table\n"
+       "BGP origin code\n"
+       "remote EGP\n"
+       "local IGP\n"
+       "unknown heritage\n")
+
+DEFSH (VTYSH_OSPFD, no_debug_ospf_ism_cmd_vtysh, 
+       "no debug ospf ism", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "OSPF information\n"
+       "OSPF Interface State Machine")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_in_cmd_vtysh, 
+       "clear ip bgp A.B.C.D vpnv4 unicast in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh, 
+       "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n"
+       "Push out prefix-list ORF and do inbound soft reconfig\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_network_cmd_vtysh, 
+       "no ospf network", 
+       "Negate a command or set its defaults\n"
+       "OSPF interface commands\n"
+       "Network type\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_ipv6_prefix_list_le_ge_cmd_vtysh, 
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", 
+       "Negate a command or set its defaults\n"
+       "IPv6 information\n"
+       "Build a prefix list\n"
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_remote_as_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "remote-as <1-65535>", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Specify a BGP neighbor\n"
+       "AS number\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_cmd_vtysh, 
+       "show ip ospf neighbor", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Neighbor list\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_in_cmd_vtysh, 
+       "clear ip bgp <1-65535> soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, neighbor_capability_orf_prefix_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Advertise capability to the peer\n"
+       "Advertise ORF capability to the peer\n"
+       "Advertise prefixlist ORF capability to this neighbor\n"
+       "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+       "Capability to RECEIVE the ORF from this neighbor\n"
+       "Capability to SEND the ORF to this neighbor\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_as_out_cmd_vtysh, 
+       "clear bgp <1-65535> out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_detail_cmd_vtysh, 
+       "show ip ospf neighbor detail", 
+       "Show running system information\n"
+       "IP information\n"
+       "OSPF information\n"
+       "Neighbor list\n"
+       "detail of all neighbors\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_next_hop_prefix_list_cmd_vtysh, 
+       "match ip next-hop prefix-list WORD", 
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_OSPFD, no_ospf_distance_cmd_vtysh, 
+       "no distance <1-255>", 
+       "Negate a command or set its defaults\n"
+       "Define an administrative distance\n"
+       "OSPF Administrative distance\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_interface_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X) " "interface WORD", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Interface\n"
+       "Interface name\n")
+
+DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_cmd_vtysh, 
+       "default-information originate always metric-type (1|2)", 
+       "Control distribution of default information\n"
+       "Distribute a default route\n"
+       "Always advertise default route\n"
+       "OSPF metric type for default routes\n"
+       "Set OSPF External Type 1 metrics\n"
+       "Set OSPF External Type 2 metrics\n")
+
+DEFSH (VTYSH_RIPNGD, no_ripng_default_metric_val_cmd_vtysh, 
+       "no default-metric <1-16>", 
+       "Negate a command or set its defaults\n"
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_route_map_cmd_vtysh, 
+       "show ip bgp route-map WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the route-map\n"
+       "A route-map to match on\n")
+
+DEFSH (VTYSH_BGPD, set_originator_id_cmd_vtysh, 
+       "set originator-id A.B.C.D", 
+       "Set values in destination routing protocol\n"
+       "BGP originator ID attribute\n"
+       "IP address of originator\n")
+
+DEFSH (VTYSH_RIPD, debug_rip_packet_direct_cmd_vtysh, 
+       "debug rip packet (recv|send)", 
+       "Debugging functions (see also 'undebug')\n"
+       "RIP information\n"
+       "RIP packet\n"
+       "RIP receive packet\n"
+       "RIP send packet\n")
+
+DEFSH (VTYSH_BGPD, no_aggregate_address_summary_only_cmd_vtysh, 
+       "no aggregate-address A.B.C.D/M summary-only", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_view_route_cmd_vtysh, 
+       "show ip bgp view WORD A.B.C.D", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "BGP view\n"
+       "BGP view name\n"
+       "Network in the BGP routing table to display\n")
+
+DEFSH (VTYSH_RIPD, no_ip_rip_receive_version_num_cmd_vtysh, 
+       "no ip rip receive version (1|2)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "Version 1\n"
+       "Version 2\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh, 
+       "clear ip bgp * vpnv4 unicast soft in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_RIPD, accept_lifetime_duration_day_month_cmd_vtysh, 
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", 
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_cmd_vtysh, 
+       "no match ip address", 
+       "Negate a command or set its defaults\n"
+       "Match values from routing table\n"
+       "IP information\n"
+       "Match address of route\n")
+
+DEFSH (VTYSH_ZEBRA, show_ipv6_route_protocol_cmd_vtysh, 
+       "show ipv6 route (bgp|connected|kernel|ospf6|ripng|static)", 
+       "Show running system information\n"
+       "IP information\n"
+       "IP routing table\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Connected\n"
+       "Kernel\n"
+       "Open Shortest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+
+DEFSH (VTYSH_ZEBRA, ip_address_label_cmd_vtysh, 
+       "ip address A.B.C.D/M label LINE", 
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Label of this address\n"
+       "Label\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_community4_exact_cmd_vtysh, 
+       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_priority_addr_cmd_vtysh, 
+       "no ip ospf priority A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Router priority\n"
+       "Address of interface")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbors_peer_cmd_vtysh, 
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n")
+
+DEFSH (VTYSH_OSPFD, auto_cost_reference_bandwidth_cmd_vtysh, 
+       "auto-cost reference-bandwidth <1-4294967>", 
+       "Calculate OSPF interface cost according to bandwidth\n"
+       "Use reference bandwidth method to assign OSPF cost\n"
+       "The reference bandwidth in terms of Mbits per second\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_out_cmd_vtysh, 
+       "clear bgp ipv6 * out", 
+       "Reset functions\n"
+       "BGP information\n"
+       "Address family\n"
+       "Clear all peers\n"
+       "Soft reconfig outbound update\n")
+
+DEFSH (VTYSH_BGPD, aggregate_address_cmd_vtysh, 
+       "aggregate-address A.B.C.D/M", 
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_exact_cmd_vtysh, 
+       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "Exact match of the communities")
+
+DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_local_cmd_vtysh, 
+       "no set ipv6 next-hop local", 
+       "Negate a command or set its defaults\n"
+       "Set values in destination routing protocol\n"
+       "IPv6 information\n"
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n")
+
+DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_in_cmd_vtysh, 
+       "clear bgp view WORD * soft in", 
+       "Reset functions\n"
+       "BGP information\n"
+       "BGP view\n"
+       "view name\n"
+       "Clear all peers\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_list_cmd_vtysh, 
+       "show ip bgp prefix-list WORD", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display routes conforming to the prefix-list\n"
+       "IP prefix-list name\n")
+
+DEFSH (VTYSH_BGPD, neighbor_set_peer_group_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD", 
+       "Specify neighbor router\n"
+       "Neighbor address\nIPv6 address\n"
+       "Member of the peer-group\n"
+       "peer-group name\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_any_cmd_vtysh, 
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) any", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any source host\n")
+
+DEFSH (VTYSH_BGPD, no_auto_summary_cmd_vtysh, 
+       "no auto-summary", 
+       "Negate a command or set its defaults\n"
+       "Enable automatic network number summarization\n")
+
+DEFSH (VTYSH_OSPFD, no_ip_ospf_network_cmd_vtysh, 
+       "no ip ospf network", 
+       "Negate a command or set its defaults\n"
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Network type\n")
+
+DEFSH (VTYSH_BGPD, neighbor_attr_unchanged3_cmd_vtysh, 
+       "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)", 
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "BGP attribute is propagated unchanged to this neighbor\n"
+       "Nexthop attribute\n"
+       "As-path attribute\n"
+       "Med attribute\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_mask_any_cmd_vtysh, 
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", 
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Any destination host\n")
+
+DEFSH (VTYSH_BGPD, no_ipv6_aggregate_address_summary_only_cmd_vtysh, 
+       "no aggregate-address X:X::X:X/M summary-only", 
+       "Negate a command or set its defaults\n"
+       "Configure BGP aggregate entries\n"
+       "Aggregate prefix\n"
+       "Filter more specific routes from updates\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_nomask_cmd_vtysh, 
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n")
+
+DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_list_exact_cmd_vtysh, 
+       "show bgp ipv6 community-list WORD exact-match", 
+       "Show running system information\n"
+       "BGP information\n"
+       "Address family\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_in_cmd_vtysh, 
+       "clear ip bgp <1-65535> vpnv4 unicast in", 
+       "Reset functions\n"
+       "IP information\n"
+       "BGP information\n"
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
+DEFSH (VTYSH_OSPFD, ip_ospf_retransmit_interval_cmd_vtysh, 
+       "ip ospf retransmit-interval <3-65535>", 
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Time between retransmitting lost link state advertisements\n"
+       "Seconds\n")
+
+DEFSH (VTYSH_ZEBRA, no_ip_route_cmd_vtysh, 
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE)", 
+       "Negate a command or set its defaults\n"
+       "IP information\n"
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_cmd_vtysh, 
+       "show ip bgp vpnv4 all", 
+       "Show running system information\n"
+       "IP information\n"
+       "BGP information\n"
+       "Display VPNv4 NLRI specific information\n"
+       "Display information about all VPNv4 NLRIs\n")
+
+DEFSH (VTYSH_RIPD, no_key_string_cmd_vtysh, 
+       "no key-string [LINE]", 
+       "Negate a command or set its defaults\n"
+       "Unset key string\n"
+       "The key\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_soft_reconfiguration_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Per neighbor soft reconfiguration\n"
+       "Allow inbound soft reconfiguration for this neighbor\n")
+
+DEFSH (VTYSH_BGPD, no_debug_bgp_events_cmd_vtysh, 
+       "no debug bgp events", 
+       "Negate a command or set its defaults\n"
+       "Debugging functions (see also 'undebug')\n"
+       "BGP information\n"
+       "BGP events\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) ", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n")
+
+DEFSH (VTYSH_ZEBRA, ip_irdp_holdtime_cmd_vtysh, 
+       "ip irdp holdtime <0-9000>", 
+       "IP information\n"
+       "ICMP Router discovery on this interface\n"
+       "Set holdtime value\n"
+       "Holdtime value in seconds. Default is 1800 seconds\n")
+
+DEFSH (VTYSH_BGPD, match_community_cmd_vtysh, 
+       "match community (<1-99>|<100-199>|WORD)", 
+       "Match values from routing table\n"
+       "Match BGP community list\n"
+       "Community-list number (standard)\n"
+       "Community-list number (expanded)\n"
+       "Community-list name\n")
+
+DEFSH (VTYSH_BGPD, show_ip_extcommunity_list_cmd_vtysh, 
+       "show ip extcommunity-list", 
+       "Show running system information\n"
+       "IP information\n"
+       "List extended-community list\n")
+
+DEFSH (VTYSH_OSPF6D, no_interface_area_cmd_vtysh, 
+       "no interface IFNAME area A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Disable routing on an IPv6 interface\n"
+       "Interface name(e.g. ep0)\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_mask_cmd_vtysh, 
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", 
+       "Negate a command or set its defaults\n"
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+
+DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_cmd_vtysh, 
+       "access-list WORD (deny|permit) A.B.C.D/M", 
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+
+DEFSH (VTYSH_OSPFD, no_area_range_cmd_vtysh, 
+       "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", 
+       "Negate a command or set its defaults\n"
+       "OSPF area parameters\n"
+       "OSPF area ID in IP address format\n"
+       "OSPF area ID as a decimal value\n"
+       "Deconfigure OSPF area range for route summarization\n"
+       "area range prefix\n")
+
+DEFSH (VTYSH_BGPD, old_ipv6_bgp_network_cmd_vtysh, 
+       "ipv6 bgp network X:X::X:X/M", 
+       "IPv6 information\n"
+       "BGP information\n"
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+
+DEFSH (VTYSH_BGPD, no_neighbor_filter_list_cmd_vtysh, 
+       "no neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)", 
+       "Negate a command or set its defaults\n"
+       "Specify neighbor router\n"
+       "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+       "Establish BGP filters\n"
+       "AS path access-list name\n"
+       "Filter incoming routes\n"
+       "Filter outgoing routes\n")
+
+DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_list_exact_cmd_vtysh, 
+       "show ipv6 bgp community-list WORD exact-match", 
+       "Show running system information\n"
+       "IPv6 information\n"
+       "BGP information\n"
+       "Display routes matching the community-list\n"
+       "community-list name\n"
+       "Exact match of the communities\n")
+
+DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_routemap_cmd_vtysh, 
+       "redistribute connected route-map WORD", 
+       "Redistribute information from another routing protocol\n"
+       "Connected\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+
+DEFSH (VTYSH_BGPD, undebug_bgp_events_cmd_vtysh, 
+       "undebug bgp events", 
+       "Disable debugging functions (see also 'debug')\n"
+       "BGP information\n"
+       "BGP events\n")
+
+void
+vtysh_init_cmd ()
+{
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_all_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_instance_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd_vtysh);
+  install_element (OSPF_NODE, &no_network_area_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_version_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_name_all_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_type_routemap_cmd_vtysh);
+  install_element (OSPF6_NODE, &interface_area_passive_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_standard_nomask_cmd_vtysh);
+  install_element (RMAP_NODE, &match_aspath_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_nsm_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_metric_type_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_any_host_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh);
+  install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd_vtysh);
+  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_timers_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd_vtysh);
+  install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd_vtysh);
+  install_element (OSPF6_NODE, &interface_area_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_zebra_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_origin_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ip_address_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_paths_cmd_vtysh);
+  install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_timers_connect_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd_vtysh);
+  install_element (RIPNG_NODE, &default_information_originate_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd_vtysh);
+  install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_as_path_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_normal_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh);
+  install_element (RMAP_NODE, &match_metric_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh);
+  install_element (KEYCHAIN_NODE, &no_key_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_cost_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &router_zebra_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ipv6_next_hop_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_router_zebra_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_summary_cmd_vtysh);
+  install_element (OSPF_NODE, &neighbor_pollinterval_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_route_pref_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_zebra_packet_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_local_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_send_community_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_damp_set3_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community_all_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ripng_packet_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_always_compare_med_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_events_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd_vtysh);
+  install_element (RMAP_NODE, &match_community_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_routemap_cmd_vtysh);
+  install_element (CONFIG_NODE, &bgp_config_type_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_all_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_remark_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_confederation_peers_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_bestpath_med3_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (OSPF_NODE, &area_authentication_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_timers_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_address_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_event_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_community_val_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh);
+  install_element (OSPF6_NODE, &interface_area_plist_passive_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd_vtysh);
+  install_element (OSPF_NODE, &neighbor_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_distance_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_network_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd_vtysh);
+  install_element (OSPF_NODE, &no_passive_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_cmd_vtysh);
+  install_element (KEYCHAIN_NODE, &no_key_chain_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_view_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community4_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_address_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_cluster_id_cmd_vtysh);
+  install_element (OSPF_NODE, &no_neighbor_priority_pollinterval_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_confederation_peers_cmd_vtysh);
+  install_element (RMAP_NODE, &set_local_pref_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_peer_group_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_import_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_mask_cmd_vtysh);
+  install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd_vtysh);
+  install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_local_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd_vtysh);
+  install_element (RMAP_NODE, &set_community_none_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_update_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_route_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_default_local_preference_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_transparent_nexthop_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_passive_interface_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ripng_zebra_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_bgp_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_distribute_list_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_param4_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_nexthop_self_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_route_pref_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_damp_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_route_mask_pref_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_events_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+  install_element (RMAP_NODE, &set_origin_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_debug_ospf6_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd_vtysh);
+  install_element (RMAP_NODE, &set_community_delete_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_capability_dynamic_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_rip_zebra_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_description_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_weight_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_address_label_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd_vtysh);
+  install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_cmd_vtysh);
+  install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_update_source_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_route_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_host_any_cmd_vtysh);
+  install_element (RIP_NODE, &rip_default_information_originate_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_distance_source_access_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd_vtysh);
+  install_element (OSPF6_NODE, &ospf6_redistribute_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ipv6_address_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_debugging_bgp_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_standard_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community2_exact_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_cmd_vtysh);
+  install_element (OSPF_NODE, &network_area_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_version_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_damp_set2_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_node_cmd_vtysh);
+  install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_route_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_param3_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_rip_zebra_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_enforce_first_as_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_export_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_router_id_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_route_mask_pref_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_route_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_update_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ripng_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_route_addr_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_import_check_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd_vtysh);
+  install_element (RIP_NODE, &rip_network_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_router_id_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_default_metric_val_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_route_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+  install_element (OSPF6_NODE, &interface_area_plist_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_default_originate_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd_vtysh);
+  install_element (RIP_NODE, &rip_timers_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_update_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd_vtysh);
+  install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_activate_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_standard_host_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_force_prefix_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_cost_addr_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (INTERFACE_NODE, &multicast_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_deterministic_med_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_routemap_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd_vtysh);
+  install_element (RMAP_NODE, &set_community_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_activate_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_priority_cmd_vtysh);
+  install_element (CONFIG_NODE, &dump_bgp_routes_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community3_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_metric_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distribute_list_out_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_cluster_id_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (OSPF_NODE, &no_auto_cost_reference_bandwidth_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_timers_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh);
+  install_element (RIP_NODE, &rip_offset_list_ifname_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (RMAP_NODE, &rmap_onmatch_next_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_routemap_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_filter_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_addr_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_distance_source_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_as_set_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_zebra_interface_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd_vtysh);
+  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_authtype_md5_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_filter_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_origin_val_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_event_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd_vtysh);
+  install_element (INTERFACE_NODE, &bandwidth_if_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authtype_authkey_cmd_vtysh);
+  install_element (OSPF_NODE, &area_range_advertise_cost_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (OSPF_NODE, &no_neighbor_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_aspath_prepend_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh);
+  install_element (OSPF_NODE, &area_stub_cmd_vtysh);
+  install_element (OSPF_NODE, &area_authentication_message_digest_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_filter_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_ism_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_cost_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd_vtysh);
+  install_element (RMAP_NODE, &set_ip_nexthop_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_event_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_activate_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_fsm_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_override_capability_cmd_vtysh);
+  install_element (VIEW_NODE, &show_table_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_routemap_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_cost_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community2_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh);
+  install_element (CONFIG_NODE, &dump_bgp_all_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ripng_packet_detail_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_as_set_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_distance2_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_param2_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh);
+  install_element (OSPF_NODE, &auto_cost_reference_bandwidth_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_route_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_filter_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_debugging_ripng_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd_vtysh);
+  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_scan_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh);
+  install_element (OSPF_NODE, &no_refresh_timer_val_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_local_pref_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_distance_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_weight_val_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_debugging_zebra_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_backdoor_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_cmd_vtysh);
+  install_element (OSPF_NODE, &area_range_cost_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_zebra_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd_vtysh);
+  install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_priority_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_lsa_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_rip_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_remove_private_as_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_standard_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh);
+  install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authkey_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_router_bgp_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_timers_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_in_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_dead_interval_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh);
+  install_element (OSPF_NODE, &area_shortcut_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_bgp_config_type_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_regexp_cmd_vtysh);
+  install_element (RMAP_NODE, &match_origin_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_out_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_table_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd_vtysh);
+  install_element (RIP_NODE, &rip_default_metric_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_param3_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_md5_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_set_peer_group_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh);
+  install_element (BGP_NODE, &old_ipv6_bgp_network_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_local_pref_val_cmd_vtysh);
+  install_element (OSPF_NODE, &no_neighbor_pollinterval_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd_vtysh);
+  install_element (RIP_NODE, &rip_distance_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_weight_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_rip_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd_vtysh);
+  install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_access_list_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_network_cmd_vtysh);
+  install_element (OSPF_NODE, &no_router_id_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+  install_element (BGP_NODE, &no_synchronization_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_update_source_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_address_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_rip_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_standard_host_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh);
+  install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_range_advertise_cost_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_prefix_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_preference_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_passive_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community4_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_originator_id_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_forwarding_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh);
+  install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_val_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_scan_time_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_prefix_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_param2_cmd_vtysh);
+  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_summary_only_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd_vtysh);
+  install_element (RMAP_NODE, &set_originator_id_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_cluster_id32_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_access_list_any_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_range_cost_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_param4_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_forwarding_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community_cmd_vtysh);
+  install_element (RMAP_NODE, &set_ecommunity_rt_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd_vtysh);
+  install_element (OSPF_NODE, &timers_spf_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_port_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_community_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_zebra_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf6_all_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_zebra_kernel_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &dump_bgp_updates_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_always_compare_med_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_address_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd_vtysh);
+  install_element (VIEW_NODE, &show_debug_ospf6_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ripng_events_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_authtype_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_remote_as_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd_vtysh);
+  install_element (ENABLE_NODE, &reload_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd_vtysh);
+  install_element (RMAP_NODE, &set_metric_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_distance_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_route_mask_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community2_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_default_originate_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_distance_source_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_filter_list_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_standard_any_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_cost_addr_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_fsm_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd_vtysh);
+  install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_route_pref_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_as_path_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_access_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_filter_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_scan_time_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_route_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_priority_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_authkey_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_param1_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_debugging_rip_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_route_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_default_metric_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_bandwidth_if_cmd_vtysh);
+  install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_interface_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_default_metric_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_timers_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community_list_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_routemap_cmd_vtysh);
+  install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd_vtysh);
+  install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+  install_element (INTERFACE_NODE, &shutdown_if_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_routemap_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_address_secondary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd_vtysh);
+  install_element (RIP_NODE, &rip_distance_source_cmd_vtysh);
+  install_element (OSPF_NODE, &router_id_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_all_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_community_delete_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_addr_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ip_address_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_standard_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community_list_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_nsm_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_route_map_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_key_chain_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_all_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_community_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_aggregator_as_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh);
+  install_element (OSPF_NODE, &no_refresh_timer_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_mask_natural_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_forwarding_cmd_vtysh);
+  install_element (RIP_NODE, &rip_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_rip_packet_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (OSPF_NODE, &neighbor_priority_pollinterval_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_port_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_damp_unset_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd_vtysh);
+  install_element (BGP_NODE, &no_auto_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_send_community_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd_vtysh);
+  install_element (OSPF_NODE, &area_range_advertise_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_expanded_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_rip_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd_vtysh);
+  install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_args_addr_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_metric_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_version_ospf6_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_metric_routemap_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_passive_interface_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_interface_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authtype_args_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authtype_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_community_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd_vtysh);
+  install_element (OSPF_NODE, &area_filter_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_unsuppress_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_interface_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_description_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_remark_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_range_subst_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_network_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_zebra_events_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_origin_val_cmd_vtysh);
+  install_element (OSPF_NODE, &area_default_cost_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &key_string_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd_vtysh);
+  install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_node_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_enforce_multihop_cmd_vtysh);
+  install_element (RMAP_NODE, &set_weight_cmd_vtysh);
+  install_element (VIEW_NODE, &show_debugging_ripng_cmd_vtysh);
+  install_element (OSPF_NODE, &area_import_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_default_information_originate_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_stub_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_network_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ripng_events_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_default_local_preference_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_community_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_debugging_zebra_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community4_exact_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authtype_args_md5_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_access_list_name_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_range_not_advertise_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_routemap_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community3_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh);
+  install_element (CONFIG_NODE, &bgp_multiple_instance_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_router_rip_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_metric_val_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_originator_id_val_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_bestpath_med_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_md5_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_le_cmd_vtysh);
+  install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd_vtysh);
+  install_element (OSPF_NODE, &passive_interface_addr_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_default_metric_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &bgp_network_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_community_list_arg_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_as_path_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_bestpath_med_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_view_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_community_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_authtype_authkey_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_normal_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_abr_type_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh);
+  install_element (RIP_NODE, &rip_redistribute_type_metric_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_network_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_transparent_as_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_route_map_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_any_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_bgp_update_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_metric_val_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_authentication_key_cmd_vtysh);
+  install_element (RMAP_NODE, &set_aggregator_as_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd_vtysh);
+  install_element (RIP_NODE, &rip_version_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_remote_as_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_debugging_ospf_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_route_addr_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_access_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_strict_capability_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ripng_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh);
+  install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_default_metric_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_protocols_rip_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community3_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_peer_group_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authtype_md5_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd_vtysh);
+  install_element (OSPF_NODE, &passive_interface_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_advertise_interval_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_dump_bgp_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_route_protocol_cmd_vtysh);
+  install_element (OSPF_NODE, &area_export_list_cmd_vtysh);
+  install_element (OSPF6_NODE, &router_id_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_abr_type_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_aspath_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_shortcut_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_zebra_kernel_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_distance_source_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_host_host_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_interface_ip_ospf_authentication_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ripng_packet_detail_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_route_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd_vtysh);
+  install_element (ZEBRA_NODE, &redistribute_ospf6_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_forwarding_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_deterministic_med_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_mask_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_description_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd_vtysh);
+  install_element (RMAP_NODE, &match_community_exact_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_fast_external_failover_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_mask_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_community_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_distance_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_route_supernets_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_router_id_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_community_delete_val_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_vlink_param1_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd_vtysh);
+  install_element (OSPF_NODE, &refresh_timer_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_zebra_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_rip_packet_cmd_vtysh);
+  install_element (VIEW_NODE, &show_version_ospf6_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_route_supernets_cmd_vtysh);
+  install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd_vtysh);
+  install_element (RMAP_NODE, &rmap_onmatch_goto_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_ism_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_range_advertise_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ripng_zebra_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community3_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community4_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_range_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_local_as_val_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_route_map_all_cmd_vtysh);
+  install_element (OSPF_NODE, &no_passive_interface_addr_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_rip_events_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_passive_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_backdoor_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd_vtysh);
+  install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_exact_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_cmd_vtysh);
+  install_element (CONFIG_NODE, &config_table_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_filter_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_zebra_packet_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_type_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh);
+  install_element (OSPF6_NODE, &area_range_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_rip_events_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd_vtysh);
+  install_element (RMAP_NODE, &match_interface_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_community_exact_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_version_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_standard_any_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_any_any_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ripng_packet_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (RIP_NODE, &rip_offset_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_import_check_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_default_cost_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_offset_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_lsa_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd_vtysh);
+  install_element (OSPF_NODE, &area_range_not_advertise_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_zebra_client_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd_vtysh);
+  install_element (OSPF_NODE, &area_range_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_cmd_vtysh);
+  install_element (RIP_NODE, &rip_distance_source_access_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_router_bgp_view_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_shutdown_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_redistribute_type_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh);
+  install_element (OSPF_NODE, &no_neighbor_priority_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_route_mask_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_shutdown_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_regexp_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_route_map_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_origin_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_network_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_weight_val_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_multicast_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_prefix_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_database_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_authtype_args_authkey_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd_vtysh);
+  install_element (OSPF_NODE, &neighbor_priority_cmd_vtysh);
+  install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_exact_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_weight_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_timers_connect_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_community_none_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_version_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_interface_ip_ospf_authentication_addr_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_ospf_route_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_aspath_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_normal_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_bestpath_med2_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_shutdown_if_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh);
+  install_element (RMAP_NODE, &set_metric_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_always_routemap_cmd_vtysh);
+  install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd_vtysh);
+  install_element (RMAP_NODE, &set_atomic_aggregate_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_scan_time_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_update_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd_vtysh);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh);
+  install_element (RIP_NODE, &rip_passive_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh);
+  install_element (RMAP_NODE, &set_aspath_prepend_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_activate_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_timers_arg_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_address_label_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_zebra_events_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_ospf_interface_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_standard2_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (OSPF6_NODE, &no_interface_area_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ripng_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh);
+  install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd_vtysh);
+  install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd_vtysh);
+  install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_default_information_originate_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_summary_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_hello_interval_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community_all_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_timers_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_override_capability_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val2_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_mask_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_neighbor_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_route_protocol_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_external_in_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd_vtysh);
+  install_element (OSPF_NODE, &area_vlink_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_event_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd_vtysh);
+  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_type_routemap_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh);
+  install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ipv6_address_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_router_id_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_confederation_identifier_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd_vtysh);
+  install_element (INTERFACE_NODE, &interface_ip_ospf_authentication_args_cmd_vtysh);
+  install_element (OSPF6_NODE, &passive_interface_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_route_server_client_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_any_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_send_community_type_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh);
+  install_element (RIPNG_NODE, &ripng_aggregate_address_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_port_val_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_ip_address_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_prefix_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_description_val_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community_exact_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_damp_unset2_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_routemap_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_send_community_type_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ospf_network_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_neighbors_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_stub_nosum_cmd_vtysh);
+  install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd_vtysh);
+  install_element (OSPF_NODE, &area_range_subst_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd_vtysh);
+  install_element (ENABLE_NODE, &debug_bgp_filter_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_route_map_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh);
+  install_element (RIP_NODE, &rip_neighbor_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_debug_rip_packet_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_events_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_allowas_in_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd_vtysh);
+  install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd_vtysh);
+  install_element (VIEW_NODE, &show_zebra_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh);
+  install_element (RIP_NODE, &no_rip_network_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd_vtysh);
+  install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd_vtysh);
+  install_element (OSPF6_NODE, &no_passive_interface_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_zebra_events_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_route_reflector_client_cmd_vtysh);
+  install_element (RMAP_NODE, &set_ecommunity_soo_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_route_cmd_vtysh);
+  install_element (RIP_NODE, &rip_redistribute_type_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_rip_packet_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_force_prefix_cmd_vtysh);
+  install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd_vtysh);
+  install_element (BGP_NODE, &no_bgp_router_id_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd_vtysh);
+  install_element (OSPF_NODE, &no_area_authentication_cmd_vtysh);
+  install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_strict_capability_cmd_vtysh);
+  install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd_vtysh);
+  install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_router_ospf_cmd_vtysh);
+  install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd_vtysh);
+  install_element (ENABLE_NODE, &no_debug_ripng_events_cmd_vtysh);
+  install_element (OSPF_NODE, &no_timers_spf_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd_vtysh);
+  install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd_vtysh);
+  install_element (INTERFACE_NODE, &rip_split_horizon_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd_vtysh);
+  install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd_vtysh);
+  install_element (RMAP_NODE, &no_match_interface_val_cmd_vtysh);
+  install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd_vtysh);
+  install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd_vtysh);
+  install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd_vtysh);
+  install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd_vtysh);
+  install_element (BGP_NODE, &bgp_timers_cmd_vtysh);
+  install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh);
+  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd_vtysh);
+  install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd_vtysh);
+  install_element (OSPF_NODE, &area_stub_nosum_cmd_vtysh);
+  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd_vtysh);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd_vtysh);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd_vtysh);
+}
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
new file mode 100644 (file)
index 0000000..b9c9ad6
--- /dev/null
@@ -0,0 +1,426 @@
+/* Configuration generator.
+   Copyright (C) 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "linklist.h"
+#include "memory.h"
+
+#include "vtysh/vtysh.h"
+
+vector configvec;
+
+struct config
+{
+  /* Configuration node name. */
+  char *name;
+
+  /* Configuration string line. */
+  struct list *line;
+
+  /* Configuration can be nest. */
+  struct config *config;
+
+  /* Index of this config. */
+  u_int32_t index;
+};
+
+struct list *config_top;
+\f
+int
+line_cmp (char *c1, char *c2)
+{
+  return strcmp (c1, c2);
+}
+
+void
+line_del (char *line)
+{
+  XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
+}
+
+struct config *
+config_new ()
+{
+  struct config *config;
+  config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
+  return config;
+}
+
+int
+config_cmp (struct config *c1, struct config *c2)
+{
+  return strcmp (c1->name, c2->name);
+}
+
+void
+config_del (struct config* config)
+{
+  list_delete (config->line);
+  if (config->name)
+    XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
+  XFREE (MTYPE_VTYSH_CONFIG, config);
+}
+
+struct config *
+config_get (int index, char *line)
+{
+  struct config *config;
+  struct config *config_loop;
+  struct list *master;
+  struct listnode *nn;
+
+  config = config_loop = NULL;
+
+  master = vector_lookup_ensure (configvec, index);
+
+  if (! master)
+    {
+      master = list_new ();
+      master->del = (void (*) (void *))config_del;
+      master->cmp = (int (*)(void *, void *)) config_cmp;
+      vector_set_index (configvec, index, master);
+    }
+  
+  LIST_LOOP (master, config_loop, nn)
+    {
+      if (strcmp (config_loop->name, line) == 0)
+       config = config_loop;
+    }
+
+  if (! config)
+    {
+      config = config_new ();
+      config->line = list_new ();
+      config->line->del = (void (*) (void *))line_del;
+      config->line->cmp = (int (*)(void *, void *)) line_cmp;
+      config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
+      config->index = index;
+      listnode_add (master, config);
+    }
+  return config;
+}
+
+void
+config_add_line (struct list *config, char *line)
+{
+  listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
+}
+
+void
+config_add_line_uniq (struct list *config, char *line)
+{
+  struct listnode *nn;
+  char *pnt;
+
+  LIST_LOOP (config, pnt, nn)
+    {
+      if (strcmp (pnt, line) == 0)
+       return;
+    }
+  listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
+}
+
+void
+vtysh_config_parse_line (char *line)
+{
+  char c;
+  static struct config *config = NULL;
+
+  if (! line)
+    return;
+
+  c = line[0];
+
+  if (c == '\0')
+    return;
+
+  /* printf ("[%s]\n", line); */
+
+  switch (c)
+    {
+    case '!':
+    case '#':
+      break;
+    case ' ':
+      /* Store line to current configuration. */
+      if (config)
+       {
+         if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0)
+           config = config_get (BGP_VPNV4_NODE, line);
+         else if (strncmp (line, " address-family ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0)
+           config = config_get (BGP_IPV4M_NODE, line);
+         else if (strncmp (line, " address-family ipv6", strlen (" address-family ipv6")) == 0)
+           config = config_get (BGP_IPV6_NODE, line);
+         else if (config->index == RMAP_NODE)
+           config_add_line_uniq (config->line, line);
+         else
+           config_add_line (config->line, line);
+       }
+      else
+       config_add_line (config_top, line);
+      break;
+    default:
+      if (strncmp (line, "interface", strlen ("interface")) == 0)
+       config = config_get (INTERFACE_NODE, line);
+      else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
+       config = config_get (RIP_NODE, line);
+      else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
+       config = config_get (OSPF_NODE, line);
+      else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
+       config = config_get (BGP_NODE, line);
+      else if (strncmp (line, "router", strlen ("router")) == 0)
+       config = config_get (BGP_NODE, line);
+      else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
+       config = config_get (RMAP_NODE, line);
+      else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
+       config = config_get (ACCESS_NODE, line);
+      else if (strncmp (line, "ip prefix-list", strlen ("ip prefix-list")) == 0)
+       config = config_get (PREFIX_NODE, line);
+      else if (strncmp (line, "ip as-path access-list", strlen ("ip as-path access-list")) == 0)
+       config = config_get (AS_LIST_NODE, line);
+      else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0)
+       config = config_get (COMMUNITY_LIST_NODE, line);
+      else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
+       config = config_get (IP_NODE, line);
+      else if (strncmp (line, "key", strlen ("key")) == 0)
+       config = config_get (KEYCHAIN_NODE, line);
+      else
+       {
+         if (strncmp (line, "log", strlen ("log")) == 0
+             || strncmp (line, "hostname", strlen ("hostname")) == 0
+             || strncmp (line, "password", strlen ("hostname")) == 0)
+           config_add_line_uniq (config_top, line);
+         else
+           config_add_line (config_top, line);
+         config = NULL;
+       }
+      break;
+    }
+}
+
+void
+vtysh_config_parse (char *line)
+{
+  char *begin;
+  char *pnt;
+  
+  begin = pnt = line;
+
+  while (*pnt != '\0')
+    {
+      if (*pnt == '\n')
+       {
+         *pnt++ = '\0';
+         vtysh_config_parse_line (begin);
+         begin = pnt;
+       }
+      else
+       {
+         pnt++;
+       }
+    }
+}
+
+/* Macro to check delimiter is needed between each configuration line
+   or not.  */
+#define NO_DELIMITER(I)  \
+  ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
+   || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE)
+
+/* Display configuration to file pointer.  */
+void
+vtysh_config_dump (FILE *fp)
+{
+  struct listnode *nn;
+  struct listnode *nm;
+  struct config *config;
+  struct list *master;
+  char *line;
+  int i;
+
+  LIST_LOOP (config_top, line, nn)
+    {
+      fprintf (fp, "%s\n", line);
+      fflush (fp);
+    }
+  fprintf (fp, "!\n");
+  fflush (fp);
+
+  for (i = 0; i < vector_max (configvec); i++)
+    if ((master = vector_slot (configvec, i)) != NULL)
+      {
+       LIST_LOOP (master, config, nn)
+         {
+           fprintf (fp, "%s\n", config->name);
+            fflush (fp);
+
+           LIST_LOOP (config->line, line, nm)
+             {
+               fprintf  (fp, "%s\n", line);
+               fflush (fp);
+             }
+           if (! NO_DELIMITER (i))
+             {
+               fprintf (fp, "!\n");
+               fflush (fp);
+             }
+         }
+       if (NO_DELIMITER (i))
+         {
+           fprintf (fp, "!\n");
+           fflush (fp);
+         }
+      }
+
+  for (i = 0; i < vector_max (configvec); i++)
+    if ((master = vector_slot (configvec, i)) != NULL)
+      {
+       list_delete (master);
+       vector_slot (configvec, i) = NULL;
+      }
+  list_delete_all_node (config_top);
+}
+
+/* Read up configuration file from file_name. */
+static void
+vtysh_read_file (FILE *confp)
+{
+  int ret;
+  struct vty *vty;
+
+  vty = vty_new ();
+  vty->fd = 0;                 /* stdout */
+  vty->type = VTY_TERM;
+  vty->node = CONFIG_NODE;
+  
+  vtysh_execute_no_pager ("enable");
+  vtysh_execute_no_pager ("configure terminal");
+
+  /* Execute configuration file */
+  ret = vtysh_config_from_file (vty, confp);
+
+  vtysh_execute_no_pager ("end");
+  vtysh_execute_no_pager ("disable");
+
+  vty_close (vty);
+
+  if (ret != CMD_SUCCESS) 
+    {
+      switch (ret)
+       {
+       case CMD_ERR_AMBIGUOUS:
+         fprintf (stderr, "Ambiguous command.\n");
+         break;
+       case CMD_ERR_NO_MATCH:
+         fprintf (stderr, "There is no such command.\n");
+         break;
+       }
+      fprintf (stderr, "Error occured during reading below line.\n%s\n", 
+              vty->buf);
+      exit (1);
+    }
+}
+
+/* Read up configuration file from file_name. */
+void
+vtysh_read_config (char *config_file,
+                  char *config_current_dir,
+                  char *config_default_dir)
+{
+  char *cwd;
+  FILE *confp = NULL;
+  char *fullpath;
+
+  /* If -f flag specified. */
+  if (config_file != NULL)
+    {
+      if (! IS_DIRECTORY_SEP (config_file[0]))
+       {
+         cwd = getcwd (NULL, MAXPATHLEN);
+         fullpath = XMALLOC (MTYPE_TMP, 
+                             strlen (cwd) + strlen (config_file) + 2);
+         sprintf (fullpath, "%s/%s", cwd, config_file);
+       }
+      else
+       fullpath = config_file;
+
+      confp = fopen (fullpath, "r");
+
+      if (confp == NULL)
+       {
+         fprintf (stderr, "can't open configuration file [%s]\n", 
+                  config_file);
+         exit(1);
+       }
+    }
+  else
+    {
+      /* Relative path configuration file open. */
+      if (config_current_dir)
+       confp = fopen (config_current_dir, "r");
+
+      /* If there is no relative path exists, open system default file. */
+      if (confp == NULL)
+       {
+         confp = fopen (config_default_dir, "r");
+         if (confp == NULL)
+           {
+             fprintf (stderr, "can't open configuration file [%s]\n",
+                      config_default_dir);
+             exit (1);
+           }      
+         else
+           fullpath = config_default_dir;
+       }
+      else
+       {
+         /* Rleative path configuration file. */
+         cwd = getcwd (NULL, MAXPATHLEN);
+         fullpath = XMALLOC (MTYPE_TMP, 
+                             strlen (cwd) + strlen (config_current_dir) + 2);
+         sprintf (fullpath, "%s/%s", cwd, config_current_dir);
+       }  
+    }  
+  vtysh_read_file (confp);
+
+  fclose (confp);
+
+  host_config_set (fullpath);
+}
+
+void
+vtysh_config_write (FILE *fp)
+{
+  extern struct host host;
+
+  if (host.name)
+    fprintf (fp, "hostname %s\n", host.name);
+  fprintf (fp, "!\n");
+}
+
+void
+vtysh_config_init ()
+{
+  config_top = list_new ();
+  config_top->del = (void (*) (void *))line_del;
+  configvec = vector_init (1);
+}
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
new file mode 100644 (file)
index 0000000..f30aba4
--- /dev/null
@@ -0,0 +1,288 @@
+/* Virtual terminal interface shell.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include <sys/un.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <pwd.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "command.h"
+
+#include "vtysh/vtysh.h"
+#include "vtysh/vtysh_user.h"
+\f
+/* VTY shell program name. */
+char *progname;
+
+/* Configuration file name.  Usually this is configurable, but vtysh
+   has static configuration file only.  */
+char *config_file = NULL;
+
+/* Configuration file and directory. */
+char *config_current = NULL;
+char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG;
+
+/* Integrated configuration file. */
+char *integrate_file = NULL;
+char *integrate_current = NULL;
+#if 0
+char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
+#endif
+
+/* Flag for indicate executing child command. */
+int execute_flag = 0;
+
+/* For sigsetjmp() & siglongjmp(). */
+static sigjmp_buf jmpbuf;
+
+/* Flag for avoid recursive siglongjmp() call. */
+static int jmpflag = 0;
+
+/* A static variable for holding the line. */
+static char *line_read;
+
+/* Master of threads. */
+struct thread_master *master;
+\f
+/* SIGTSTP handler.  This function care user's ^Z input. */
+void
+sigtstp (int sig)
+{
+  /* Execute "end" command. */
+  vtysh_execute ("end");
+  
+  /* Initialize readline. */
+  rl_initialize ();
+  printf ("\n");
+
+  /* Check jmpflag for duplicate siglongjmp(). */
+  if (! jmpflag)
+    return;
+
+  jmpflag = 0;
+
+  /* Back to main command loop. */
+  siglongjmp (jmpbuf, 1);
+}
+
+/* SIGINT handler.  This function care user's ^Z input.  */
+void
+sigint (int sig)
+{
+  /* Check this process is not child process. */
+  if (! execute_flag)
+    {
+      rl_initialize ();
+      printf ("\n");
+      rl_forced_update_display ();
+    }
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTSTP, sigtstp);
+  signal_set (SIGPIPE, SIG_IGN);
+}
+\f
+/* Help information display. */
+static void
+usage (int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages kernel routing table management and \
+redistribution between different routing protocols.\n\n\
+-b, --boot               Execute boot startup configuration\n\
+-e, --eval               Execute argument as command\n\
+-h, --help               Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+  exit (status);
+}
+
+/* VTY shell options, we use GNU getopt library. */
+struct option longopts[] = 
+{
+  { "boot",                no_argument,             NULL, 'b'},
+  { "eval",                 required_argument,       NULL, 'e'},
+  { "help",                 no_argument,             NULL, 'h'},
+  { 0 }
+};
+\f
+/* Read a string, and return a pointer to it.  Returns NULL on EOF. */
+char *
+vtysh_rl_gets ()
+{
+  /* If the buffer has already been allocated, return the memory
+     to the free pool. */
+  if (line_read)
+    {
+      free (line_read);
+      line_read = NULL;
+    }
+     
+  /* Get a line from the user.  Change prompt according to node.  XXX. */
+  line_read = readline (vtysh_prompt ());
+     
+  /* If the line has any text in it, save it on the history. */
+  if (line_read && *line_read)
+    add_history (line_read);
+     
+  return (line_read);
+}
+\f
+/* VTY shell main routine. */
+int
+main (int argc, char **argv, char **env)
+{
+  char *p;
+  int opt;
+  int eval_flag = 0;
+  int boot_flag = 0;
+  char *eval_line = NULL;
+  char *integrated_file = NULL;
+
+  /* Preserve name of myself. */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  /* Option handling. */
+  while (1) 
+    {
+      opt = getopt_long (argc, argv, "be:h", longopts, 0);
+    
+      if (opt == EOF)
+       break;
+
+      switch (opt) 
+       {
+       case 0:
+         break;
+       case 'b':
+         boot_flag = 1;
+         break;
+       case 'e':
+         eval_flag = 1;
+         eval_line = optarg;
+         break;
+       case 'h':
+         usage (0);
+         break;
+       case 'i':
+         integrated_file = strdup (optarg);
+       default:
+         usage (1);
+         break;
+       }
+    }
+
+  /* Initialize user input buffer. */
+  line_read = NULL;
+
+  /* Signal and others. */
+  signal_init ();
+
+  /* Make vty structure and register commands. */
+  vtysh_init_vty ();
+  vtysh_init_cmd ();
+  vtysh_user_init ();
+  vtysh_config_init ();
+
+  vty_init_vtysh ();
+
+  sort_node ();
+
+  vtysh_connect_all ();
+
+  /* Read vtysh configuration file. */
+  vtysh_read_config (config_file, config_current, config_default);
+
+  /* If eval mode */
+  if (eval_flag)
+    {
+      vtysh_execute_no_pager (eval_line);
+      exit (0);
+    }
+  
+  /* Boot startup configuration file. */
+  if (boot_flag)
+    {
+      vtysh_read_config (integrate_file, integrate_current, integrate_default);
+      exit (0);
+    }
+
+  vtysh_pager_init ();
+
+  vtysh_readline_init ();
+
+  vty_hello (vty);
+
+  vtysh_auth ();
+
+  /* Preparation for longjmp() in sigtstp(). */
+  sigsetjmp (jmpbuf, 1);
+  jmpflag = 1;
+
+  /* Main command loop. */
+  while (vtysh_rl_gets ())
+    vtysh_execute (line_read);
+
+  printf ("\n");
+
+  /* Rest in peace. */
+  exit (0);
+}
diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c
new file mode 100644 (file)
index 0000000..b84da2e
--- /dev/null
@@ -0,0 +1,191 @@
+/* User authentication for vtysh.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include <pwd.h>
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#endif /* USE_PAM */
+
+#include "memory.h"
+#include "linklist.h"
+#include "command.h"
+
+#ifdef USE_PAM
+static struct pam_conv conv = 
+{
+  misc_conv,
+  NULL
+};
+
+int
+vtysh_pam (char *user)
+{
+  int ret;
+  pam_handle_t *pamh = NULL;
+
+  /* Start PAM. */
+  ret = pam_start("zebra", user, &conv, &pamh);
+  /* printf ("ret %d\n", ret); */
+
+  /* Is user really user? */
+  if (ret == PAM_SUCCESS)
+    ret = pam_authenticate (pamh, 0);
+  /* printf ("ret %d\n", ret); */
+  
+#if 0
+  /* Permitted access? */
+  if (ret == PAM_SUCCESS)
+    ret = pam_acct_mgmt (pamh, 0);
+  printf ("ret %d\n", ret);
+
+  if (ret == PAM_AUTHINFO_UNAVAIL)
+    ret = PAM_SUCCESS;
+#endif /* 0 */
+  
+  /* This is where we have been authorized or not. */
+#ifdef DEBUG
+  if (ret == PAM_SUCCESS)
+    printf("Authenticated\n");
+  else
+    printf("Not Authenticated\n");
+#endif /* DEBUG */
+
+  /* close Linux-PAM */
+  if (pam_end (pamh, ret) != PAM_SUCCESS) 
+    {
+      pamh = NULL;
+      fprintf(stderr, "vtysh_pam: failed to release authenticator\n");
+      exit(1);
+    }
+
+  return ret == PAM_SUCCESS ? 0 : 1;
+}
+#endif /* USE_PAM */
+
+struct user
+{
+  char *name;
+  u_char nopassword;
+};
+
+struct list *userlist;
+
+struct user *
+user_new ()
+{
+  struct user *user;
+  user = XMALLOC (0, sizeof (struct user));
+  memset (user, 0, sizeof (struct user));
+  return user;
+}
+
+void
+user_free (struct user *user)
+{
+  XFREE (0, user);
+}
+
+struct user *
+user_lookup (char *name)
+{
+  struct listnode *nn;
+  struct user *user;
+
+  LIST_LOOP (userlist, user, nn)
+    {
+      if (strcmp (user->name, name) == 0)
+       return user;
+    }
+  return NULL;
+}
+
+void
+user_config_write ()
+{
+  struct listnode *nn;
+  struct user *user;
+
+  LIST_LOOP (userlist, user, nn)
+    {
+      if (user->nopassword)
+       printf (" username %s nopassword\n", user->name);
+    }
+}
+
+struct user *
+user_get (char *name)
+{
+  struct user *user;
+  user = user_lookup (name);
+  if (user)
+    return user;
+
+  user = user_new ();
+  user->name = strdup (name);
+  listnode_add (userlist, user);
+
+  return user;
+}
+
+DEFUN (username_nopassword,
+       username_nopassword_cmd,
+       "username WORD nopassword",
+       "\n"
+       "\n"
+       "\n")
+{
+  struct user *user;
+  user = user_get (argv[0]);
+  user->nopassword = 1;
+  return CMD_SUCCESS;
+}
+
+int
+vtysh_auth ()
+{
+  struct user *user;
+  struct passwd *passwd;
+
+  passwd = getpwuid (geteuid ());
+
+  user = user_lookup (passwd->pw_name);
+  if (user && user->nopassword)
+    /* Pass through */;
+  else
+    {
+#ifdef USE_PAM
+      if (vtysh_pam (passwd->pw_name))
+       exit (0);
+#endif /* USE_PAM */
+    }
+  return 0;
+}
+
+void
+vtysh_user_init ()
+{
+  userlist = list_new ();
+  install_element (CONFIG_NODE, &username_nopassword_cmd);
+}
diff --git a/vtysh/vtysh_user.h b/vtysh/vtysh_user.h
new file mode 100644 (file)
index 0000000..8d0a4cf
--- /dev/null
@@ -0,0 +1,27 @@
+/* User authentication for vtysh.
+ * Copyright (C) 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _VTYSH_USER_H
+#define _VTYSH_USER_H
+
+int vtysh_auth ();
+
+#endif /* _VTYSH_USER_H */
diff --git a/zebra/.cvsignore b/zebra/.cvsignore
new file mode 100644 (file)
index 0000000..95401bf
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile
+*.o
+zebra
+zebra.conf
+client
+tags
+TAGS
+.deps
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
new file mode 100644 (file)
index 0000000..b5383f1
--- /dev/null
@@ -0,0 +1,1221 @@
+2002-09-28  Akihiro Mizutani <mizutani@net-chef.net>
+
+       * zebra_rib.c (static_add_ipv4): Null0 static route is added.
+
+2002-09-10  Jochen Friedrich <chris+zebra@scram.de>
+
+       * rt_netlink.c: Add check for EAGAIN.
+       * kernel_socket.c: Likewise
+
+2002-06-12  Israel Keys <ikeys@oz.agile.tv>
+
+       * rt_netlink.c: Setting the NLM_F_ACK flag on the netlink command
+         message so that we get an ACK for successful netlink commands.
+         Change the netlink socket to BLOCKING while we wait for a
+         response; be it an ACK or an NLMSG_ERROR.  Change
+         netlink_parse_info to deal with ACK messages.
+
+2001-11-01  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+       * rtadv.c (rtadv_make_socket): setsockopt(IPV6_CHECKSUM) does not
+       work for ICMPv6 socket.
+
+2001-10-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * rib.c (rib_process): Select connected route any case.
+
+2001-10-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * interface.c (no_ip_address_secondary): Add "no" to command.
+
+2001-10-18  NOGUCHI Kay  <kay@v6.access.co.jp>
+
+       * ioctl.c (if_prefix_add_ipv6): Set the prefered and valid lifetime
+       to infinity as the freebsd4.4 workaroud.
+
+2001-08-26  mihail.balikov@interbgc.com
+
+       * zebra_snmp.c: Fix snmpwalk problem such as IPv4 address
+       A.B.C.255.
+
+2001-08-22  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * rtadv.c: Do not send RA to loopback interface.
+
+2001-08-20  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * ioctl.c (if_set_prefix): Remove Linux 2.0 specific connected
+       route treatment.
+
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92a released.
+
+2001-08-17  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * rib.c: Kernel route is treated as EGP routes in nexthop active
+       check.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+       * zebra-0.92 released.
+
+2001-08-08  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * rib.c (show_ip_route_prefix_longer): Add longer-prefix option to
+       show route commands.
+
+2001-07-29  Yon Uriarte <havanna_moon@gmx.net>
+
+       * zserv.c (zsend_ipv4_add_multipath): Add
+       NEXTHOP_TYPE_IPV4_IFINDEX check.
+
+2001-07-29  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * rtadv.c: Apply valid lifetime, preferred lifetime, onilnk flag,
+       autonomous address-configuration flag patch.
+       (no_ipv6_nd_suppress_ra): Change "ipv6 nd send-ra" to "no ipv6 nd
+       suppress-ra".
+
+2001-07-24  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * rtadv.c (ipv6_nd_ra_interval): Add "ipv6 nd ra-interval SECONDS"
+       command.
+
+2001-07-24  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+       * rt_socket.c (kernel_rtm_ipv4): Add KAME/NetBSD151 equal cost
+       multicast FIB support both IPv4 and IPv6.
+
+2001-07-24  Hal Snyder <hal@vailsys.com>
+
+       * if_ioctl.c (interface_list_ioctl): Fix bug of failing to get the
+       full list of interfaces on some configurations of OpenBSD.
+
+2001-07-23  NOGUCHI Kay <kay@v6.access.co.jp>
+
+       * rtadv.c (ipv6_nd_send_ra): Apply [zebra 9320] to fix "ipv6 nd
+       send-ra" bug.
+       (ipv6_nd_ra_lifetime): "ipv6 nd ra-lifetime 0" for default router
+       availability.
+       (ipv6_nd_managed_config_flag): "ipv6 nd managed-config-flag" is
+       added.
+       (ipv6_nd_other_config_flag): "ipv6 nd other-config-flag" is added.
+       
+2001-07-23  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+       * ioctl.c (if_ioctl): Change ioctl argument from int to u_long.
+
+       * rt_ioctl.c: Likewise.
+
+2001-07-23  Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+       * kernel_socket.c (rtm_write): Only set RTF_CLONING when the
+       interface is not p2p.
+
+2001-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ioctl.c (if_prefix_add_ipv6): Fix argument type.
+
+2001-04-06  Toshiaki Takada  <takada@zebra.org>
+
+       * zserv.c (zsend_interface_delete): Use client->obuf instead of
+       allocating new stream.
+
+2001-03-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c: Revert RTPROT_BOOT change.
+
+2001-03-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_route_change): Skip RTPROT_BOOT route.
+       (netlink_routing_table): Likewise.
+
+2001-03-07  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * zserv.c (zsend_ipv4_add_multipath): Send metric value to
+       protocol daemons.
+
+2001-02-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_routing_table): Do not return
+       tb[RTA_GATEWAY] is NULL.  Reported by: "Michael O'Keefe"
+       <mokeefe@qualcomm.com>.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (interface_list_ioctl): Call if_add_update().
+       Suggested by: Chris Dunlop <chris@onthe.net.au>.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (nexthop_active_ipv4): When nexthop type is
+       NEXTHOP_TYPE_IPV4_IFINDEX, propery set the ifindex to rifindex.
+
+       * zserv.c: Initialize rtm_table_default with 0.
+
+       * zebra-0.91 is released.
+
+2001-01-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * kernel_socket.c (rtm_read): Filter cloned route.  Suggested by:
+       Jun-ichiro itojun Hagino <itojun@iijlab.net>
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * connected.c (connected_up_ipv6): When point-to-point destination
+       address is ::, use local address for connected network.
+       (connected_down_ipv6): Likewise.
+
+2001-01-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.c (zebra_serv): Add missing close() call.  Reported by:
+       David Waitzman <djw@vineyard.net>.
+
+2001-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_lookup_ipv4): New function for checking exact match
+       IGP route.
+
+2001-01-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (show_ipv6_route_protocol): Fix bug of "show ip route
+       route-type".
+
+2001-01-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.c (zebra_interface): Do not call
+       zebra_interface_add_update for inactive interface.
+
+       * zserv.c (zsend_interface_address_add): Send interface address
+       flag.
+       (zsend_interface_address_delete): Likewise.
+
+2001-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.c (if_addr_add):  Add flags.
+
+       * connected.c (ifa_add_ipv4): Add new function for interface
+       address handling.
+       (ifa_delete_ipv4): Likewise.
+
+2001-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_update): Update IPv6 RIB.
+
+       * kernel_socket.c (ifam_read): Call if_refresh() for update
+       interface flag status.  This is for implicit interface up on *BSD.
+
+       * interface.c (if_refresh): Add interface flag refresh function.
+
+       * kernel_socket.c (rtm_read): Fetch link-local address interface
+       index.
+       (ifan_read): We need to fetch interface information.  Suggested
+       by: Yasuhiro Ohara <yasu@sfc.wide.ad.jp>.
+
+       * rib.c (static_ipv6_nexthop_same): Add check for
+       NEXTHOP_TYPE_IPV6_IFNAME.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.h (NEW_RIB): Turn on NEW_RIB flag.  IPv6 new RIB code are
+       taken into place.
+
+2001-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (static_ipv6_write): Display STATIC_IPV6_GATEWAY_IFNAME
+       configuration.
+       (rib_delete_ipv6): Handle same route conter for IPv6 connected
+       route.
+       (show_ipv6_route_protocol): New command.
+       (show_ipv6_route_addr): Likewise.
+       (show_ipv6_route_prefix): Likewise.
+       (rib_update): Sweep kernel route when it is cleaned up.
+
+       * rt_socket.c (kernel_add_ipv6): Add NEXTHOP_IPV6_IFNAME
+       treatmenet.
+
+       * rt_netlink.c (kernel_init): Likewise.
+
+       * rt_ioctl.c (kernel_ioctl_ipv6_multipath): Likewise.
+
+       * rib.c (rib_add_ipv4): Cope with same connected route on a
+       interface.  Suggested by: Matthew Grant <grantma@anathoth.gen.nz>.
+       (nexthop_ipv6_ifname_add): Add NEXTHOP_IPV6_IFNAME treatmenet.
+
+       * rib.h (struct new_rib): Add refcnt to keep track on the
+       reference of same connected route.
+
+       * ioctl.c (if_set_prefix): Add check for GNU_LINUX.
+
+2001-01-13  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+       * kernel_socket.c (ifan_read, rtm_type_str): Add RTM_OIFINFO check.
+       (rtm_type_str): Add RTM_IFANNOUNCE check.
+       (ifan_read): New function.
+       (kernel_read): Add case for RTM_IFANNOUNCE.
+
+2001-01-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_ioctl.c (kernel_ioctl_ipv6_multipath): New function.
+
+       * rt_netlink.c (netlink_route_multipath): IPv6 address ifindex
+       treatment.
+
+       * connected.c (connected_up_ipv6): Add dest value check.
+
+       * rib.c (nexthop_active_ipv6): Do not touch IPv6 nexthop's
+       ifindex.
+       (rib_add_ipv4): Import rib_add_ipv6() same route check code.
+       (nexthop_active_check): NEXTHOP_TYPE_IPV6_IFINDEX activity is only
+       checked by ifindex.
+
+       * rt_socket.c (kernel_rtm_ipv6_multipath): New function.
+
+       * redistribute.c (redistribute_add): Use
+       zsend_ipv6_add_multipath().
+       (redistribute_delete_multipath): Use
+       zsend_ipv6_delete_multipath().
+
+       * interface.c (ip_address): Check current IP address to avoid
+       duplicate.
+
+       * rib.c (rib_delete_ipv4): When deleted route is connected route,
+       check ifindex.
+       (rib_add_ipv4): When connected route is added do not perform
+       implicit withdraw.
+       (rib_delete_ipv4): Check ifindex for connected route.
+
+       * kernel_socket.c (rtm_read): When route has RTF_STATIC, set
+       ZEBRA_FLAG_STATIC for indicate as persistent route.
+       (ifam_read): Unset interface index from link-local address when
+       IPv6 stack is KAME.
+
+       * rib.c (rib_update): Do not delete persistent kernel route.
+
+       * rib.h (struct new_rib): Integrate RIB_FLAG_* to ZEBRA_FLAG_*.
+
+       * rt_socket.c (kernel_add_ipv6_multipath): Add placeholder.
+       (kernel_delete_ipv6_multipath): Likewise.
+
+       * rt_netlink.c (netlink_talk): Give struct nlsock to netlink_talk.
+
+2001-01-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_update): Revert Matthew Grant's patch
+       zebra_cvs_newribfix.patch.  Use struct rib->ifindex for kernel
+       interface index.  Introduce NEXTHOP_TYPE_IPV4_IFINDEX to support
+       that.  Add support for address deletion situation.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.c: Remove HAVE_IF_PSEUDO part.
+
+       * rib.h: Likewise.
+
+       * rt_netlink.c (netlink_link_change): Likewise.
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.c: Remove OLD_RIB codes.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.90 is released.
+
+2001-01-09  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * interface.c (if_new_intern_ifindex): Allocate a new internal
+       interface index.
+       (if_addr_refresh): Fix up ip addresses configured via zebra.
+       (if_add_update): Handle an interface addition.
+       (if_delete_update): Handle an interface delete event.
+
+       * rib.c (nexthop_ipv4_add): Add kernel route deletion process when
+       interface goes down.
+
+2001-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.c (if_dump_vty): When HAVE_NET_RT_IFLIST is defined,
+       NetBSD also use this function.  Suggested by Jasper Wallace
+       <jasper@ivision.co.uk>.
+
+2001-01-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (nexthop_active_ipv4): Move back to set methodo to old
+       one.
+
+2001-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_add_ipv4): EBGP multihop set ZEBRA_FLAG_INTERNAL
+       flag, so treat it.
+
+2001-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_talk_ipv6): When IPv6 route message is
+       sent from netlink_cmd, the same message comes from netlink.  To
+       avoid confusion, temporary netlink_talk_ipv6 use netlink.sock
+       instead of netlink_cmd.sock.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.h (ZEBRA_SERV_PATH): Change "/tmp/zebra" to "/tmp/.zebra".
+       Change "/tmp/zserv" to "/tmp/.zserv".
+       
+2000-12-29  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+       * rt_netlink.c (struct nlsock): Divide kernel message into listen
+       socket and command socket.
+       (netlink_talk): Remove socket listen code.  Use netlink_parse_info
+       for read kernel response.
+
+2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (vty_show_ip_route): Show uptime of the RIP,OSPF,BGP
+       routes.
+
+2000-12-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_route_multipath): Metric value is
+       reflected to kernel routing table.
+
+       * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Likewise.
+
+       * kernel_socket.c (rtm_write): Likewise.
+
+       * rib.c (nexthop_active_ipv4): Only iBGP route perform recursive
+       nexthop lookup.
+
+       * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Add ioctl version of
+       new RIB implementation.
+
+2000-12-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.h: Remove MULTIPATH_NUM.  It is defined by configure script.
+
+2000-12-25  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+       * rib.c (rib_if_up): Call rib_fib_set instead of RIB_FIB_SET for
+       proper redistribution.
+
+2000-12-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (nexthop_active_ipv4): Add self lookup nexthop check.
+       (show_ip_route_protocol): Support new RIB.
+
+       * rt_netlink.c (netlink_route_change): Do not return when gate is
+       NULL.
+
+2000-12-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_lookup_ipv4_nexthop): IBGP nexthop check function is
+       updated.
+       (rib_add_ipv4): Free implicit withdraw route's RIB.
+
+2000-12-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (nexthop_active_ipv4): Check indirect nexthop.
+
+       * redistribute.c (redistribute_add_multipath): Redistribution
+       works with new rib code.
+
+2000-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_route_multipath): Check useful nexthop
+       number.
+       (netlink_route_multipath): Clear rtnh_flags and rtnh_hops.
+
+       * rib.c (nexthop_active_update): Set flag for the rib's nexthop
+       activity is changed.
+       (nexthop_active_check): Before checking interface is up, make it
+       sure the interface exist.
+
+2000-11-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (ip_route): New RIB prototype.
+
+2000-11-16  Yon Uriarte <ukl2@rz.uni-karlsruhe.de>
+
+       * zserv.c (zsend_interface_add): Send hardware address when
+       hw_addr_len is greater than 0.
+
+2000-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * connected.c (connected_up_ipv4): Fix ptop bug.  The destination
+       network should be installed into routing table.
+       (connected_down_ipv4): Likewise.
+       (connected_add_ipv4): Change to use connected_up_ipv4.
+       (connected_delete_ipv4): Likewise.
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_interface_addr): Revert Harald Welte
+       <laforge@gnumonks.org>'s ptop patch then back to original code to
+       avoid duplicated connected route problem.  Suggested by Frank van
+       Maarseveen <F.vanMaarseveen@inter.NL.net>.
+
+       * kernel_socket.c (rtm_read): Make behavior consistent even #ifdef
+       DEBUG is defined.  Reported by Jun-ichiro itojun Hagino
+       <itojun@iijlab.net>.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+       * main.c (main): Call zebra_snmp_init() when it is enabled.
+
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.c (zebra_serv_un): UNIX domain socket server of zebra
+       protocol.
+
+2000-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_add_ipv4): Same check bug is fixed.
+
+2000-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_if_down): Remove kernel route when the interface goes
+       down.
+
+       * debug.c: New command "debug zebra kernel" is added.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.89 is released.
+
+2000-09-24  Harald Welte <laforge@gnumonks.org>
+
+       * rt_netlink.c (netlink_interface_addr): Fix point-to-point address
+       treatment in netlink interface.
+
+2000-09-21  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+       * rib.c (rib_if_down): Pull static route only.  Protocol daemon
+       must withdraw routes when interface goes down.
+       (rib_add_ipv4): Check nexthop when replace route.
+
+2000-09-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (if_getaddrs): New function for looking up
+       interface's address by getifaddrs().
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * connected.c (connected_delete_ipv4): Add check for connected
+       address is found or not.
+       (connected_add_ipv6): Reflect IPv6 connected address change to
+       protocol daemons.
+       (connected_delete_ipv6): Likewise.
+
+2000-09-07  David Lipovkov <davidl@nbase.co.il>
+
+       * rib.c (rib_delete_ipv4): Reverted the change from pseudo
+       interface patch to original.  Because ospfd deletes routes using
+       zero ifindex.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra-0.88 is released.
+
+2000-08-15  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * rib.c (show_ip_route_protocol): Help string correction.
+       (show_ip_route_prefix): Check prefix mask.
+       (show_ip_route_vty_detail): Display distance and metric.
+
+2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.c (zsend_interface_add): Change ifindex store size from
+       two octet to four.
+       (zsend_interface_delete): Likewise.
+       (zsend_interface_address_add): Likewise.
+       (zsend_interface_address_delete): Likewise.
+       (zsend_interface_up): Likewise.
+       (zsend_interface_down): Likewise.
+
+2000-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_add_ipv4): Do not install distance 255 route.
+
+2000-08-10  Toshiaki Takada  <takada@zebra.org>
+
+       * interface.c (bandwidth_if), (no_bandwidth_if):  Call
+       zebra_interface_up_update () instead of using if_up() and if_down().
+
+2000-08-07  "Akihiro Mizutani" <mizutani@dml.com>
+
+       * interface.c (bandwidth_if): Fix help string.
+
+2000-08-07  Matthew Grant <grantma@anathoth.gen.nz>
+
+       * interface.c (if_dump_vty): Display bandwidth value.
+       (bandwidth_if): New command "bandwidth <1-10000000>" is added.
+       When interface is up, force protocol daemons to recalculate routes
+       due to cost change.
+       (no_bandwidth_if): Likewise.
+       (if_config_write): Output bandwidth configuration.
+
+       * zserv.c (zsend_interface_add): Send bandwidth value.
+       (zsend_interface_up): Likewise.
+       (zsend_interface_down): Likewise.
+
+
+2000-08-07  Michael Rozhavsky <mike@nbase.co.il>
+
+       * rib.c (show_ip_route_protocol): "show ip route
+       (bgp|connected|kernel|ospf|rip|static)" is added.
+
+2000-08-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_lookup_ipv4_nexthop): Check parent node until IGP
+       nexthop is found.
+       (rib_add_ipv4_internal): Set fib ifindex to rib ifindex.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * redistribute.c (redistribute_delete): Fix bug of default route
+       redistribute treatment.
+
+2000-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_init): Install ip_node in rib.c instead of zserv.c.
+       Change default distance value.
+
+                    Old         New
+       ------------------------------------------
+       system      10           0
+       kernel      20           0
+       connected   30           0
+       static      40           1
+       rip         50         120
+       ripng       50         120
+       ospf        60         110
+       ospf6       49         110
+       bgp         70         200(iBGP)  20(eBGP)
+       ------------------------------------------
+
+       * zserv.c (client_lookup): Function removed.
+       (zsend_interface_add): Use client's output buffer.  Check ifinfo
+       flag.
+       (zsend_interface_delete): Likewise.
+       Delete ipv4_static_radix and ipv6_static_radix.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.h (struct zebra_client): When client request interface
+       information, ifinfo is set.
+
+       * rib.c: Temporary Revert changes for pseudo interface.
+
+       * rib.h: Likewise.
+
+       * zserv.c: Likewise.
+
+       * interface.c: Likewise.
+       
+2000-08-02  David Lipovkov <davidl@nbase.co.il>
+
+       * interface.c (zebra_if_init): Install interface "pseudo"
+       commands.
+
+       * rib.c (rib_create): ifname argument is added.
+       (rib_add_ipv4_pseudo): New function is added.
+       (rib_delete_ipv4_pseudo): Likewise.
+
+       * rib.h : Delete INTERFACE_UNKNOWN definition.  Add prototype for
+       pseudo interface functions.
+
+       * rt_netlink.c (netlink_link_change): Check for pseudo interface.
+
+       * zserv.c (ip_route): When destination is pseudo interface, call
+       rib_add_ipv4_pseudo().
+
+       * zserv.c (no_ip_route): Trim "unknown" argument.
+
+2000-07-26  kunitake@dti.ad.jp
+
+       * if_ioctl.c (if_get_hwaddr): Fix hardware address length from 8
+       to 6.
+
+       * rtadv.c (rtadv_send_packet): Fix shift bug for hardware address.
+
+2000-07-24  Akihiro Mizutani <mizutani@dml.com>
+
+       * interface.c: Use install_default() for common VTY commands.
+
+2000-07-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (interface_list_ioctl): A interface list size is
+       calculated from ifreq->if_addr.sa_len.  This is for OpenBSD.
+
+       * ioctl.c (if_get_mtu): Remove codes for SIOCGIFDATA.
+
+2000-07-09  Chris Dunlop <chris@onthe.net.au>
+
+       * if_ioctl.c (if_get_index): Add check for HAVE_BROKEN_ALIASES.
+
+2000-07-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.c (zebra_client_read): Add ZEBRA_REDISTRIBUTE_{ADD,DELETE}
+       message handling.
+
+2000-07-02  David Lipovkov <davidl@nbase.co.il>
+
+       * zserv.c: "ip route A.B.C.D/M unknown" command is added.
+
+2000-06-28  Michael Rozhavsky <mike@nbase.co.il>
+
+       * rib.c: Remove old kernel route when new route comes in.
+
+2000-06-13  David Lipovkov <davidl@nbase.co.il>
+
+       * rib.c (rib_if_up): Add check for unknown interface.
+
+2000-06-13 Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.h: Define INTERFACE_UNKNOWN.
+
+2000-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (EXTRA_DIST): Move irdp.c until implementation is
+       finished.
+
+2000-06-05  David Lipovkov <davidl@nbase.co.il>
+
+       * interface.c (if_zebra_delete_hook): Call rib_if_delete().
+
+       * redistribute.c (zebra_interface_delete_update): New function.
+
+       * redistribute.h (zebra_interface_delete_update): New function
+       prototype.
+
+       * rib.c (rib_if_delete): New function.  Walk down all routes and
+       delete all on the interface.
+
+       * rib.h: New function prototype.
+
+       * rt_netlink.c (netlink_link_change): Call
+       zebra_interface_delete_update ().
+
+2000-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (interface_info_ioctl): Check interface's flag before
+       checking interface's address.
+
+2000-04-26  Jochen Friedrich <jochen@nwe.de>
+
+       * GNOME-PRODUCT-ZEBRA-MIB: New file.
+
+       * GNOME-SMI: New file.
+
+2000-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * irdp.c: New file from 1997 development code.
+       * irdp.h: Likewise.
+
+2000-04-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rtadv.c (rtadv_send_packet): Enclose router advertisement
+       logging with IS_ZEBRA_DEBUG_PACKET.
+
+2000-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zserv.c (zebra_client_close): Remove client structure from
+       client_list when connection is terminated.
+
+2000-03-21  David Lipovkov <davidl@nbase.co.il>
+
+       * connected.c (connected_add_ipv4): Allows all necessary structure
+       updates for connected route, but doesn't insert it into rib if
+       it's interface is down.
+
+2000-01-21  Hideto Yamakawa <hideto.yamakawa@soliton.co.jp>
+
+       * rtread_getmsg.c: Set some definition for Solaris 2.5 and Solaris
+       2.5.1.
+
+2000-01-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (no_ipv6_route_ifname): Fix buf of cheking return value
+       from str2prefix_ipv6().
+
+2000-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_socket.c: Revert to use RTF_HOST for IPv4 with /32 route and
+       IPv6 with /128 routes.
+       (kernel_rtm_ipv4): In case of /32 route's gateway is interface. It
+       should have mask for cloning.
+
+1999-12-26  Jochen.Friedrich@genorz.de
+
+       * interface.c (if_dump_vty): Fix a bug of missing VTY_NEWLINE.
+
+1999-12-23  Alex Zinin <zinin@amt.ru>
+       * interface.*: dynamic int up/down support
+
+1999-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ipforward_proc.c (dropline): Move dropline() from lib/dropline.c
+
+       * rtread_proc.c (proc_route_read): Don't use dropline().
+
+1999-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * kernel_socket.c (rtm_read): When message is RTM_GET, it has own
+       process's pid.
+
+1999-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * main.c (main): Change to default log output to ZLOG_STDOUT.
+
+       * zserv.c (zebra_serv): More detailed error print.
+
+1999-11-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * kernel_socket.c (rtm_read): Check old pid for static route
+       insertion check.
+
+1999-11-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.c (if_dump_vty): BSDI/OS uses 64bit for interface
+       statistics counter.
+
+       * mtu_kvm.c: New file added.
+
+1999-11-27  Vladimir B. Grebenschikov <vova@express.ru>
+
+       * kernel_socket.c (rtm_write): Set RTF_CLONING flag for
+       route to the directly connected interface.
+
+1999-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_socket.c: Delete USE_HOST_BIT definition.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+       * rtread_getmsg.c: Undef some definition to resolve conflict.
+
+1999-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * kernel_socket.c (rtm_write): Change to use pre stored struct_dl
+       value for gateway specification.
+
+1999-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_socket.c (kernel_rtm_ipv4): Even mask is 32 under IPv4 or
+       128 under IPv6, don't use RTF_HOST.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (EXTRA_DIST): Add rtread_getmsg.c.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+       * rtread_getmsg.c: Added for Solaris 2.6 support.
+
+1999-11-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rtread_sysctl.c (rtm_read_route): RTM_DELETE handling added.
+
+       * rt_socket.c (kernel_read): Better BSD routing socket support.
+
+1999-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * client_main.c: Disable making obsolete zebra test `client'
+       command.
+
+1999-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.c: Renamed to zserv.c.
+
+       * zebra.h: Global definitions are moved to lib/zebra.h.  Then
+       renamed to zserv.h.
+
+1999-10-15  Jordan Mendelson <jordy@wserv.com>
+
+       * if_ioctl.c: Add Linux 2.2.X's alias support and dynamic
+       interface.  Remove ugly MAX_INTERFACE handling codes.
+
+1999-09-17  Satosi KOBAYASI <kobayasi@north.ad.jp>
+
+       * Fix serious bug of IPv6 route deletion.
+
+1999-09-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ioctl.c (if_set_prefix): Properly set broadcast address.
+
+1999-09-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * rib.c (rib_add_ipv6, rib_delete_ipv6): now protocol daemons
+       can install connected route to kernel via zebra
+
+1999-08-24  VOP <vop@unity.net>
+
+       * rib.c: Include "sockunion.h"
+
+1999-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ipforward.h: New file.
+
+       * zebra.h: Obsolete message ZEBRA_GET_ALL_INTERFACE,
+       ZEBRA_GET_ONE_INTERFACE, ZEBRA_GET_HOSTINFO are deleted.
+
+1999-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_INTERFACE_ADDRESS_ADD):
+       ZEBRA_INTERFACE_{ADD,DELETE} added.
+
+1999-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c: show ip route A.B.C.D works.
+
+       * zebra.c (zebra_read_ipv4): Add ifindex to zebra messages.
+
+1999-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h: New Zebra message ZEBRA_INTERFACE_{ADD,DELETE} added.
+
+1999-08-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.h: New file.
+       * Makefile.am: Add interface.h
+
+1999-08-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * redistribute.c (zebra_redistribute): give ifindex to client.
+
+1999-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * main.c (longopts): -k, --keep_kernel option added.
+
+1999-07-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * rt_socket.c (rtm_write): forgot closing socket bug fixed.
+
+1999-07-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * rib.c (show_ipv6_cmd): if rib is link show interface name.
+
+1999-07-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * rt_socket.c (rtm_write): use sockaddr_dl when null gateway.
+
+1999-07-16  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * rt_socket.c (rtm_write): ipv6 route table bug fixed.
+
+1999-07-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * zebra.c (zebra_read_ipv6): read link prefix from ospf6 support
+
+1999-07-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+       * rt_socket.c (kernel_rtm_ipv6): gate treatment bug fixed.
+
+1999-07-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_sysctl.c (ifm_read): Clear sockunion argument before fetching
+       data.  Suggested by "Chris P. Ross" <cross@eng.us.uu.net>
+
+1999-07-08  HEO SeonMeyong <seirios@Matrix.IRI.Co.Jp>
+
+       * interface.c (if_tun_add): Add KAME's gif tunnel setting codes.
+
+1999-06-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.c (zebra_serv): Only accept loopback address connection.
+
+1999-06-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_ROUTE_EXTERNAL): Add zebra messages flags
+
+1999-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ipforward_proc.c: ipforward_on () and ipforward_off () added.
+
+1999-06-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ipforward_proc.c (ipforward_ipv6): Check for IPv6 forwarding
+       using /proc file system is added.
+
+1999-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (if_get_index): Interface index set bug is fixed by
+       adding #else at the middle of function.  Suggested by David Luyer
+       <luyer@ucs.uwa.edu.au>.
+
+1999-05-29    <kunihiro@zebra.org>
+
+       * rt_ioctl.c: Comment out #include <linux/ipv6_route.h>.
+
+1999-05-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_ROUTE_MAX): Add new define for the max value of
+       the sort of routes.
+
+1999-05-25  Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+       * rt_netlink.c (netlink_socket): Make netlink socket non-blocking.
+       (netlink_parse_info): If errno is EWOULDBLOCK then continue to
+       parse the message.
+       (netlink_talk): Likewise
+       
+1999-05-17    <kunihiro@zebra.org>
+
+       * redistribute.c (zebra_check_addr): Added for loopback address
+       check.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (netlink_route_change): Tempolary bypass ipv6 route
+       change treatment.
+
+       * Makefile.am (noinst_HEADERS): redistribute.h added.
+
+       * redistribute.h: New file.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+       * zebra.c (show_table): Show all table configuration DEFUN.
+       (config_table): Config table number DEFUN.
+
+       * rt_netlink.c: Add support for multiple routing table.
+
+       * rib.c (rib_weed_table): New function added for delete all
+       routes from specified routing table.
+
+       * main.c (signal_init): SIGTERM call sigint.
+       (sigint): Loggging more better message.
+
+1999-05-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c: Change log () to zlog ().
+
+1999-05-07    <kunihiro@zebra.org>
+
+       * zebra.h (ZEBRA_ROUTE_OSPF6): Added for ospf6d route.
+
+1999-04-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * interface.c: Add `no ip address' command.
+
+1999-04-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c (kernel_read): Function added for asynchronous
+       zebra between kernel communication.
+
+1999-03-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rtread_sysctl.c (rtm_read): Fix address memcopy overrun bug.
+       Reported by Achim Patzner <ap@bnc.net>.
+
+1999-03-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: Install configuration sample with 600 permission.
+
+1999-03-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am: Add -I.. to INCLUDES.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+       * syslog support added
+
+1999-02-17 Peter Galbavy <Peter.Galbavy@knowledge.com>
+
+       * if_sysctl.c (interface_list): allocated memory free when unknown
+       ifm_type is returned.
+
+       * ioctl.c (if_get_mtu): added SIOCGIFDATA treatment.
+       
+1998-12-15  Magnus Ahltorp <map@stacken.kth.se>
+
+       * interface.c: Header include added.
+
+1998-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt.h (kernel_delete_ipv6): change int index to unsigned int index.
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (interface_list_ioctl): interface flag must be
+       checked before check addresses of the interface.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6.
+
+1998-10-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ioctl.c: Linux version before 2.1.0 need interface route setup.
+
+1998-09-15  HEO SeonMeyong  <seirios@matrix.iri.co.jp>
+
+       * change HYDRANGEA to KAME
+
+1998-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (if_addr_ioctl): set address family for getting
+       interface's address.
+       (if_get_index): silently return when can't get interface's index.
+
+1998-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * main.c (main): batch mode option '-b' added.
+
+1998-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ioctl.c (if_set_prefix): add `ip address IPV4ADDR' command.
+       * interface.c (shutdown_if): add interface shutdown and no
+       shutdown command.
+
+1998-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rib.c (rib_add_ipv6): delete rib_add_in6.
+
+1998-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * main.c: retain flag is added.
+
+1998-07-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rtable.[ch]: merged with rib.[ch]
+
+1998-07-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * connected.h: renamed from ifa.h.
+
+1998-06-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rename if.c to interface.c
+       * rename ifa.c to connected.c
+
+       * Porting to Debian GNU/Linux 2.0 (hamm).
+
+1998-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c: renamed from krt_netlink.c
+       
+       * fib.c: deleted.
+       * rt_kvm.c: deleted.
+       * rtread_getmsg.c: deleted.
+
+1998-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c (multicast): add multicast flag [un]set fucntion.
+
+1998-05-19  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * rt_socket.c: Modify for compile on Solaris, but dont't work it.
+         rt_socket.c have some undefined function, so add directive "IMPLEMENT"
+
+1998-05-18  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+       * zebra.c: Modify for compile on Solaris.
+
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * main.c: change CONFDIR to SYSCONFDIR.
+
+1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * .cvsignore: added.
+
+1998-04-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * client.c: moves to ../lib.
+
+1998-03-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if_ioctl.c (if_get_addr): Change address copy from memcopy() to
+       structure assignment.
+
+1998-03-30  URA Hiroshi <ura@yamato.ibm.co.jp>
+
+       * if_sysctl.c (ifm_interface_add): sdl->sdl_data copy bug fixed.
+
+1998-02-23  "Hannes R. Boehm" <hannes@boehm.org>
+
+       * if.c (if_init): add config_exit_cmd and config_help_cmd.
+
+1998-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_ioctl.c (route_ioctl): EPERM treatment added.
+
+1998-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_socket.c (kernel_read): communication port zebra between
+       kernel is now handled by kernel_read.
+
+1998-01-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * main.c (main): zebra [-P port] can specify vty port number.
+
+1997-12-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.c: change select will be block.
+
+1997-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * add static route treatment.
+
+1997-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_netlink.c: add netlink support over GNU/Linux system.
+
+1997-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * all inet_addr is changed to inet_aton.
+
+       * zebra.c (ip_route): add ip route command for static routes.
+
+1997-11-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c (if_flag_dump): Linux port of if_flag_dump and _vty.
+
+1997-11-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c: add interface command.
+
+1997-11-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * ipforward_proc.c : Now works on Linux.
+
+1997-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * command.c : add completion feature.
+
+1997-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vty.c (vty_command): add vty interface.
+
+1997-10-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * zebra.c: add verbose mode.
+
+1997-10-12 SonMyong Ho <s-ho@Matrix.IRI.Co.Jp>
+
+       * Hydrangea for FreeBSD supported
+       * in.h: add some prototype.
+
+1997-10-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_socket.c and rtread.c completely rewritten.
+
+1997-10-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * rt_socket.c: rename kernel_sock to routing_socket
+
+1997-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * if.c (if_new): interface structure change from linklist to vector.
+
+1997-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * vector.c (vector_init): create vector related function
+
+1997-09-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+       * Makefile.in: add tags target
+
+       * start IPv6 support for INRIA FreeBSD.
+
diff --git a/zebra/GNOME-PRODUCT-ZEBRA-MIB b/zebra/GNOME-PRODUCT-ZEBRA-MIB
new file mode 100644 (file)
index 0000000..96bcec5
--- /dev/null
@@ -0,0 +1,78 @@
+GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN\r
+\r
+IMPORTS\r
+       MODULE-IDENTITY,\r
+       OBJECT-IDENTITY\r
+               FROM SNMPv2-SMI\r
+       gnomeProducts\r
+               FROM GNOME-SMI;\r
+\r
+zebra MODULE-IDENTITY\r
+       LAST-UPDATED "200004250000Z"\r
+       ORGANIZATION "GNOME project"\r
+       CONTACT-INFO\r
+               "GNU Network Object Model Environment project\r
+               \r
+               see http://www.gnome.org for contact persons of a particular\r
+               area or subproject of GNOME.\r
+\r
+               Administrative contact for MIB module:\r
+\r
+               Jochen Friedrich\r
+               Wingertstr. 70/1\r
+               68809 Neulussheim\r
+               Germany \r
+\r
+               email: snmp@gnome.org"\r
+       DESCRIPTION\r
+               "The product registrations for the various zebra subdeamons.\r
+               These registrations are guaranteed to be unique and are used\r
+               for SMUX registration by default (if not overridden manually)."\r
+       ::= { gnomeProducts 2 }\r
+\r
+zserv OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "zserv is part of the zebra project which again is a GNU\r
+               endorsed internet routing program.\r
+               zserv is the main zebra process which implements routing\r
+               entries with the kernel and handles routing updates between\r
+               other routing protocols."\r
+       ::= { zebra 1 }\r
+\r
+bgpd OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "bgpd is part of the zebra project which again is a GNU\r
+               endorsed internet routing program."\r
+       ::= { zebra 2 }\r
+\r
+ripd OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "ripd is part of the zebra project which again is a GNU\r
+               endorsed internet routing program."\r
+       ::= { zebra 3 }\r
+\r
+ripngd OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "ripngd is part of the zebra project which again is a GNU\r
+               endorsed internet routing program."\r
+       ::= { zebra 4 }\r
+\r
+ospfd OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "ospfd is part of the zebra project which again is a GNU\r
+               endorsed internet routing program."\r
+       ::= { zebra 5 }\r
+\r
+ospf6d OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "ospf6d is part of the zebra project which again is a GNU\r
+               endorsed internet routing program."\r
+       ::= { zebra 6 }\r
+\r
+END\r
diff --git a/zebra/GNOME-SMI b/zebra/GNOME-SMI
new file mode 100644 (file)
index 0000000..164732b
--- /dev/null
@@ -0,0 +1,53 @@
+GNOME-SMI DEFINITIONS ::= BEGIN\r
+\r
+IMPORTS\r
+       MODULE-IDENTITY,\r
+       OBJECT-IDENTITY,\r
+       enterprises\r
+               FROM SNMPv2-SMI;\r
+\r
+gnome MODULE-IDENTITY\r
+       LAST-UPDATED "9809010000Z"\r
+       ORGANIZATION "GNOME project"\r
+       CONTACT-INFO\r
+               "GNU Network Object Model Environment project\r
+               \r
+               see http://www.gnome.org for contact persons of a particular\r
+               area or subproject of GNOME.\r
+\r
+               Administrative contact for MIB module:\r
+\r
+               Jochen Friedrich\r
+               Wingertstr. 70/1\r
+               68809 Neulussheim\r
+               Germany \r
+\r
+               email: snmp@gnome.org"\r
+       DESCRIPTION\r
+               "The Structure of GNOME."\r
+       ::= { enterprises 3317 }        -- assigned by IANA\r
+\r
+gnomeProducts OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "gnomeProducts is the root OBJECT IDENTIFIER from\r
+               which sysObjectID values are assigned."\r
+       ::= { gnome 1 }\r
+\r
+gnomeMgmt OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "gnomeMgmt defines the subtree for production GNOME related\r
+               MIB registrations."\r
+       ::= { gnome 2 }\r
+\r
+gnomeTest OBJECT-IDENTITY\r
+       STATUS  current\r
+       DESCRIPTION\r
+               "gnomeTest defines the subtree for testing GNOME related\r
+               MIB registrations."\r
+       ::= { gnome 3 }\r
+\r
+-- more to come if necessary.\r
+\r
+END\r
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
new file mode 100644 (file)
index 0000000..6214767
--- /dev/null
@@ -0,0 +1,57 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@
+INSTALL_SDATA=@INSTALL@ -m 600
+
+LIB_IPV6 = @LIB_IPV6@
+
+ipforward = @IPFORWARD@
+if_method = @IF_METHOD@
+if_proc = @IF_PROC@
+rt_method = @RT_METHOD@
+rtread_method = @RTREAD_METHOD@
+kernel_method = @KERNEL_METHOD@
+other_method = @OTHER_METHOD@
+
+otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \
+       $(rtread_method) $(kernel_method) $(other_method)
+
+sbin_PROGRAMS = zebra
+
+zebra_SOURCES = \
+       zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \
+       redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c
+
+noinst_HEADERS = \
+       connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
+       interface.h ipforward.h irdp.h
+
+zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6)
+
+zebra_DEPENDENCIES = $(otherobj)
+
+sysconf_DATA = zebra.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \
+       ipforward_aix.c ipforward_ews.c ipforward_proc.c \
+       ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \
+       rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \
+       rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \
+       GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB irdp.c
+
+#client : client_main.o ../lib/libzebra.a
+#      $(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6)
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
diff --git a/zebra/Makefile.in b/zebra/Makefile.in
new file mode 100644 (file)
index 0000000..ad35b38
--- /dev/null
@@ -0,0 +1,493 @@
+# Makefile.in generated by automake 1.7 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@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+ipforward = @IPFORWARD@
+if_method = @IF_METHOD@
+if_proc = @IF_PROC@
+rt_method = @RT_METHOD@
+rtread_method = @RTREAD_METHOD@
+kernel_method = @KERNEL_METHOD@
+other_method = @OTHER_METHOD@
+
+otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \
+       $(rtread_method) $(kernel_method) $(other_method)
+
+
+sbin_PROGRAMS = zebra
+
+zebra_SOURCES = \
+       zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \
+       redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c
+
+
+noinst_HEADERS = \
+       connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
+       interface.h ipforward.h irdp.h
+
+
+zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6)
+
+zebra_DEPENDENCIES = $(otherobj)
+
+sysconf_DATA = zebra.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \
+       ipforward_aix.c ipforward_ews.c ipforward_proc.c \
+       ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \
+       rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \
+       rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \
+       GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB irdp.c
+
+subdir = zebra
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+sbin_PROGRAMS = zebra$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am_zebra_OBJECTS = zserv.$(OBJEXT) main.$(OBJEXT) interface.$(OBJEXT) \
+       connected.$(OBJEXT) ioctl.$(OBJEXT) zebra_rib.$(OBJEXT) \
+       redistribute.$(OBJEXT) debug.$(OBJEXT) rtadv.$(OBJEXT) \
+       zebra_snmp.$(OBJEXT) zebra_vty.$(OBJEXT)
+zebra_OBJECTS = $(am_zebra_OBJECTS)
+zebra_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/connected.Po ./$(DEPDIR)/debug.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/interface.Po ./$(DEPDIR)/ioctl.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/main.Po ./$(DEPDIR)/redistribute.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/rtadv.Po ./$(DEPDIR)/zebra_rib.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/zebra_snmp.Po ./$(DEPDIR)/zebra_vty.Po \
+@AMDEP_TRUE@   ./$(DEPDIR)/zserv.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(zebra_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(zebra_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  zebra/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sbindir)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+         rm -f $(DESTDIR)$(sbindir)/$$f; \
+       done
+
+clean-sbinPROGRAMS:
+       -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+zebra$(EXEEXT): $(zebra_OBJECTS) $(zebra_DEPENDENCIES) 
+       @rm -f zebra$(EXEEXT)
+       $(LINK) $(zebra_LDFLAGS) $(zebra_OBJECTS) $(zebra_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connected.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redistribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtadv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_vty.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zserv.Po@am__quote@
+
+distclean-depend:
+       -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@     -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@   then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@   else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@   fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+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 =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+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
+
+ctags: CTAGS
+CTAGS:  $(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 "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_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 tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(DISTFILES)'; for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+           dir="/$$dir"; \
+           $(mkinstalldirs) "$(distdir)$$dir"; \
+         else \
+           dir=''; \
+         fi; \
+         if test -d $$d/$$file; then \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+       $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+       distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+       uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-sbinPROGRAMS ctags 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 pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am uninstall-info-am \
+       uninstall-sbinPROGRAMS uninstall-sysconfDATA
+
+
+#client : client_main.o ../lib/libzebra.a
+#      $(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6)
+
+install-sysconfDATA: $(sysconf_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       @list='$(sysconf_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+           $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+         fi; fi; \
+       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/zebra/client_main.c b/zebra/client_main.c
new file mode 100644 (file)
index 0000000..c319aac
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * $Id: client_main.c,v 1.1 2002/12/13 20:15:30 paul Exp $
+ *
+ * GNU Zebra client test main routine.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "stream.h"
+#include "zclient.h"
+#include "thread.h"
+#include "table.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+
+struct thread *master;
+
+/* Zebra client structure. */
+struct zclient *zclient = NULL;
+
+/* Zebra socket. */
+int sock;
+
+/* IPv4 route add and delete test. */
+void
+zebra_test_ipv4 (int command, int type, char *prefix, char *gateway,
+                u_char distance)
+{
+  struct zapi_ipv4 api;
+  struct prefix_ipv4 p;
+  struct in_addr gate;
+  struct in_addr *gpnt;
+
+  str2prefix_ipv4 (prefix, &p);
+  inet_aton (gateway, &gate);
+  gpnt = &gate;
+
+  api.type = type;
+  api.flags = 0;
+
+  api.message = 0;
+  SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+  api.nexthop_num = 1;
+  api.nexthop = &gpnt;
+  api.ifindex_num = 0;
+  if (distance)
+    {
+      SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+      api.distance = distance;
+    }
+  
+
+  switch (command)
+    {
+    case ZEBRA_IPV4_ROUTE_ADD:
+      zapi_ipv4_add (zclient, &p, &api);
+      break;
+    case ZEBRA_IPV4_ROUTE_DELETE:
+      zapi_ipv4_delete (zclient, &p, &api);
+      break;
+    }
+}
+
+#ifdef HAVE_IPV6
+/* IPv6 route add and delete test. */
+void
+zebra_test_v6 (int sock)
+{
+  struct prefix_ipv6 p;
+  struct in6_addr nexthop;
+
+  str2prefix_ipv6 ("3ffe:506::2/128", &p);
+  inet_pton (AF_INET6, "::1", &nexthop);
+
+  /* zebra_ipv6_add (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
+
+  sleep (5);
+  /* zebra_ipv6_delete (sock, ZEBRA_ROUTE_STATIC, 0, &p, &nexthop, 1); */
+}
+#endif /* HAVE_IPV6 */
+
+/* Print out usage and exit. */
+void
+usage_exit ()
+{
+  fprintf (stderr, "Usage: client filename\n");
+  exit (1);
+}
+
+struct zebra_info 
+{
+  char *str;
+  int type;
+} zebra_type[] = 
+{
+  { "static", ZEBRA_ROUTE_STATIC },
+  { "rip",    ZEBRA_ROUTE_RIP },
+  { "ripng",  ZEBRA_ROUTE_RIPNG },
+  { "ospf",   ZEBRA_ROUTE_OSPF },
+  { "ospf6",  ZEBRA_ROUTE_OSPF6 },
+  { "bgp",    ZEBRA_ROUTE_BGP },
+  { NULL,     0 }
+};
+
+/* Zebra route simulator. */
+void
+zebra_sim (FILE *fp)
+{
+  char buf[BUFSIZ];
+  char distance_str[BUFSIZ];
+  u_char distance;
+
+  while (fgets (buf, sizeof buf, fp))
+    {
+      int i;
+      int ret;
+      int type;
+      char str[BUFSIZ], command[BUFSIZ], prefix[BUFSIZ], gateway[BUFSIZ];
+
+      distance = 0;
+
+      if (*buf == '#')
+       continue;
+
+      type = ZEBRA_ROUTE_STATIC;
+
+      ret = sscanf (buf, "%s %s %s %s %s\n", command, str, prefix, gateway,
+                   distance_str);
+
+      if (ret == 5)
+       {
+         distance = atoi (distance_str);
+       }
+      else
+       {
+         ret = sscanf (buf, "%s %s %s %s\n", command, str, prefix, gateway);
+
+         if (ret != 4)
+           continue;
+       }
+
+      for (i = 0; i < 10; i++)
+       {
+         if (!zebra_type[i].str)
+           break;
+         if (strcmp (zebra_type[i].str, str) == 0)
+           {
+             type = zebra_type[i].type;
+             break;
+           }
+       }
+      
+      if (strcmp (command, "add") == 0)
+       {
+         zebra_test_ipv4 (ZEBRA_IPV4_ROUTE_ADD, type, prefix, gateway,
+                          distance);
+         printf ("%s", buf);
+         continue;
+       }
+
+      if (strcmp (command, "del") == 0)
+       {
+         zebra_test_ipv4 (ZEBRA_IPV4_ROUTE_DELETE, type, prefix, gateway,
+                          distance);
+         printf ("%s", buf);
+         continue;
+       }
+    }
+}
+
+/* Test zebra client main routine. */
+int
+main (int argc, char **argv)
+{
+  FILE *fp;
+
+  if (argc == 1)
+      usage_exit ();
+
+  /* Establish connection to zebra. */
+  zclient = zclient_new ();
+  zclient->enable = 1;
+#ifdef HAVE_TCP_ZEBRA
+  zclient->sock = zclient_socket ();
+#else
+  zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+
+  /* Open simulation file. */
+  fp = fopen (argv[1], "r");
+  if (fp == NULL)
+    {
+      fprintf (stderr, "can't open %s\n", argv[1]);
+      exit (1);
+    }
+
+  /* Do main work. */
+  zebra_sim (fp);
+
+  sleep (100);
+
+  fclose (fp);
+  close (sock);
+
+  return 0;
+}
diff --git a/zebra/connected.c b/zebra/connected.c
new file mode 100644 (file)
index 0000000..cb43074
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Address linked list routine.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "table.h"
+#include "rib.h"
+#include "table.h"
+#include "log.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+\f
+/* If same interface address is already exist... */
+struct connected *
+connected_check_ipv4 (struct interface *ifp, struct prefix *p)
+{
+  struct connected *ifc;
+  listnode node;
+
+  for (node = listhead (ifp->connected); node; node = nextnode (node))
+    {
+      ifc = getdata (node);
+
+      if (prefix_same (ifc->address, p))
+       return ifc;
+    }
+  return NULL;
+}
+
+/* Called from if_up(). */
+void
+connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv4 p;
+  struct prefix_ipv4 *addr;
+  struct prefix_ipv4 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv4 *) ifc->address;
+  dest = (struct prefix_ipv4 *) ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = addr->prefixlen;
+
+  /* Point-to-point check. */
+  if (if_is_pointopoint (ifp))
+    p.prefix = dest->prefix;
+  else
+    p.prefix = addr->prefix;
+
+  /* Apply mask to the network. */
+  apply_mask_ipv4 (&p);
+
+  /* In case of connected address is 0.0.0.0/0 we treat it tunnel
+     address. */
+  if (prefix_ipv4_any (&p))
+    return;
+
+  rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
+
+  rib_update ();
+}
+
+/* Add connected IPv4 route to the interface. */
+void
+connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, 
+                   int prefixlen, struct in_addr *broad, char *label)
+{
+  struct prefix_ipv4 *p;
+  struct connected *ifc;
+  struct connected *current;
+
+  /* Make connected structure. */
+  ifc = connected_new ();
+  ifc->ifp = ifp;
+  ifc->flags = flags;
+
+  /* Allocate new connected address. */
+  p = prefix_ipv4_new ();
+  p->family = AF_INET;
+  p->prefix = *addr;
+  p->prefixlen = prefixlen;
+  ifc->address = (struct prefix *) p;
+
+  /* If there is broadcast or pointopoint address. */
+  if (broad)
+    {
+      p = prefix_ipv4_new ();
+      p->family = AF_INET;
+      p->prefix = *broad;
+      ifc->destination = (struct prefix *) p;
+    }
+
+  /* Label of this address. */
+  if (label)
+    ifc->label = strdup (label);
+
+  /* Check same connected route. */
+  current = connected_check_ipv4 (ifp, (struct prefix *) ifc->address);
+  if (current)
+    {
+      connected_free (ifc);
+      ifc = current;
+    }
+  else
+    {
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* Update interface address information to protocol daemon. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      zebra_interface_address_add_update (ifp, ifc);
+
+      if (if_is_up(ifp))
+       connected_up_ipv4 (ifp, ifc);
+    }
+}
+
+void
+connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv4 p;
+  struct prefix_ipv4 *addr;
+  struct prefix_ipv4 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv4 *)ifc->address;
+  dest = (struct prefix_ipv4 *)ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = addr->prefixlen;
+
+  if (if_is_pointopoint (ifp))
+    p.prefix = dest->prefix;
+  else
+    p.prefix = addr->prefix;
+
+  /* Apply mask to the network. */
+  apply_mask_ipv4 (&p);
+
+  /* In case of connected address is 0.0.0.0/0 we treat it tunnel
+     address. */
+  if (prefix_ipv4_any (&p))
+    return;
+
+  rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+  rib_update ();
+}
+
+/* Delete connected IPv4 route to the interface. */
+void
+connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
+                      int prefixlen, struct in_addr *broad, char *label)
+{
+  struct prefix_ipv4 p;
+  struct connected *ifc;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = *addr;
+  p.prefixlen = prefixlen;
+
+  ifc = connected_check_ipv4 (ifp, (struct prefix *) &p);
+  if (! ifc)
+    return;
+
+  /* Update interface address information to protocol daemon. */
+  if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      zebra_interface_address_delete_update (ifp, ifc);
+
+      connected_down_ipv4 (ifp, ifc);
+
+      UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+    }
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+    }
+}
+
+#ifdef HAVE_IPV6
+/* If same interface address is already exist... */
+struct connected *
+connected_check_ipv6 (struct interface *ifp, struct prefix *p)
+{
+  struct connected *ifc;
+  listnode node;
+
+  for (node = listhead (ifp->connected); node; node = nextnode (node))
+    {
+      ifc = getdata (node);
+
+      if (prefix_same (ifc->address, p))
+       return ifc;
+    }
+  return 0;
+}
+
+void
+connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv6 p;
+  struct prefix_ipv6 *addr;
+  struct prefix_ipv6 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv6 *) ifc->address;
+  dest = (struct prefix_ipv6 *) ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = addr->prefixlen;
+
+  if (if_is_pointopoint (ifp) && dest)
+    {
+      if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
+       p.prefix = addr->prefix;
+      else
+       p.prefix = dest->prefix;
+    }
+  else
+    p.prefix = addr->prefix;
+
+  /* Apply mask to the network. */
+  apply_mask_ipv6 (&p);
+
+  if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
+    return;
+
+  rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+  rib_update ();
+}
+
+/* Add connected IPv6 route to the interface. */
+void
+connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
+                   int prefixlen, struct in6_addr *broad)
+{
+  struct prefix_ipv6 *p;
+  struct connected *ifc;
+  struct connected *current;
+
+  /* Make connected structure. */
+  ifc = connected_new ();
+  ifc->ifp = ifp;
+
+  /* Allocate new connected address. */
+  p = prefix_ipv6_new ();
+  p->family = AF_INET6;
+  IPV6_ADDR_COPY (&p->prefix, addr);
+  p->prefixlen = prefixlen;
+  ifc->address = (struct prefix *) p;
+
+  /* If there is broadcast or pointopoint address. */
+  if (broad)
+    {
+      p = prefix_ipv6_new ();
+      p->family = AF_INET6;
+      IPV6_ADDR_COPY (&p->prefix, broad);
+      ifc->destination = (struct prefix *) p;
+    }
+
+  current = connected_check_ipv6 (ifp, (struct prefix *) ifc->address);
+  if (current)
+    {
+      connected_free (ifc);
+      ifc = current;
+    }
+  else
+    {
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* Update interface address information to protocol daemon. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      zebra_interface_address_add_update (ifp, ifc);
+
+      if (if_is_up(ifp))
+       connected_up_ipv6 (ifp, ifc);
+    }
+}
+
+void
+connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix_ipv6 p;
+  struct prefix_ipv6 *addr;
+  struct prefix_ipv6 *dest;
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    return;
+
+  addr = (struct prefix_ipv6 *) ifc->address;
+  dest = (struct prefix_ipv6 *) ifc->destination;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = addr->prefixlen;
+
+  if (if_is_pointopoint (ifp) && dest)
+    {
+      if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
+       p.prefix = addr->prefix;
+      else
+       p.prefix = dest->prefix;
+    }
+  else
+    p.prefix = addr->prefix;
+
+  apply_mask_ipv6 (&p);
+
+  if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
+    return;
+
+  rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+  rib_update ();
+}
+
+void
+connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
+                    int prefixlen, struct in6_addr *broad)
+{
+  struct prefix_ipv6 p;
+  struct connected *ifc;
+  
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  memcpy (&p.prefix, address, sizeof (struct in6_addr));
+  p.prefixlen = prefixlen;
+
+  ifc = connected_check_ipv6 (ifp, (struct prefix *) &p);
+  if (! ifc)
+    return;
+
+  /* Update interface address information to protocol daemon. */
+  if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+    {
+      zebra_interface_address_delete_update (ifp, ifc);
+
+      connected_down_ipv6 (ifp, ifc);
+
+      UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+    }
+
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+    }
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/connected.h b/zebra/connected.h
new file mode 100644 (file)
index 0000000..7bf13ba
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Interface's address and mask.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_CONNECTED_H
+#define _ZEBRA_CONNECTED_H
+
+struct connected *
+connected_check_ipv4 (struct interface *ifp, struct prefix *p);
+
+void
+connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, 
+                   int prefixlen, struct in_addr *broad, char *label);
+
+void
+connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
+                      int prefixlen, struct in_addr *broad, char *label);
+
+void
+connected_up_ipv4 (struct interface *, struct connected *);
+void
+connected_down_ipv4 (struct interface *, struct connected *);
+
+#ifdef HAVE_IPV6
+struct connected *
+connected_check_ipv6 (struct interface *ifp, struct prefix *p);
+
+void
+connected_add_ipv6 (struct interface *ifp, struct in6_addr *address,
+                   int prefixlen, struct in6_addr *broad);
+void
+connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
+                      int prefixlen, struct in6_addr *broad);
+void
+connected_up_ipv6 (struct interface *, struct connected *);
+
+void
+connected_down_ipv6 (struct interface *ifp, struct connected *);
+
+#endif /* HAVE_IPV6 */
+
+#endif /*_ZEBRA_CONNECTED_H */
diff --git a/zebra/debug.c b/zebra/debug.c
new file mode 100644 (file)
index 0000000..fc99623
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Zebra debug related function
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include "command.h"
+#include "debug.h"
+
+/* For debug statement. */
+unsigned long zebra_debug_event;
+unsigned long zebra_debug_packet;
+unsigned long zebra_debug_kernel;
+
+DEFUN (show_debugging_zebra,
+       show_debugging_zebra_cmd,
+       "show debugging zebra",
+       SHOW_STR
+       "Zebra configuration\n"
+       "Debugging information\n")
+{
+  vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    vty_out (vty, "  Zebra event debugging is on%s", VTY_NEWLINE);
+
+  if (IS_ZEBRA_DEBUG_PACKET)
+    {
+      if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV)
+       {
+         vty_out (vty, "  Zebra packet%s debugging is on%s",
+                  IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+                  VTY_NEWLINE);
+       }
+      else
+       {
+         if (IS_ZEBRA_DEBUG_SEND)
+           vty_out (vty, "  Zebra packet send%s debugging is on%s",
+                    IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, "  Zebra packet receive%s debugging is on%s",
+                    IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+       }
+    }
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    vty_out (vty, "  Zebra kernel debugging is on%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_events,
+       debug_zebra_events_cmd,
+       "debug zebra events",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra events\n")
+{
+  zebra_debug_event = ZEBRA_DEBUG_EVENT;
+  return CMD_WARNING;
+}
+
+DEFUN (debug_zebra_packet,
+       debug_zebra_packet_cmd,
+       "debug zebra packet",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n")
+{
+  zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+  zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+  zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_packet_direct,
+       debug_zebra_packet_direct_cmd,
+       "debug zebra packet (recv|send)",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+{
+  zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+  zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_packet_detail,
+       debug_zebra_packet_detail_cmd,
+       "debug zebra packet (recv|send) detail",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n"
+       "Debug option set detaied information\n")
+{
+  zebra_debug_packet = ZEBRA_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet |= ZEBRA_DEBUG_RECV;
+  zebra_debug_packet |= ZEBRA_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_zebra_kernel,
+       debug_zebra_kernel_cmd,
+       "debug zebra kernel",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra between kernel interface\n")
+{
+  zebra_debug_kernel = ZEBRA_DEBUG_KERNEL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_events,
+       no_debug_zebra_events_cmd,
+       "no debug zebra events",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra events\n")
+{
+  zebra_debug_event = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_packet,
+       no_debug_zebra_packet_cmd,
+       "no debug zebra packet",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n")
+{
+  zebra_debug_packet = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_packet_direct,
+       no_debug_zebra_packet_direct_cmd,
+       "no debug zebra packet (recv|send)",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra packet\n"
+       "Debug option set for receive packet\n"
+       "Debug option set for send packet\n")
+{
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet &= ~ZEBRA_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    zebra_debug_packet &= ~ZEBRA_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_zebra_kernel,
+       no_debug_zebra_kernel_cmd,
+       "no debug zebra kernel",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra between kernel interface\n")
+{
+  zebra_debug_kernel = 0;
+  return CMD_SUCCESS;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  "",                          /* Debug node has no interface. */
+  1
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+  int write = 0;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    {
+      vty_out (vty, "debug zebra events%s", VTY_NEWLINE);
+      write++;
+    }
+  if (IS_ZEBRA_DEBUG_PACKET)
+    {
+      if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV)
+       {
+         vty_out (vty, "debug zebra packet%s%s",
+                  IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+                  VTY_NEWLINE);
+         write++;
+       }
+      else
+       {
+         if (IS_ZEBRA_DEBUG_SEND)
+           vty_out (vty, "debug zebra packet send%s%s",
+                    IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         else
+           vty_out (vty, "debug zebra packet recv%s%s",
+                    IS_ZEBRA_DEBUG_DETAIL ? " detail" : "",
+                    VTY_NEWLINE);
+         write++;
+       }
+    }
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    {
+      vty_out (vty, "debug zebra kernel%s", VTY_NEWLINE);
+      write++;
+    }
+  return write;
+}
+
+void
+zebra_debug_init ()
+{
+  zebra_debug_event = 0;
+  zebra_debug_packet = 0;
+
+  install_node (&debug_node, config_write_debug);
+
+  install_element (VIEW_NODE, &show_debugging_zebra_cmd);
+
+  install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_events_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_kernel_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
+
+  install_element (CONFIG_NODE, &debug_zebra_events_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_kernel_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
+}
diff --git a/zebra/debug.h b/zebra/debug.h
new file mode 100644 (file)
index 0000000..6eaa957
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Zebra debug related function
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_DEBUG_H
+#define _ZEBRA_DEBUG_H
+
+/* Debug flags. */
+#define ZEBRA_DEBUG_EVENT   0x01
+
+#define ZEBRA_DEBUG_PACKET  0x01
+#define ZEBRA_DEBUG_SEND    0x20
+#define ZEBRA_DEBUG_RECV    0x40
+#define ZEBRA_DEBUG_DETAIL  0x80
+
+#define ZEBRA_DEBUG_KERNEL  0x01
+
+/* Debug related macro. */
+#define IS_ZEBRA_DEBUG_EVENT  (zebra_debug_event & ZEBRA_DEBUG_EVENT)
+
+#define IS_ZEBRA_DEBUG_PACKET (zebra_debug_packet & ZEBRA_DEBUG_PACKET)
+#define IS_ZEBRA_DEBUG_SEND   (zebra_debug_packet & ZEBRA_DEBUG_SEND)
+#define IS_ZEBRA_DEBUG_RECV   (zebra_debug_packet & ZEBRA_DEBUG_RECV)
+#define IS_ZEBRA_DEBUG_DETAIL (zebra_debug_packet & ZEBRA_DEBUG_DETAIL)
+
+#define IS_ZEBRA_DEBUG_KERNEL (zebra_debug_kernel & ZEBRA_DEBUG_KERNEL)
+
+extern unsigned long zebra_debug_event;
+extern unsigned long zebra_debug_packet;
+extern unsigned long zebra_debug_kernel;
+
+void zebra_debug_init ();
+
+#endif /* _ZEBRA_DEBUG_H */
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
new file mode 100644 (file)
index 0000000..46f5301
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Interface looking up by ioctl ().
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "memory.h"
+#include "log.h"
+
+#include "zebra/interface.h"
+
+/* Interface looking up using infamous SIOCGIFCONF. */
+int
+interface_list_ioctl ()
+{
+  int ret;
+  int sock;
+#define IFNUM_BASE 32
+  int ifnum;
+  struct ifreq *ifreq;
+  struct ifconf ifconf;
+  struct interface *ifp;
+  int n;
+  int lastlen;
+
+  /* Normally SIOCGIFCONF works with AF_INET socket. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) 
+    {
+      zlog_warn ("Can't make AF_INET socket stream: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Set initial ifreq count.  This will be double when SIOCGIFCONF
+     fail.  Solaris has SIOCGIFNUM. */
+#ifdef SIOCGIFNUM
+  ret = ioctl (sock, SIOCGIFNUM, &ifnum);
+  if (ret < 0)
+    ifnum = IFNUM_BASE;
+  else
+    ifnum++;
+#else
+  ifnum = IFNUM_BASE;
+#endif /* SIOCGIFNUM */
+
+  ifconf.ifc_buf = NULL;
+
+  lastlen = 0;
+  /* Loop until SIOCGIFCONF success. */
+  for (;;) 
+    {
+      ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
+      ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
+
+      ret = ioctl(sock, SIOCGIFCONF, &ifconf);
+
+      if (ret < 0) 
+       {
+         zlog_warn ("SIOCGIFCONF: %s", strerror(errno));
+         goto end;
+       }
+      /* Repeatedly get info til buffer fails to grow. */
+      if (ifconf.ifc_len > lastlen)
+       {
+          lastlen = ifconf.ifc_len;
+         ifnum += 10;
+         continue;
+       }
+      /* Success. */
+      break;
+    }
+
+  /* Allocate interface. */
+  ifreq = ifconf.ifc_req;
+
+#ifdef OPEN_BSD
+  for (n = 0; n < ifconf.ifc_len; )
+    {
+      int size;
+
+      ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
+      ifp = if_get_by_name (ifreq->ifr_name);
+      if_add_update (ifp);
+      size = ifreq->ifr_addr.sa_len;
+      if (size < sizeof (ifreq->ifr_addr))
+       size = sizeof (ifreq->ifr_addr);
+      size += sizeof (ifreq->ifr_name);
+      n += size;
+    }
+#else
+  for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
+    {
+      ifp = if_get_by_name (ifreq->ifr_name);
+      if_add_update (ifp);
+      ifreq++;
+    }
+#endif /* OPEN_BSD */
+
+ end:
+  close (sock);
+  XFREE (MTYPE_TMP, ifconf.ifc_buf);
+
+  return ret;
+}
+
+/* Get interface's index by ioctl. */
+int
+if_get_index (struct interface *ifp)
+{
+  static int if_fake_index = 1;
+
+#ifdef HAVE_BROKEN_ALIASES
+  /* Linux 2.2.X does not provide individual interface index for aliases. */
+  ifp->ifindex = if_fake_index++;
+  return ifp->ifindex;
+#else
+#ifdef SIOCGIFINDEX
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
+  if (ret < 0)
+    {
+      /* Linux 2.0.X does not have interface index. */
+      ifp->ifindex = if_fake_index++;
+      return ifp->ifindex;
+    }
+
+  /* OK we got interface index. */
+#ifdef ifr_ifindex
+  ifp->ifindex = ifreq.ifr_ifindex;
+#else
+  ifp->ifindex = ifreq.ifr_index;
+#endif
+  return ifp->ifindex;
+
+#else
+  ifp->ifindex = if_fake_index++;
+  return ifp->ifindex;
+#endif /* SIOCGIFINDEX */
+#endif /* HAVE_BROKEN_ALIASES */
+}
+
+#ifdef SIOCGIFHWADDR
+int
+if_get_hwaddr (struct interface *ifp)
+{
+  int ret;
+  struct ifreq ifreq;
+  int i;
+
+  strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+  ifreq.ifr_addr.sa_family = AF_INET;
+
+  /* Fetch Hardware address if available. */
+  ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
+  if (ret < 0)
+    ifp->hw_addr_len = 0;
+  else
+    {
+      memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
+
+      for (i = 0; i < 6; i++)
+       if (ifp->hw_addr[i] != 0)
+         break;
+
+      if (i == 6)
+       ifp->hw_addr_len = 0;
+      else
+       ifp->hw_addr_len = 6;
+    }
+  return 0;
+}
+#endif /* SIOCGIFHWADDR */
+
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+
+int
+if_getaddrs ()
+{
+  int ret;
+  struct ifaddrs *ifap;
+  struct ifaddrs *ifapfree;
+  struct interface *ifp;
+  int prefixlen;
+
+  ret = getifaddrs (&ifap); 
+  if (ret != 0)
+    {
+      zlog_err ("getifaddrs(): %s", strerror (errno));
+      return -1;
+    }
+
+  for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
+    {
+      ifp = if_lookup_by_name (ifap->ifa_name);
+      if (ifp == NULL)
+       {
+         zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
+                   ifap->ifa_name);
+         continue;
+       }
+
+      if (ifap->ifa_addr->sa_family == AF_INET)
+       {
+         struct sockaddr_in *addr;
+         struct sockaddr_in *mask;
+         struct sockaddr_in *dest;
+         struct in_addr *dest_pnt;
+
+         addr = (struct sockaddr_in *) ifap->ifa_addr;
+         mask = (struct sockaddr_in *) ifap->ifa_netmask;
+         prefixlen = ip_masklen (mask->sin_addr);
+
+         dest_pnt = NULL;
+
+         if (ifap->ifa_flags & IFF_POINTOPOINT) 
+           {
+             dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
+             dest_pnt = &dest->sin_addr;
+           }
+
+         if (ifap->ifa_flags & IFF_BROADCAST)
+           {
+             dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
+             dest_pnt = &dest->sin_addr;
+           }
+
+         connected_add_ipv4 (ifp, 0, &addr->sin_addr,
+                             prefixlen, dest_pnt, NULL);
+       }
+#ifdef HAVE_IPV6
+      if (ifap->ifa_addr->sa_family == AF_INET6)
+       {
+         struct sockaddr_in6 *addr;
+         struct sockaddr_in6 *mask;
+         struct sockaddr_in6 *dest;
+         struct in6_addr *dest_pnt;
+
+         addr = (struct sockaddr_in6 *) ifap->ifa_addr;
+         mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
+         prefixlen = ip6_masklen (mask->sin6_addr);
+
+         dest_pnt = NULL;
+
+         if (ifap->ifa_flags & IFF_POINTOPOINT) 
+           {
+             if (ifap->ifa_dstaddr)
+               {
+                 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
+                 dest_pnt = &dest->sin6_addr;
+               }
+           }
+
+         if (ifap->ifa_flags & IFF_BROADCAST)
+           {
+             if (ifap->ifa_broadaddr)
+               {
+                 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
+                 dest_pnt = &dest->sin6_addr;
+               }
+           }
+
+         connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt);
+       }
+#endif /* HAVE_IPV6 */
+    }
+
+  freeifaddrs (ifapfree);
+
+  return 0; 
+}
+#else /* HAVE_GETIFADDRS */
+/* Interface address lookup by ioctl.  This function only looks up
+   IPv4 address. */
+int
+if_get_addr (struct interface *ifp)
+{
+  int ret;
+  struct ifreq ifreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in mask;
+  struct sockaddr_in dest;
+  struct in_addr *dest_pnt;
+  u_char prefixlen;
+
+  /* Interface's name and address family. */
+  strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+  ifreq.ifr_addr.sa_family = AF_INET;
+
+  /* Interface's address. */
+  ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
+  if (ret < 0) 
+    {
+      if (errno != EADDRNOTAVAIL)
+       {
+         zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno));
+         return ret;
+       }
+      return 0;
+    }
+  memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
+
+  /* Interface's network mask. */
+  ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
+  if (ret < 0) 
+    {
+      if (errno != EADDRNOTAVAIL) 
+       {
+         zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno));
+         return ret;
+       }
+      return 0;
+    }
+#ifdef ifr_netmask
+  memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
+#else
+  memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
+#endif /* ifr_netmask */
+  prefixlen = ip_masklen (mask.sin_addr);
+
+  /* Point to point or borad cast address pointer init. */
+  dest_pnt = NULL;
+
+  if (ifp->flags & IFF_POINTOPOINT) 
+    {
+      ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
+      if (ret < 0) 
+       {
+         if (errno != EADDRNOTAVAIL) 
+           {
+             zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno));
+             return ret;
+           }
+         return 0;
+       }
+      memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
+      dest_pnt = &dest.sin_addr;
+    }
+  if (ifp->flags & IFF_BROADCAST)
+    {
+      ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
+      if (ret < 0) 
+       {
+         if (errno != EADDRNOTAVAIL) 
+           {
+             zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno));
+             return ret;
+           }
+         return 0;
+       }
+      memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
+      dest_pnt = &dest.sin_addr;
+    }
+
+
+  /* Set address to the interface. */
+  connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL);
+
+  return 0;
+}
+#endif /* HAVE_GETIFADDRS */
+
+/* Fetch interface information via ioctl(). */
+static void
+interface_info_ioctl ()
+{
+  listnode node;
+  struct interface *ifp;
+  
+  for (node = listhead (iflist); node; node = nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if_get_index (ifp);
+#ifdef SIOCGIFHWADDR
+      if_get_hwaddr (ifp);
+#endif /* SIOCGIFHWADDR */
+      if_get_flags (ifp);
+#ifndef HAVE_GETIFADDRS
+      if_get_addr (ifp);
+#endif /* ! HAVE_GETIFADDRS */
+      if_get_mtu (ifp);
+      if_get_metric (ifp);
+    }
+}
+
+/* Lookup all interface information. */
+void
+interface_list ()
+{
+  /* Linux can do both proc & ioctl, ioctl is the only way to get
+     interface aliases in 2.2 series kernels. */
+#ifdef HAVE_PROC_NET_DEV
+  interface_list_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+  interface_list_ioctl ();
+
+  /* After listing is done, get index, address, flags and other
+     interface's information. */
+  interface_info_ioctl ();
+
+#ifdef HAVE_GETIFADDRS
+  if_getaddrs ();
+#endif /* HAVE_GETIFADDRS */
+
+#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
+  /* Linux provides interface's IPv6 address via
+     /proc/net/if_inet6. */
+  ifaddr_proc_ipv6 ();
+#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
+}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
new file mode 100644 (file)
index 0000000..c9c1476
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Interface looking up by netlink.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* Extern from rt_netlink.c */  
+void interface_lookup_netlink ();  
+
+/* Interface information read by netlink. */
+void
+interface_list ()
+{
+  interface_lookup_netlink ();  
+}
diff --git a/zebra/if_proc.c b/zebra/if_proc.c
new file mode 100644 (file)
index 0000000..117859f
--- /dev/null
@@ -0,0 +1,246 @@
+/* Interface name and statistics get function using proc file system
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "zebra/ioctl.h"
+#include "zebra/connected.h"
+#include "zebra/interface.h"
+
+/* Proc filesystem one line buffer. */
+#define PROCBUFSIZ                  1024
+
+/* Path to device proc file system. */
+#ifndef _PATH_PROC_NET_DEV
+#define _PATH_PROC_NET_DEV        "/proc/net/dev"
+#endif /* _PATH_PROC_NET_DEV */
+
+/* Return statistics data pointer. */
+static char *
+interface_name_cut (char *buf, char **name)
+{
+  char *stat;
+
+  /* Skip white space.  Line will include header spaces. */
+  while (*buf == ' ')
+    buf++;
+  *name = buf;
+
+  /* Cut interface name. */
+  stat = strrchr (buf, ':');
+  *stat++ = '\0';
+
+  return stat;
+}
+
+/* Fetch each statistics field. */
+static int
+ifstat_dev_fields (int version, char *buf, struct interface *ifp)
+{
+  switch (version) 
+    {
+    case 3:
+      sscanf(buf,
+            "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+            &ifp->stats.rx_bytes,
+            &ifp->stats.rx_packets,
+            &ifp->stats.rx_errors,
+            &ifp->stats.rx_dropped,
+            &ifp->stats.rx_fifo_errors,
+            &ifp->stats.rx_frame_errors,
+            &ifp->stats.rx_compressed,
+            &ifp->stats.rx_multicast,
+
+            &ifp->stats.tx_bytes,
+            &ifp->stats.tx_packets,
+            &ifp->stats.tx_errors,
+            &ifp->stats.tx_dropped,
+            &ifp->stats.tx_fifo_errors,
+            &ifp->stats.collisions,
+            &ifp->stats.tx_carrier_errors,
+            &ifp->stats.tx_compressed);
+      break;
+    case 2:
+      sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+            &ifp->stats.rx_bytes,
+            &ifp->stats.rx_packets,
+            &ifp->stats.rx_errors,
+            &ifp->stats.rx_dropped,
+            &ifp->stats.rx_fifo_errors,
+            &ifp->stats.rx_frame_errors,
+
+            &ifp->stats.tx_bytes,
+            &ifp->stats.tx_packets,
+            &ifp->stats.tx_errors,
+            &ifp->stats.tx_dropped,
+            &ifp->stats.tx_fifo_errors,
+            &ifp->stats.collisions,
+            &ifp->stats.tx_carrier_errors);
+      ifp->stats.rx_multicast = 0;
+      break;
+    case 1:
+      sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+            &ifp->stats.rx_packets,
+            &ifp->stats.rx_errors,
+            &ifp->stats.rx_dropped,
+            &ifp->stats.rx_fifo_errors,
+            &ifp->stats.rx_frame_errors,
+
+            &ifp->stats.tx_packets,
+            &ifp->stats.tx_errors,
+            &ifp->stats.tx_dropped,
+            &ifp->stats.tx_fifo_errors,
+            &ifp->stats.collisions,
+            &ifp->stats.tx_carrier_errors);
+      ifp->stats.rx_bytes = 0;
+      ifp->stats.tx_bytes = 0;
+      ifp->stats.rx_multicast = 0;
+      break;
+    }
+  return 0;
+}
+
+/* Update interface's statistics. */
+int
+ifstat_update_proc ()
+{
+  FILE *fp;
+  char buf[PROCBUFSIZ];
+  int version;
+  struct interface *ifp;
+  char *stat;
+  char *name;
+
+  /* Open /proc/net/dev. */
+  fp = fopen (_PATH_PROC_NET_DEV, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open proc file %s: %s",
+                _PATH_PROC_NET_DEV, strerror (errno));
+      return -1;
+    }
+
+  /* Drop header lines. */
+  fgets (buf, PROCBUFSIZ, fp);
+  fgets (buf, PROCBUFSIZ, fp);
+
+  /* To detect proc format veresion, parse second line. */
+  if (strstr (buf, "compressed"))
+    version = 3;
+  else if (strstr (buf, "bytes"))
+    version = 2;
+  else
+    version = 1;
+
+  /* Update each interface's statistics. */
+  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+    {
+      stat = interface_name_cut (buf, &name);
+      ifp = if_get_by_name (name);
+      ifstat_dev_fields (version, stat, ifp);
+    }
+
+  return 0;
+}
+
+/* Interface structure allocation by proc filesystem. */
+int
+interface_list_proc ()
+{
+  FILE *fp;
+  char buf[PROCBUFSIZ];
+  struct interface *ifp;
+  char *name;
+
+  /* Open /proc/net/dev. */
+  fp = fopen (_PATH_PROC_NET_DEV, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open proc file %s: %s",
+                _PATH_PROC_NET_DEV, strerror (errno));
+      return -1;
+    }
+
+  /* Drop header lines. */
+  fgets (buf, PROCBUFSIZ, fp);
+  fgets (buf, PROCBUFSIZ, fp);
+
+  /* Only allocate interface structure.  Other jobs will be done in
+     if_ioctl.c. */
+  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+    {
+      interface_name_cut (buf, &name);
+      ifp = if_get_by_name (name);
+      if_add_update (ifp);
+    }
+  return 0;
+}
+\f
+#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
+
+#ifndef _PATH_PROC_NET_IF_INET6
+#define _PATH_PROC_NET_IF_INET6          "/proc/net/if_inet6"
+#endif /* _PATH_PROC_NET_IF_INET6 */
+
+int
+ifaddr_proc_ipv6 ()
+{
+  FILE *fp;
+  char buf[PROCBUFSIZ];
+  int n;
+  char addr[33];
+  char ifname[20];
+  int ifindex, plen, scope, status;
+  struct interface *ifp;
+  struct prefix_ipv6 p;
+
+  /* Open proc file system. */
+  fp = fopen (_PATH_PROC_NET_IF_INET6, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open proc file %s: %s",
+                _PATH_PROC_NET_IF_INET6, strerror (errno));
+      return -1;
+    }
+  
+  /* Get interface's IPv6 address. */
+  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
+    {
+      n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", 
+                 addr, &ifindex, &plen, &scope, &status, ifname);
+      if (n != 6)
+       continue;
+
+      ifp = if_get_by_name (ifname);
+
+      /* Fetch interface's IPv6 address. */
+      str2in6_addr (addr, &p.prefix);
+      p.prefixlen = plen;
+
+      connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL);
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c
new file mode 100644 (file)
index 0000000..1441dfc
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Get interface's address and mask information by sysctl() function.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "connected.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "log.h"
+
+int
+ifstat_update_sysctl ()
+{
+  caddr_t ref, buf, end;
+  size_t bufsiz;
+  struct if_msghdr *ifm;
+  struct interface *ifp;
+
+#define MIBSIZ 6
+  int mib[MIBSIZ] =
+  { 
+    CTL_NET,
+    PF_ROUTE,
+    0,
+    0, /*  AF_INET & AF_INET6 */
+    NET_RT_IFLIST,
+    0 
+  };
+
+  /* Query buffer size. */
+  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog_warn ("sysctl() error by %s", strerror (errno));
+      return -1;
+    }
+
+  /* We free this memory at the end of this function. */
+  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+  /* Fetch interface informations into allocated buffer. */
+  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno));
+      return -1;
+    }
+
+  /* Parse both interfaces and addresses. */
+  for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) 
+    {
+      ifm = (struct if_msghdr *) buf;
+      if (ifm->ifm_type == RTM_IFINFO)
+       {
+         ifp = if_lookup_by_index (ifm->ifm_index);
+         if (ifp)
+           ifp->stats = ifm->ifm_data;
+       }
+    }
+
+  /* Free sysctl buffer. */
+  XFREE (MTYPE_TMP, ref);
+
+  return 0;
+}
+
+/* Interface listing up function using sysctl(). */
+void
+interface_list ()
+{
+  caddr_t ref, buf, end;
+  size_t bufsiz;
+  struct if_msghdr *ifm;
+  int ifm_read (struct if_msghdr *);
+  int ifam_read (struct ifa_msghdr *);
+
+#define MIBSIZ 6
+  int mib[MIBSIZ] =
+  { 
+    CTL_NET,
+    PF_ROUTE,
+    0,
+    0, /*  AF_INET & AF_INET6 */
+    NET_RT_IFLIST,
+    0 
+  };
+
+  /* Query buffer size. */
+  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "sysctl() error by %s", strerror (errno));
+      return;
+    }
+
+  /* We free this memory at the end of this function. */
+  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+
+  /* Fetch interface informations into allocated buffer. */
+  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno));
+      return;
+    }
+
+  /* Parse both interfaces and addresses. */
+  for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) 
+    {
+      ifm = (struct if_msghdr *) buf;
+
+      switch (ifm->ifm_type) 
+       {
+       case RTM_IFINFO:
+         ifm_read (ifm);
+         break;
+       case RTM_NEWADDR:
+         ifam_read ((struct ifa_msghdr *) ifm);
+         break;
+       default:
+         zlog_info ("interfaces_list(): unexpected message type");
+         XFREE (MTYPE_TMP, ref);
+         return;
+         break;
+       }
+    }
+
+  /* Free sysctl buffer. */
+  XFREE (MTYPE_TMP, ref);
+}
diff --git a/zebra/interface.c b/zebra/interface.c
new file mode 100644 (file)
index 0000000..5629ebb
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ * Interface function.
+ * Copyright (C) 1997, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "connected.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+\f
+/* Allocate a new internal interface index 
+ * This works done from the top so that %d macros
+ * print a - sign! 
+ */
+static unsigned int
+if_new_intern_ifindex (void)
+{
+  /* Start here so that first one assigned is 0xFFFFFFFF */
+  static unsigned int ifindex = IFINDEX_INTERNBASE + 1;
+
+  for (;;) 
+    {
+      ifindex--;
+      if ( ifindex <= IFINDEX_INTERNBASE )
+       ifindex = 0xFFFFFFFF;
+
+      if (if_lookup_by_index(ifindex) == NULL)
+       return ifindex;
+    }
+}
+
+/* Called when new interface is added. */
+int
+if_zebra_new_hook (struct interface *ifp)
+{
+  struct zebra_if *zebra_if;
+
+  zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if));
+  memset (zebra_if, 0, sizeof (struct zebra_if));
+
+  zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
+  zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC;
+
+#ifdef RTADV
+  {
+    /* Set default router advertise values. */
+    struct rtadvconf *rtadv;
+
+    rtadv = &zebra_if->rtadv;
+
+    rtadv->AdvSendAdvertisements = 0;
+    rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
+    rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
+    rtadv->AdvIntervalTimer = 0;
+    rtadv->AdvManagedFlag = 0;
+    rtadv->AdvOtherConfigFlag = 0;
+    rtadv->AdvLinkMTU = 0;
+    rtadv->AdvReachableTime = 0;
+    rtadv->AdvRetransTimer = 0;
+    rtadv->AdvCurHopLimit = 0;
+    rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+
+    rtadv->AdvPrefixList = list_new ();
+  }    
+#endif /* RTADV */
+
+  ifp->info = zebra_if;
+  return 0;
+}
+
+/* Called when interface is deleted. */
+int
+if_zebra_delete_hook (struct interface *ifp)
+{
+  if (ifp->info)
+    XFREE (MTYPE_TMP, ifp->info);
+  return 0;
+}
+
+/* Wake up configured address if it is not in current kernel
+   address. */
+void
+if_addr_wakeup (struct interface *ifp)
+{
+  struct listnode *node;
+  struct connected *ifc;
+  struct prefix *p;
+  int ret;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      ifc = getdata (node);
+      p = ifc->address;
+       
+      if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)
+         && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+       {
+         /* Address check. */
+         if (p->family == AF_INET)
+           {
+             if (! if_is_up (ifp))
+               {
+                 if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+                 if_refresh (ifp);
+               }
+
+             ret = if_set_prefix (ifp, ifc);
+             if (ret < 0)
+               {
+                 zlog_warn ("Can't set interface's address: %s", 
+                            strerror(errno));
+                 continue;
+               }
+             SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+             zebra_interface_address_add_update (ifp, ifc);
+
+             if (if_is_up(ifp))
+               connected_up_ipv4 (ifp, ifc);
+           }
+#ifdef HAVE_IPV6
+         if (p->family == AF_INET6)
+           {
+             if (! if_is_up (ifp))
+               {
+                 if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+                 if_refresh (ifp);
+               }
+
+             ret = if_prefix_add_ipv6 (ifp, ifc);
+             if (ret < 0)
+               {
+                 zlog_warn ("Can't set interface's address: %s", 
+                            strerror(errno));
+                 continue;
+               }
+             SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+             zebra_interface_address_add_update (ifp, ifc);
+
+             if (if_is_up(ifp))
+               connected_up_ipv6 (ifp, ifc);
+           }
+#endif /* HAVE_IPV6 */
+       }
+    }
+}
+
+/* Handle interface addition */
+void
+if_add_update (struct interface *ifp)
+{
+  zebra_interface_add_update (ifp);
+
+  if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+
+      if_addr_wakeup (ifp);
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("interface %s index %d becomes active.", 
+                  ifp->name, ifp->ifindex);
+    }
+  else
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("interface %s index %d is added.", ifp->name, ifp->ifindex);
+    }
+}
+
+/* Handle an interface delete event */
+void 
+if_delete_update (struct interface *ifp)
+{
+  struct listnode *node;
+  struct listnode *next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  if (if_is_up(ifp))
+    {
+      zlog_err ("interface %s index %d is still up while being deleted.",
+           ifp->name, ifp->ifindex);
+      return;
+    }
+
+  /* Mark interface as inactive */
+  UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+  
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("interface %s index %d is now inactive.",
+              ifp->name, ifp->ifindex);
+
+  /* Delete connected routes from the kernel. */
+  if (ifp->connected)
+    {
+      for (node = listhead (ifp->connected); node; node = next)
+       {
+         next = node->next;
+         ifc = getdata (node);
+         p = ifc->address;
+
+         if (p->family == AF_INET)
+           connected_down_ipv4 (ifp, ifc);
+#ifdef HAVE_IPV6
+         else if (p->family == AF_INET6)
+           connected_down_ipv6 (ifp, ifc);
+#endif /* HAVE_IPV6 */
+
+         zebra_interface_address_delete_update (ifp, ifc);
+
+         UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+         
+         if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+           {      
+             listnode_delete (ifp->connected, ifc);
+             connected_free (ifc);
+           }
+       }
+    }
+  zebra_interface_delete_update (ifp);
+}
+
+/* Interface is up. */
+void
+if_up (struct interface *ifp)
+{
+  listnode node;
+  listnode next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  /* Notify the protocol daemons. */
+  zebra_interface_up_update (ifp);
+
+  /* Install connected routes to the kernel. */
+  if (ifp->connected)
+    {
+      for (node = listhead (ifp->connected); node; node = next)
+       {
+         next = node->next;
+         ifc = getdata (node);
+         p = ifc->address;
+
+         if (p->family == AF_INET)
+           connected_up_ipv4 (ifp, ifc);
+#ifdef HAVE_IPV6
+         else if (p->family == AF_INET6)
+           connected_up_ipv6 (ifp, ifc);
+#endif /* HAVE_IPV6 */
+       }
+    }
+
+  /* Examine all static routes. */
+  rib_update ();
+}
+
+/* Interface goes down.  We have to manage different behavior of based
+   OS. */
+void
+if_down (struct interface *ifp)
+{
+  listnode node;
+  listnode next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  /* Notify to the protocol daemons. */
+  zebra_interface_down_update (ifp);
+
+  /* Delete connected routes from the kernel. */
+  if (ifp->connected)
+    {
+      for (node = listhead (ifp->connected); node; node = next)
+       {
+         next = node->next;
+         ifc = getdata (node);
+         p = ifc->address;
+
+         if (p->family == AF_INET)
+           connected_down_ipv4 (ifp, ifc);
+#ifdef HAVE_IPV6
+         else if (p->family == AF_INET6)
+           connected_down_ipv6 (ifp, ifc);
+#endif /* HAVE_IPV6 */
+       }
+    }
+
+  /* Examine all static routes which direct to the interface. */
+  rib_update ();
+}
+
+void
+if_refresh (struct interface *ifp)
+{
+  if (if_is_up (ifp))
+    {
+      if_get_flags (ifp);
+      if (! if_is_up (ifp))
+       if_down (ifp);
+    }
+  else
+    {
+      if_get_flags (ifp);
+      if (if_is_up (ifp))
+       if_up (ifp);
+    }
+}
+
+/* Printout flag information into vty */
+void
+if_flag_dump_vty (struct vty *vty, unsigned long flag)
+{
+  int separator = 0;
+
+#define IFF_OUT_VTY(X, Y) \
+  if ((X) && (flag & (X))) \
+    { \
+      if (separator) \
+       vty_out (vty, ","); \
+      else \
+       separator = 1; \
+      vty_out (vty, Y); \
+    }
+
+  vty_out (vty, "<");
+  IFF_OUT_VTY (IFF_UP, "UP");
+  IFF_OUT_VTY (IFF_BROADCAST, "BROADCAST");
+  IFF_OUT_VTY (IFF_DEBUG, "DEBUG");
+  IFF_OUT_VTY (IFF_LOOPBACK, "LOOPBACK");
+  IFF_OUT_VTY (IFF_POINTOPOINT, "POINTOPOINT");
+  IFF_OUT_VTY (IFF_NOTRAILERS, "NOTRAILERS");
+  IFF_OUT_VTY (IFF_RUNNING, "RUNNING");
+  IFF_OUT_VTY (IFF_NOARP, "NOARP");
+  IFF_OUT_VTY (IFF_PROMISC, "PROMISC");
+  IFF_OUT_VTY (IFF_ALLMULTI, "ALLMULTI");
+  IFF_OUT_VTY (IFF_OACTIVE, "OACTIVE");
+  IFF_OUT_VTY (IFF_SIMPLEX, "SIMPLEX");
+  IFF_OUT_VTY (IFF_LINK0, "LINK0");
+  IFF_OUT_VTY (IFF_LINK1, "LINK1");
+  IFF_OUT_VTY (IFF_LINK2, "LINK2");
+  IFF_OUT_VTY (IFF_MULTICAST, "MULTICAST");
+  vty_out (vty, ">");
+}
+
+/* Output prefix string to vty. */
+int
+prefix_vty_out (struct vty *vty, struct prefix *p)
+{
+  char str[INET6_ADDRSTRLEN];
+
+  inet_ntop (p->family, &p->u.prefix, str, sizeof (str));
+  vty_out (vty, "%s", str);
+  return strlen (str);
+}
+
+/* Dump if address information to vty. */
+void
+connected_dump_vty (struct vty *vty, struct connected *connected)
+{
+  struct prefix *p;
+  struct interface *ifp;
+
+  /* Set interface pointer. */
+  ifp = connected->ifp;
+
+  /* Print interface address. */
+  p = connected->address;
+  vty_out (vty, "  %s ", prefix_family_str (p));
+  prefix_vty_out (vty, p);
+  vty_out (vty, "/%d", p->prefixlen);
+
+  /* If there is destination address, print it. */
+  p = connected->destination;
+  if (p)
+    {
+      if (p->family == AF_INET)
+       if (ifp->flags & IFF_BROADCAST)
+         {
+           vty_out (vty, " broadcast ");
+           prefix_vty_out (vty, p);
+         }
+
+      if (ifp->flags & IFF_POINTOPOINT)
+       {
+         vty_out (vty, " pointopoint ");
+         prefix_vty_out (vty, p);
+       }
+    }
+
+  if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY))
+    vty_out (vty, " secondary");
+
+  if (connected->label)
+    vty_out (vty, " %s", connected->label);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+#ifdef RTADV
+/* Dump interface ND information to vty. */
+void
+nd_dump_vty (struct vty *vty, struct interface *ifp)
+{
+  struct zebra_if *zif;
+  struct rtadvconf *rtadv;
+
+  zif = (struct zebra_if *) ifp->info;
+  rtadv = &zif->rtadv;
+
+  if (rtadv->AdvSendAdvertisements)
+    {
+      vty_out (vty, "  ND advertised reachable time is %d milliseconds%s",
+              rtadv->AdvReachableTime, VTY_NEWLINE);
+      vty_out (vty, "  ND advertised retransmit interval is %d milliseconds%s",
+              rtadv->AdvRetransTimer, VTY_NEWLINE);
+      vty_out (vty, "  ND router advertisements are sent every %d seconds%s",
+              rtadv->MaxRtrAdvInterval, VTY_NEWLINE);
+      vty_out (vty, "  ND router advertisements live for %d seconds%s",
+              rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      if (rtadv->AdvManagedFlag)
+       vty_out (vty, "  Hosts use DHCP to obtain routable addresses.%s",
+                VTY_NEWLINE);
+      else
+       vty_out (vty, "  Hosts use stateless autoconfig for addresses.%s",
+                VTY_NEWLINE);
+    }
+}
+#endif /* RTADV */
+
+/* Interface's information print out to vty interface. */
+void
+if_dump_vty (struct vty *vty, struct interface *ifp)
+{
+#ifdef HAVE_SOCKADDR_DL
+  struct sockaddr_dl *sdl;
+#endif /* HAVE_SOCKADDR_DL */
+  struct connected *connected;
+  listnode node;
+
+  vty_out (vty, "Interface %s%s", ifp->name,
+          VTY_NEWLINE);
+  if (ifp->desc)
+    vty_out (vty, "  Description: %s%s", ifp->desc,
+            VTY_NEWLINE);
+  if (ifp->ifindex <= 0)
+    {
+      vty_out(vty, "  index %d pseudo interface%s", ifp->ifindex, VTY_NEWLINE);
+      return;
+    }
+  else if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      vty_out(vty, "  index %d inactive interface%s", 
+             ifp->ifindex, 
+             VTY_NEWLINE);
+      return;
+    }
+
+  vty_out (vty, "  index %d metric %d mtu %d ",
+          ifp->ifindex, ifp->metric, ifp->mtu);
+  if_flag_dump_vty (vty, ifp->flags);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  /* Hardware address. */
+#ifdef HAVE_SOCKADDR_DL
+  sdl = &ifp->sdl;
+  if (sdl != NULL && sdl->sdl_alen != 0)
+    {
+      int i;
+      u_char *ptr;
+
+      vty_out (vty, "  HWaddr: ");
+      for (i = 0, ptr = LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++)
+       vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+#else
+  if (ifp->hw_addr_len != 0)
+    {
+      int i;
+
+      vty_out (vty, "  HWaddr: ");
+      for (i = 0; i < ifp->hw_addr_len; i++)
+       vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+#endif /* HAVE_SOCKADDR_DL */
+  
+  /* Bandwidth in kbps */
+  if (ifp->bandwidth != 0)
+    {
+      vty_out(vty, "  bandwidth %u kbps", ifp->bandwidth);
+      vty_out(vty, "%s", VTY_NEWLINE);
+    }
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      connected = getdata (node);
+      if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL))
+       connected_dump_vty (vty, connected);
+    }
+
+#ifdef RTADV
+  nd_dump_vty (vty, ifp);
+#endif /* RTADV */
+
+#ifdef HAVE_PROC_NET_DEV
+  /* Statistics print out using proc file system. */
+  vty_out (vty, "    input packets %lu, bytes %lu, dropped %lu,"
+          " multicast packets %lu%s",
+          ifp->stats.rx_packets, ifp->stats.rx_bytes, 
+          ifp->stats.rx_dropped, ifp->stats.rx_multicast, VTY_NEWLINE);
+
+  vty_out (vty, "    input errors %lu, length %lu, overrun %lu,"
+          " CRC %lu, frame %lu, fifo %lu, missed %lu%s",
+          ifp->stats.rx_errors, ifp->stats.rx_length_errors,
+          ifp->stats.rx_over_errors, ifp->stats.rx_crc_errors,
+          ifp->stats.rx_frame_errors, ifp->stats.rx_fifo_errors,
+          ifp->stats.rx_missed_errors, VTY_NEWLINE);
+
+  vty_out (vty, "    output packets %lu, bytes %lu, dropped %lu%s",
+          ifp->stats.tx_packets, ifp->stats.tx_bytes,
+          ifp->stats.tx_dropped, VTY_NEWLINE);
+
+  vty_out (vty, "    output errors %lu, aborted %lu, carrier %lu,"
+          " fifo %lu, heartbeat %lu, window %lu%s",
+          ifp->stats.tx_errors, ifp->stats.tx_aborted_errors,
+          ifp->stats.tx_carrier_errors, ifp->stats.tx_fifo_errors,
+          ifp->stats.tx_heartbeat_errors, ifp->stats.tx_window_errors,
+          VTY_NEWLINE);
+
+  vty_out (vty, "    collisions %lu%s", ifp->stats.collisions, VTY_NEWLINE);
+#endif /* HAVE_PROC_NET_DEV */
+
+#ifdef HAVE_NET_RT_IFLIST
+#if defined (__bsdi__) || defined (__NetBSD__)
+  /* Statistics print out using sysctl (). */
+  vty_out (vty, "    input packets %qu, bytes %qu, dropped %qu,"
+          " multicast packets %qu%s",
+          ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes,
+          ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts,
+          VTY_NEWLINE);
+
+  vty_out (vty, "    input errors %qu%s",
+          ifp->stats.ifi_ierrors, VTY_NEWLINE);
+
+  vty_out (vty, "    output packets %qu, bytes %qu, multicast packets %qu%s",
+          ifp->stats.ifi_opackets, ifp->stats.ifi_obytes,
+          ifp->stats.ifi_omcasts, VTY_NEWLINE);
+
+  vty_out (vty, "    output errors %qu%s",
+          ifp->stats.ifi_oerrors, VTY_NEWLINE);
+
+  vty_out (vty, "    collisions %qu%s",
+          ifp->stats.ifi_collisions, VTY_NEWLINE);
+#else
+  /* Statistics print out using sysctl (). */
+  vty_out (vty, "    input packets %lu, bytes %lu, dropped %lu,"
+          " multicast packets %lu%s",
+          ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes,
+          ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts,
+          VTY_NEWLINE);
+
+  vty_out (vty, "    input errors %lu%s",
+          ifp->stats.ifi_ierrors, VTY_NEWLINE);
+
+  vty_out (vty, "    output packets %lu, bytes %lu, multicast packets %lu%s",
+          ifp->stats.ifi_opackets, ifp->stats.ifi_obytes,
+          ifp->stats.ifi_omcasts, VTY_NEWLINE);
+
+  vty_out (vty, "    output errors %lu%s",
+          ifp->stats.ifi_oerrors, VTY_NEWLINE);
+
+  vty_out (vty, "    collisions %lu%s",
+          ifp->stats.ifi_collisions, VTY_NEWLINE);
+#endif /* __bsdi__ || __NetBSD__ */
+#endif /* HAVE_NET_RT_IFLIST */
+}
+
+/* Check supported address family. */
+int
+if_supported_family (int family)
+{
+  if (family == AF_INET)
+    return 1;
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    return 1;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* Wrapper hook point for zebra daemon so that ifindex can be set 
+ * DEFUN macro not used as extract.pl HAS to ignore this
+ * See also interface_cmd in lib/if.c
+ */ 
+DEFUN_NOSH (zebra_interface,
+           zebra_interface_cmd,
+           "interface IFNAME",
+           "Select an interface to configure\n"
+           "Interface's name\n")
+{
+  int ret;
+  struct interface * ifp;
+  
+  /* Call lib interface() */
+  ret = interface_cmd.func (self, vty, argc, argv);
+
+  ifp = vty->index;  
+
+  /* Set ifindex 
+     this only happens if interface is NOT in kernel */
+  if (ifp->ifindex == 0)
+    {
+      ifp->ifindex = if_new_intern_ifindex ();
+      UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+    }
+
+  return ret;
+}
+
+DEFUN (no_zebra_interface,
+       no_zebra_interface_cmd,
+       "no interface IFNAME",
+       "Delete a pseudo interface's configuration\n"
+       "Interface's name\n")
+{
+  struct interface *ifp;
+  
+  ifp = if_lookup_by_name(argv[0]);
+  
+  if (ifp == NULL) 
+    {
+      vty_out (vty, "Inteface %s does not exist%s", 
+              argv[0],
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      vty_out(vty, "Only inactive interfaces can be deleted%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Delete interface */
+  if_delete(ifp);
+
+  return CMD_SUCCESS;
+} 
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+  1
+};
+
+/* Show all or specified interface to vty. */
+DEFUN (show_interface, show_interface_cmd,
+       "show interface [IFNAME]",  
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Inteface name\n")
+{
+  listnode node;
+  struct interface *ifp;
+  
+#ifdef HAVE_PROC_NET_DEV
+  /* If system has interface statistics via proc file system, update
+     statistics. */
+  ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+  ifstat_update_sysctl ();
+#endif /* HAVE_NET_RT_IFLIST */
+
+  /* Specified interface print. */
+  if (argc != 0)
+    {
+      ifp = if_lookup_by_name (argv[0]);
+      if (ifp == NULL) 
+       {
+         vty_out (vty, "%% Can't find interface %s%s", argv[0],
+                  VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      if_dump_vty (vty, ifp);
+      return CMD_SUCCESS;
+    }
+
+  /* All interface print. */
+  for (node = listhead (iflist); node; nextnode (node))
+    if_dump_vty (vty, getdata (node));
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (multicast,
+       multicast_cmd,
+       "multicast",
+       "Set multicast flag to interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_set_flags (ifp, IFF_MULTICAST);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't set multicast flag%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->multicast = IF_ZEBRA_MULTICAST_ON;
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_multicast,
+       no_multicast_cmd,
+       "no multicast",
+       NO_STR
+       "Unset multicast flag to interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_unset_flags (ifp, IFF_MULTICAST);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't unset multicast flag%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->multicast = IF_ZEBRA_MULTICAST_OFF;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (shutdown_if,
+       shutdown_if_cmd,
+       "shutdown",
+       "Shutdown the selected interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_unset_flags (ifp, IFF_UP);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_shutdown_if,
+       no_shutdown_if_cmd,
+       "no shutdown",
+       NO_STR
+       "Shutdown the selected interface\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *if_data;
+
+  ifp = (struct interface *) vty->index;
+  ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't up interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if_refresh (ifp);
+  if_data = ifp->info;
+  if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (bandwidth_if,
+       bandwidth_if_cmd,
+       "bandwidth <1-10000000>",
+       "Set bandwidth informational parameter\n"
+       "Bandwidth in kilobits\n")
+{
+  struct interface *ifp;   
+  unsigned int bandwidth;
+  
+  ifp = (struct interface *) vty->index;
+  bandwidth = strtol(argv[0], NULL, 10);
+
+  /* bandwidth range is <1-10000000> */
+  if (bandwidth < 1 || bandwidth > 10000000)
+    {
+      vty_out (vty, "Bandwidth is invalid%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  ifp->bandwidth = bandwidth;
+
+  /* force protocols to recalculate routes due to cost change */
+  if (if_is_up (ifp))
+    zebra_interface_up_update (ifp);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bandwidth_if,
+       no_bandwidth_if_cmd,
+       "no bandwidth",
+       NO_STR
+       "Set bandwidth informational parameter\n")
+{
+  struct interface *ifp;   
+  
+  ifp = (struct interface *) vty->index;
+
+  ifp->bandwidth = 0;
+  
+  /* force protocols to recalculate routes due to cost change */
+  if (if_is_up (ifp))
+    zebra_interface_up_update (ifp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_bandwidth_if,
+       no_bandwidth_if_val_cmd,
+       "no bandwidth <1-10000000>",
+       NO_STR
+       "Set bandwidth informational parameter\n"
+       "Bandwidth in kilobits\n")
+\f
+int
+ip_address_install (struct vty *vty, struct interface *ifp, char *addr_str,
+                   char *peer_str, char *label, int secondary)
+{
+  struct prefix_ipv4 cp;
+  struct connected *ifc;
+  struct prefix_ipv4 *p;
+  struct in_addr mask;
+  int ret;
+
+  ret = str2prefix_ipv4 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      ifc = connected_new ();
+      ifc->ifp = ifp;
+
+      /* Address. */
+      p = prefix_ipv4_new ();
+      *p = cp;
+      ifc->address = (struct prefix *) p;
+
+      /* Broadcast. */
+      if (p->prefixlen <= 30)
+       {
+         p = prefix_ipv4_new ();
+         *p = cp;
+         masklen2ip (p->prefixlen, &mask);
+         p->prefix.s_addr |= ~mask.s_addr;
+         ifc->destination = (struct prefix *) p;
+       }
+
+      /* Secondary. */
+      if (secondary)
+       SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+
+      /* Label. */
+      if (label)
+       ifc->label = strdup (label);
+
+      /* Add to linked list. */
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* This address is configured from zebra. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+  /* In case of this route need to install kernel. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      /* Some system need to up the interface to set IP address. */
+      if (! if_is_up (ifp))
+       {
+         if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+         if_refresh (ifp);
+       }
+
+      ret = if_set_prefix (ifp, ifc);
+      if (ret < 0)
+       {
+         vty_out (vty, "%% Can't set interface IP address: %s.%s", 
+                  strerror(errno), VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      /* IP address propery set. */
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      /* Update interface address information to protocol daemon. */
+      zebra_interface_address_add_update (ifp, ifc);
+
+      /* If interface is up register connected route. */
+      if (if_is_up(ifp))
+       connected_up_ipv4 (ifp, ifc);
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+ip_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str,
+                     char *peer_str, char *label, int secondry)
+{
+  struct prefix_ipv4 cp;
+  struct connected *ifc;
+  int ret;
+
+  /* Convert to prefix structure. */
+  ret = str2prefix_ipv4 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check current interface address. */
+  ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* This is not configured address. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    return CMD_WARNING;
+
+  /* This is not real address or interface is not active. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+      return CMD_WARNING;
+    }
+
+  /* This is real route. */
+  ret = if_unset_prefix (ifp, ifc);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Can't unset interface IP address: %s.%s", 
+              strerror(errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Redistribute this information. */
+  zebra_interface_address_delete_update (ifp, ifc);
+
+  /* Remove connected route. */
+  connected_down_ipv4 (ifp, ifc);
+
+  /* Free address information. */
+  listnode_delete (ifp->connected, ifc);
+  connected_free (ifc);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_address,
+       ip_address_cmd,
+       "ip address A.B.C.D/M",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n")
+{
+  return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+
+DEFUN (no_ip_address,
+       no_ip_address_cmd,
+       "no ip address A.B.C.D/M",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP Address (e.g. 10.0.0.1/8)")
+{
+  return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+
+#ifdef HAVE_NETLINK
+DEFUN (ip_address_secondary,
+       ip_address_secondary_cmd,
+       "ip address A.B.C.D/M secondary",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Secondary IP address\n")
+{
+  return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 1);
+}
+
+DEFUN (ip_address_label,
+       ip_address_label_cmd,
+       "ip address A.B.C.D/M label LINE",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Label of this address\n"
+       "Label\n")
+{
+  return ip_address_install (vty, vty->index, argv[0], NULL, argv[1], 1);
+}
+
+DEFUN (no_ip_address_secondary,
+       no_ip_address_secondary_cmd,
+       "no ip address A.B.C.D/M secondary",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Secondary IP address\n")
+{
+  return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 1);
+}
+
+DEFUN (no_ip_address_label,
+       no_ip_address_label_cmd,
+       "no ip address A.B.C.D/M label LINE",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IP address (e.g. 10.0.0.1/8)\n"
+       "Label of this address\n"
+       "Label\n")
+{
+  return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1], 1);
+}
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_IPV6
+int
+ipv6_address_install (struct vty *vty, struct interface *ifp, char *addr_str,
+                     char *peer_str, char *label, int secondary)
+{
+  struct prefix_ipv6 cp;
+  struct connected *ifc;
+  struct prefix_ipv6 *p;
+  int ret;
+
+  ret = str2prefix_ipv6 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      ifc = connected_new ();
+      ifc->ifp = ifp;
+
+      /* Address. */
+      p = prefix_ipv6_new ();
+      *p = cp;
+      ifc->address = (struct prefix *) p;
+
+      /* Secondary. */
+      if (secondary)
+       SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+
+      /* Label. */
+      if (label)
+       ifc->label = strdup (label);
+
+      /* Add to linked list. */
+      listnode_add (ifp->connected, ifc);
+    }
+
+  /* This address is configured from zebra. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+  /* In case of this route need to install kernel. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      /* Some system need to up the interface to set IP address. */
+      if (! if_is_up (ifp))
+       {
+         if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+         if_refresh (ifp);
+       }
+
+      ret = if_prefix_add_ipv6 (ifp, ifc);
+
+      if (ret < 0)
+       {
+         vty_out (vty, "%% Can't set interface IP address: %s.%s", 
+                  strerror(errno), VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      /* IP address propery set. */
+      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+      /* Update interface address information to protocol daemon. */
+      zebra_interface_address_add_update (ifp, ifc);
+
+      /* If interface is up register connected route. */
+      if (if_is_up(ifp))
+       connected_up_ipv6 (ifp, ifc);
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+ipv6_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str,
+                       char *peer_str, char *label, int secondry)
+{
+  struct prefix_ipv6 cp;
+  struct connected *ifc;
+  int ret;
+
+  /* Convert to prefix structure. */
+  ret = str2prefix_ipv6 (addr_str, &cp);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check current interface address. */
+  ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+  if (! ifc)
+    {
+      vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* This is not configured address. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+    return CMD_WARNING;
+
+  /* This is not real address or interface is not active. */
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+      || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+    {
+      listnode_delete (ifp->connected, ifc);
+      connected_free (ifc);
+      return CMD_WARNING;
+    }
+
+  /* This is real route. */
+  ret = if_prefix_delete_ipv6 (ifp, ifc);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Can't unset interface IP address: %s.%s", 
+              strerror(errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Redistribute this information. */
+  zebra_interface_address_delete_update (ifp, ifc);
+
+  /* Remove connected route. */
+  connected_down_ipv6 (ifp, ifc);
+
+  /* Free address information. */
+  listnode_delete (ifp->connected, ifc);
+  connected_free (ifc);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_address,
+       ipv6_address_cmd,
+       "ipv6 address X:X::X:X/M",
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IPv6 address (e.g. 3ffe:506::1/48)\n")
+{
+  return ipv6_address_install (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+
+DEFUN (no_ipv6_address,
+       no_ipv6_address_cmd,
+       "no ipv6 address X:X::X:X/M",
+       NO_STR
+       "Interface Internet Protocol config commands\n"
+       "Set the IP address of an interface\n"
+       "IPv6 address (e.g. 3ffe:506::1/48)\n")
+{
+  return ipv6_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0);
+}
+#endif /* HAVE_IPV6 */
+
+#ifdef KAME
+DEFUN (ip_tunnel,
+       ip_tunnel_cmd,
+       "ip tunnel IP_address IP_address",
+       "KAME ip tunneling configuration commands\n"
+       "Set FROM IP address and TO IP address\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_tunnel, no_ip_tunnel_cmd,
+       "no ip tunnel",
+       NO_STR
+       "Set FROM IP address and TO IP address\n")
+{
+  return CMD_SUCCESS;
+}
+#endif /* KAME */
+
+int
+if_config_write (struct vty *vty)
+{
+  listnode node;
+  struct interface *ifp;
+  char buf[BUFSIZ];
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      struct zebra_if *if_data;
+      listnode addrnode;
+      struct connected *ifc;
+      struct prefix *p;
+
+      ifp = getdata (node);
+      if_data = ifp->info;
+      
+      vty_out (vty, "interface %s%s", ifp->name,
+              VTY_NEWLINE);
+
+      if (ifp->desc)
+       vty_out (vty, " description %s%s", ifp->desc,
+                VTY_NEWLINE);
+
+      /* Assign bandwidth here to avoid unnecessary interface flap
+        while processing config script */
+      if (ifp->bandwidth != 0)
+       vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); 
+
+      for (addrnode = listhead (ifp->connected); addrnode; nextnode (addrnode))
+         {
+           ifc = getdata (addrnode);
+           if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+             {
+               p = ifc->address;
+               vty_out (vty, " ip%s address %s/%d",
+                        p->family == AF_INET ? "" : "v6",
+                        inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                        p->prefixlen);
+
+               if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
+                 vty_out (vty, " secondary");
+                 
+               if (ifc->label)
+                 vty_out (vty, " label %s", ifc->label);
+
+               vty_out (vty, "%s", VTY_NEWLINE);
+             }
+         }
+
+      if (if_data)
+       {
+         if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)
+           vty_out (vty, " shutdown%s", VTY_NEWLINE);
+
+         if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC)
+           vty_out (vty, " %smulticast%s",
+                    if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ",
+                    VTY_NEWLINE);
+       }
+
+#ifdef RTADV
+      rtadv_config_write (vty, ifp);
+#endif /* RTADV */
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+/* Allocate and initialize interface vector. */
+void
+zebra_if_init ()
+{
+  /* Initialize interface and new hook. */
+  if_init ();
+  if_add_hook (IF_NEW_HOOK, if_zebra_new_hook);
+  if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook);
+  
+  /* Install configuration write function. */
+  install_node (&interface_node, if_config_write);
+
+  install_element (VIEW_NODE, &show_interface_cmd);
+  install_element (ENABLE_NODE, &show_interface_cmd);
+  install_element (CONFIG_NODE, &zebra_interface_cmd);
+  install_element (CONFIG_NODE, &no_zebra_interface_cmd);
+  install_default (INTERFACE_NODE);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+  install_element (INTERFACE_NODE, &multicast_cmd);
+  install_element (INTERFACE_NODE, &no_multicast_cmd);
+  install_element (INTERFACE_NODE, &shutdown_if_cmd);
+  install_element (INTERFACE_NODE, &no_shutdown_if_cmd);
+  install_element (INTERFACE_NODE, &bandwidth_if_cmd);
+  install_element (INTERFACE_NODE, &no_bandwidth_if_cmd);
+  install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd);
+  install_element (INTERFACE_NODE, &ip_address_cmd);
+  install_element (INTERFACE_NODE, &no_ip_address_cmd);
+#ifdef HAVE_IPV6
+  install_element (INTERFACE_NODE, &ipv6_address_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_address_cmd);
+#endif /* HAVE_IPV6 */
+#ifdef KAME
+  install_element (INTERFACE_NODE, &ip_tunnel_cmd);
+  install_element (INTERFACE_NODE, &no_ip_tunnel_cmd);
+#endif /* KAME */
+#ifdef HAVE_NETLINK
+  install_element (INTERFACE_NODE, &ip_address_secondary_cmd);
+  install_element (INTERFACE_NODE, &ip_address_label_cmd);
+  install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd);
+  install_element (INTERFACE_NODE, &no_ip_address_label_cmd);
+#endif /* HAVE_NETLINK */
+}
diff --git a/zebra/interface.h b/zebra/interface.h
new file mode 100644 (file)
index 0000000..dbfa822
--- /dev/null
@@ -0,0 +1,180 @@
+/* Interface function header.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/* For interface multicast configuration. */
+#define IF_ZEBRA_MULTICAST_UNSPEC 0
+#define IF_ZEBRA_MULTICAST_ON     1
+#define IF_ZEBRA_MULTICAST_OFF    2
+
+/* For interface shutdown configuration. */
+#define IF_ZEBRA_SHUTDOWN_UNSPEC 0
+#define IF_ZEBRA_SHUTDOWN_ON     1
+#define IF_ZEBRA_SHUTDOWN_OFF    2
+
+/* Router advertisement feature. */
+#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME)
+#define RTADV
+#endif
+
+#ifdef RTADV
+/* Router advertisement parameter.  From RFC2461. */
+struct rtadvconf
+{
+  /* A flag indicating whether or not the router sends periodic Router
+     Advertisements and responds to Router Solicitations.
+     Default: FALSE */
+  int AdvSendAdvertisements;
+
+  /* The maximum time allowed between sending unsolicited multicast
+     Router Advertisements from the interface, in seconds.  MUST be no
+     less than 4 seconds and no greater than 1800 seconds. 
+
+     Default: 600 seconds */
+  int MaxRtrAdvInterval;
+#define RTADV_MAX_RTR_ADV_INTERVAL 600
+
+  /* The minimum time allowed between sending unsolicited multicast
+     Router Advertisements from the interface, in seconds.  MUST be no
+     less than 3 seconds and no greater than .75 * MaxRtrAdvInterval.
+
+     Default: 0.33 * MaxRtrAdvInterval */
+  int MinRtrAdvInterval;
+#define RTADV_MIN_RTR_ADV_INTERVAL (0.33 * RTADV_MAX_RTR_ADV_INTERVAL)
+
+  /* Unsolicited Router Advertisements' interval timer. */
+  int AdvIntervalTimer;
+
+  /* The TRUE/FALSE value to be placed in the "Managed address
+     configuration" flag field in the Router Advertisement.  See
+     [ADDRCONF].
+     Default: FALSE */
+  int AdvManagedFlag;
+
+
+  /* The TRUE/FALSE value to be placed in the "Other stateful
+     configuration" flag field in the Router Advertisement.  See
+     [ADDRCONF].
+
+     Default: FALSE */
+  int AdvOtherConfigFlag;
+
+  /* The value to be placed in MTU options sent by the router.  A
+     value of zero indicates that no MTU options are sent.
+
+     Default: 0 */
+  int AdvLinkMTU;
+
+
+  /* The value to be placed in the Reachable Time field in the Router
+     Advertisement messages sent by the router.  The value zero means
+     unspecified (by this router).  MUST be no greater than 3,600,000
+     milliseconds (1 hour).
+
+     Default: 0 */
+  u_int32_t AdvReachableTime;
+#define RTADV_MAX_REACHABLE_TIME 3600000
+
+
+  /* The value to be placed in the Retrans Timer field in the Router
+     Advertisement messages sent by the router.  The value zero means
+     unspecified (by this router).
+
+     Default: 0 */
+  int AdvRetransTimer;
+
+  /* The default value to be placed in the Cur Hop Limit field in the
+     Router Advertisement messages sent by the router.  The value
+     should be set to that current diameter of the Internet.  The
+     value zero means unspecified (by this router).
+
+     Default: The value specified in the "Assigned Numbers" RFC
+     [ASSIGNED] that was in effect at the time of implementation. */
+  int AdvCurHopLimit;
+
+  /* The value to be placed in the Router Lifetime field of Router
+     Advertisements sent from the interface, in seconds.  MUST be
+     either zero or between MaxRtrAdvInterval and 9000 seconds.  A
+     value of zero indicates that the router is not to be used as a
+     default router.
+
+     Default: 3 * MaxRtrAdvInterval */
+  int AdvDefaultLifetime;
+#define RTADV_ADV_DEFAULT_LIFETIME (3 * RTADV_MAX_RTR_ADV_INTERVAL)
+
+
+  /* A list of prefixes to be placed in Prefix Information options in
+     Router Advertisement messages sent from the interface.
+
+     Default: all prefixes that the router advertises via routing
+     protocols as being on-link for the interface from which the
+     advertisement is sent. The link-local prefix SHOULD NOT be
+     included in the list of advertised prefixes. */
+  list AdvPrefixList;
+};
+
+#endif /* RTADV */
+
+/* `zebra' daemon local interface structure. */
+struct zebra_if
+{
+  /* Shutdown configuration. */
+  u_char shutdown;
+
+  /* Multicast configuration. */
+  u_char multicast;
+
+  /* Router advertise configuration. */
+  u_char rtadv_enable;
+
+  /* Interface's address. */
+  list address;
+
+#ifdef RTADV
+  struct rtadvconf rtadv;
+#endif /* RTADV */
+};
+
+void if_delete_update (struct interface *ifp);
+void if_add_update (struct interface *ifp);
+void if_up (struct interface *);
+void if_down (struct interface *);
+void if_refresh (struct interface *);
+void zebra_interface_up_update (struct interface *ifp);
+void zebra_interface_down_update (struct interface *ifp);
+
+#ifdef HAVE_PROC_NET_DEV
+int ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+void ifstat_update_sysctl ();
+
+#endif /* HAVE_NET_RT_IFLIST */
+#ifdef HAVE_PROC_NET_DEV
+int interface_list_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_PROC_NET_IF_INET6
+int ifaddr_proc_ipv6 ();
+#endif /* HAVE_PROC_NET_IF_INET6 */
+
+#ifdef BSDI
+int if_kvm_get_mtu (struct interface *);
+#endif /* BSDI */
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
new file mode 100644 (file)
index 0000000..13afba2
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Common ioctl functions.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+
+/* clear and set interface name string */
+void
+ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
+{
+  strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
+}
+
+/* call ioctl system call */
+int
+if_ioctl (u_long request, caddr_t buffer)
+{
+  int sock;
+  int ret = 0;
+  int err = 0;
+
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  ret = ioctl (sock, request, buffer);
+  if (ret < 0)
+    {
+      err = errno;
+    }
+  close (sock);
+  
+  if (ret < 0) 
+    {
+      errno = err;
+      return ret;
+    }
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+if_ioctl_ipv6 (u_long request, caddr_t buffer)
+{
+  int sock;
+  int ret = 0;
+  int err = 0;
+
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  ret = ioctl (sock, request, buffer);
+  if (ret < 0)
+    {
+      err = errno;
+    }
+  close (sock);
+  
+  if (ret < 0) 
+    {
+      errno = err;
+      return ret;
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+/*
+ * get interface metric
+ *   -- if value is not avaliable set -1
+ */
+void
+if_get_metric (struct interface *ifp)
+{
+#ifdef SIOCGIFMETRIC
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) 
+    return;
+  ifp->metric = ifreq.ifr_metric;
+  if (ifp->metric == 0)
+    ifp->metric = 1;
+#else /* SIOCGIFMETRIC */
+  ifp->metric = -1;
+#endif /* SIOCGIFMETRIC */
+}
+
+/* get interface MTU */
+void
+if_get_mtu (struct interface *ifp)
+{
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+#if defined(SIOCGIFMTU)
+  if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) 
+    {
+      zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
+      ifp->mtu = -1;
+      return;
+    }
+
+#ifdef SUNOS_5
+  ifp->mtu = ifreq.ifr_metric;
+#else
+  ifp->mtu = ifreq.ifr_mtu;
+#endif /* SUNOS_5 */
+
+#else
+  zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
+  ifp->mtu = -1;
+#endif
+}
+
+#ifdef HAVE_NETLINK
+/* Interface address setting via netlink interface. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+  return kernel_address_add_ipv4 (ifp, ifc);
+}
+
+/* Interface address is removed using netlink interface. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+  return kernel_address_delete_ipv4 (ifp, ifc);
+}
+#else /* ! HAVE_NETLINK */
+#ifdef HAVE_IFALIASREQ
+/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
+   has ifaliasreq structure.  */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifaliasreq addreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in mask;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *) ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_addr = p->prefix;
+  addr.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in));
+  masklen2ip (p->prefixlen, &mask.sin_addr);
+  mask.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
+  
+  ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+
+/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
+   has ifaliasreq structure.  */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifaliasreq addreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in mask;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *)ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_addr = p->prefix;
+  addr.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in));
+  masklen2ip (p->prefixlen, &mask.sin_addr);
+  mask.sin_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin_len = sizeof (struct sockaddr_in);
+#endif
+  memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
+  
+  ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+#else
+/* Set up interface's address, netmask (and broadcas? ).  Linux or
+   Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifreq ifreq;
+  struct sockaddr_in addr;
+  struct sockaddr_in broad;
+  struct sockaddr_in mask;
+  struct prefix_ipv4 ifaddr;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *) ifc->address;
+
+  ifaddr = *p;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  addr.sin_addr = p->prefix;
+  addr.sin_family = p->family;
+  memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+  ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
+  if (ret < 0)
+    return ret;
+  
+  /* We need mask for make broadcast addr. */
+  masklen2ip (p->prefixlen, &mask.sin_addr);
+
+  if (if_is_broadcast (ifp))
+    {
+      apply_mask_ipv4 (&ifaddr);
+      addr.sin_addr = ifaddr.prefix;
+
+      broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
+      broad.sin_family = p->family;
+
+      memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
+      ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
+      if (ret < 0)
+       return ret;
+    }
+
+  mask.sin_family = p->family;
+#ifdef SUNOS_5
+  memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
+#else
+  memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS5 */
+  ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+/* Set up interface's address, netmask (and broadcas? ).  Linux or
+   Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct ifreq ifreq;
+  struct sockaddr_in addr;
+  struct prefix_ipv4 *p;
+
+  p = (struct prefix_ipv4 *) ifc->address;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_family = p->family;
+  memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+  ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+#endif /* HAVE_IFALIASREQ */
+#endif /* HAVE_NETLINK */
+
+/* get interface flags */
+void
+if_get_flags (struct interface *ifp)
+{
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
+  if (ret < 0) 
+    {
+      perror ("ioctl");
+      return;
+    }
+
+  ifp->flags = ifreq.ifr_flags & 0x0000ffff;
+}
+
+/* Set interface flags */
+int
+if_set_flags (struct interface *ifp, unsigned long flags)
+{
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ifreq.ifr_flags = ifp->flags;
+  ifreq.ifr_flags |= flags;
+
+  ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
+
+  if (ret < 0)
+    {
+      zlog_info ("can't set interface flags");
+      return ret;
+    }
+  return 0;
+}
+
+/* Unset interface's flag. */
+int
+if_unset_flags (struct interface *ifp, unsigned long flags)
+{
+  int ret;
+  struct ifreq ifreq;
+
+  ifreq_set_name (&ifreq, ifp);
+
+  ifreq.ifr_flags = ifp->flags;
+  ifreq.ifr_flags &= ~flags;
+
+  ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
+
+  if (ret < 0)
+    {
+      zlog_info ("can't unset interface flags");
+      return ret;
+    }
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+
+#ifdef LINUX_IPV6
+#ifndef _LINUX_IN6_H
+/* linux/include/net/ipv6.h */
+struct in6_ifreq 
+{
+  struct in6_addr ifr6_addr;
+  u_int32_t ifr6_prefixlen;
+  int ifr6_ifindex;
+};
+#endif /* _LINUX_IN6_H */
+
+/* Interface's address add/delete functions. */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct prefix_ipv6 *p;
+  struct in6_ifreq ifreq;
+
+  p = (struct prefix_ipv6 *) ifc->address;
+
+  memset (&ifreq, 0, sizeof (struct in6_ifreq));
+
+  memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
+  ifreq.ifr6_ifindex = ifp->ifindex;
+  ifreq.ifr6_prefixlen = p->prefixlen;
+
+  ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq);
+
+  return ret;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct prefix_ipv6 *p;
+  struct in6_ifreq ifreq;
+
+  p = (struct prefix_ipv6 *) ifc->address;
+
+  memset (&ifreq, 0, sizeof (struct in6_ifreq));
+
+  memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
+  ifreq.ifr6_ifindex = ifp->ifindex;
+  ifreq.ifr6_prefixlen = p->prefixlen;
+
+  ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq);
+
+  return ret;
+}
+#else /* LINUX_IPV6 */
+#ifdef HAVE_IN6_ALIASREQ
+#ifndef ND6_INFINITE_LIFETIME
+#define ND6_INFINITE_LIFETIME 0xffffffffL
+#endif /* ND6_INFINITE_LIFETIME */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct in6_aliasreq addreq;
+  struct sockaddr_in6 addr;
+  struct sockaddr_in6 mask;
+  struct prefix_ipv6 *p;
+
+  p = (struct prefix_ipv6 * ) ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_addr = p->prefix;
+  addr.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in6));
+  masklen2ip6 (p->prefixlen, &mask.sin6_addr);
+  mask.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
+  
+  addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
+  addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
+
+  ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  int ret;
+  struct in6_aliasreq addreq;
+  struct sockaddr_in6 addr;
+  struct sockaddr_in6 mask;
+  struct prefix_ipv6 *p;
+
+  p = (struct prefix_ipv6 *) ifc->address;
+
+  memset (&addreq, 0, sizeof addreq);
+  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
+
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_addr = p->prefix;
+  addr.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
+
+  memset (&mask, 0, sizeof (struct sockaddr_in6));
+  masklen2ip6 (p->prefixlen, &mask.sin6_addr);
+  mask.sin6_family = p->family;
+#ifdef HAVE_SIN_LEN
+  mask.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+  memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
+
+  addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
+  addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
+
+  ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
+  if (ret < 0)
+    return ret;
+  return 0;
+}
+#else
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  return 0;
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  return 0;
+}
+#endif /* HAVE_IN6_ALIASREQ */
+
+#endif /* LINUX_IPV6 */
+
+#endif /* HAVE_IPV6 */
diff --git a/zebra/ioctl.h b/zebra/ioctl.h
new file mode 100644 (file)
index 0000000..157fc44
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Common ioctl functions.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_IOCTL_H
+#define _ZEBRA_IOCTL_H
+
+/* Prototypes. */
+void ifreq_set_name (struct ifreq *, struct interface *);
+int if_ioctl (u_long, caddr_t);
+
+int if_set_flags (struct interface *, unsigned long);
+int if_unset_flags (struct interface *, unsigned long);
+void if_get_flags (struct interface *);
+
+int if_set_prefix (struct interface *, struct connected *);
+int if_unset_prefix (struct interface *, struct connected *);
+
+void if_get_metric (struct interface *);
+void if_get_mtu (struct interface *);
+
+#ifdef HAVE_IPV6
+int if_prefix_add_ipv6 (struct interface *, struct connected *);
+int if_prefix_delete_ipv6 (struct interface *, struct connected *);
+
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_IOCTL_H */
diff --git a/zebra/ipforward.h b/zebra/ipforward.h
new file mode 100644 (file)
index 0000000..a772337
--- /dev/null
@@ -0,0 +1,35 @@
+/* IP forward settings.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_IPFORWARD_H
+#define _ZEBRA_IPFORWARD_H
+
+int ipforward ();
+int ipforward_on ();
+int ipforward_off ();
+
+#ifdef HAVE_IPV6
+int ipforward_ipv6 ();
+int ipforward_ipv6_on ();
+int ipforward_ipv6_off ();
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_IPFORWARD_H */
diff --git a/zebra/ipforward_aix.c b/zebra/ipforward_aix.c
new file mode 100644 (file)
index 0000000..c79e7f1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * ipforward value get function for aix.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+int
+ipforward ()
+{
+  int fd, ret;
+  int af = AF_INET;
+  char netopt[] = "ipforwarding";
+  struct optreq oq;
+
+  fd = socket(af, SOCK_DGRAM, 0);
+  if (fd < 0) {
+    /* need logging here */
+    return -1;
+  }
+
+  strcpy (oq.name, netopt);
+  oq.getnext = 0;
+
+  ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq);
+  close(fd);
+
+  if (ret < 0) {
+    /* need logging here */
+    return -1;
+  }
+
+  ret = atoi (oq.data);
+  return ret;
+}
+
+int
+ipforward_on ()
+{
+  ;
+}
+
+int
+ipforward_off ()
+{
+  ;
+}
diff --git a/zebra/ipforward_ews.c b/zebra/ipforward_ews.c
new file mode 100644 (file)
index 0000000..c872000
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Ipforward value get function for NEC EWS.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+int
+ipforward ()
+{
+  int fd;
+  char buf[BUFSIZ];
+  struct mioc_rksym rks;
+
+  fd = open ("/dev/kmem", O_RDWR);
+  if (fd < 0) {
+    /* need logging here */
+    return -1;
+  }
+
+  rks.mirk_symname = "ipforwarding";
+  rks.mirk_buf = buf;
+  rks.mirk_buflen = sizeof (int);
+
+  if (ioctl (fd, MIOC_READKSYM, &rks) < 0) {
+    /* need logging here */
+    return -1;
+  }
+  close (fd);
+  return *(int *)buf;
+}
+
+int
+ipforward_on ()
+{
+  ;
+}
+
+int
+ipforward_off ()
+{
+  ;
+}
diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c
new file mode 100644 (file)
index 0000000..eb8cef0
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Fetch ipforward value by reading /proc filesystem.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+char proc_net_snmp[] = "/proc/net/snmp";
+
+static void
+dropline (FILE *fp)
+{
+  int c;
+
+  while ((c = getc (fp)) != '\n')
+    ;
+}
+
+int
+ipforward ()
+{
+  FILE *fp;
+  int ipforwarding = 0;
+  char *pnt;
+  char buf[10];
+
+  fp = fopen (proc_net_snmp, "r");
+
+  if (fp == NULL)
+    return -1;
+
+  /* We don't care about the first line. */
+  dropline (fp);
+  
+  /* Get ip_statistics.IpForwarding : 
+     1 => ip forwarding enabled 
+     2 => ip forwarding off. */
+  pnt = fgets (buf, 6, fp);
+  sscanf (buf, "Ip: %d", &ipforwarding);
+
+  if (ipforwarding == 1)
+    return 1;
+
+  return 0;
+}
+
+/* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */
+char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward";
+
+int
+ipforward_on ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv4_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "1\n");
+
+  fclose (fp);
+
+  return ipforward ();
+}
+
+int
+ipforward_off ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv4_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "0\n");
+
+  fclose (fp);
+
+  return ipforward ();
+}
+#ifdef HAVE_IPV6
+
+char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding";
+
+int
+ipforward_ipv6 ()
+{
+  FILE *fp;
+  char buf[5];
+  int ipforwarding = 0;
+
+  fp = fopen (proc_ipv6_forwarding, "r");
+
+  if (fp == NULL)
+    return -1;
+
+  fgets (buf, 2, fp);
+  sscanf (buf, "%d", &ipforwarding);
+
+  return ipforwarding;
+}
+
+int
+ipforward_ipv6_on ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv6_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "1\n");
+
+  fclose (fp);
+
+  return ipforward_ipv6 ();
+}
+
+int
+ipforward_ipv6_off ()
+{
+  FILE *fp;
+
+  fp = fopen (proc_ipv6_forwarding, "w");
+  
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "0\n");
+
+  fclose (fp);
+
+  return ipforward_ipv6 ();
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c
new file mode 100644 (file)
index 0000000..99b0e1a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * ipforward value get function for solaris.
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+
+int
+ipforward ()
+{
+  int fd, ret;
+  int ipforwarding = 0;
+  char forward[] = "ip_forwarding";
+  char *buf;
+  struct strioctl si;
+
+  buf = (char *) XMALLOC (MTYPE_TMP, sizeof forward + 1);
+  strcpy (buf, forward);
+
+  fd = open ("/dev/ip", O_RDWR);
+  if (fd < 0) {
+    free (buf);
+    /* need logging here */
+    /* "I can't get ipforwarding value because can't open /dev/ip" */
+    return -1;
+  }
+
+  si.ic_cmd = ND_GET;
+  si.ic_timout = 0;
+  si.ic_len = strlen (buf) + 1;
+  si.ic_dp = (caddr_t) buf;
+
+  ret = ioctl (fd, I_STR, &si);
+  close (fd);
+
+  if (ret < 0) {
+    free (buf);
+    /* need logging here */
+    /* can't get ipforwarding value : ioctl failed */
+    return -1;
+  }
+
+  ipforwarding = atoi (buf);
+  free (buf);
+  return ipforwarding;
+}
+
+int
+ipforward_on ()
+{
+  return 0;
+}
+
+int
+ipforward_off ()
+{
+  return 0;
+}
diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c
new file mode 100644 (file)
index 0000000..828eb86
--- /dev/null
@@ -0,0 +1,146 @@
+/* IP forward control by sysctl function.
+ * Copyright (C) 1997, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#ifdef NRL
+#include <netinet6/in6.h>
+#endif /* NRL */
+
+#include "log.h"
+
+#define MIB_SIZ 4
+
+/* IPv4 forwarding control MIB. */
+int mib[MIB_SIZ] =
+{
+  CTL_NET,
+  PF_INET,
+  IPPROTO_IP,
+  IPCTL_FORWARDING
+};
+
+int
+ipforward ()
+{
+  int len;
+  int ipforwarding = 0;
+
+  len = sizeof ipforwarding;
+  if (sysctl (mib, MIB_SIZ, &ipforwarding, &len, 0, 0) < 0) 
+    {
+      zlog_warn ("Can't get ipforwarding value");
+      return -1;
+    }
+  return ipforwarding;
+}
+
+int
+ipforward_on ()
+{
+  int len;
+  int ipforwarding = 1;
+
+  len = sizeof ipforwarding;
+  if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) 
+    {
+      zlog_warn ("Can't set ipforwarding on");
+      return -1;
+    }
+  return ipforwarding;
+}
+
+int
+ipforward_off ()
+{
+  int len;
+  int ipforwarding = 0;
+
+  len = sizeof ipforwarding;
+  if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) 
+    {
+      zlog_warn ("Can't set ipforwarding on");
+      return -1;
+    }
+  return ipforwarding;
+}
+
+#ifdef HAVE_IPV6
+
+/* IPv6 forwarding control MIB. */
+int mib_ipv6[MIB_SIZ] = 
+{
+  CTL_NET,
+  PF_INET6,
+#if defined(KAME) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL)
+  IPPROTO_IPV6,
+  IPV6CTL_FORWARDING
+#else /* NOT KAME */
+  IPPROTO_IP,
+  IP6CTL_FORWARDING
+#endif /* KAME */
+}; 
+
+int
+ipforward_ipv6 ()
+{
+  int len;
+  int ip6forwarding = 0;
+
+  len = sizeof ip6forwarding;
+  if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) 
+    {
+      zlog_warn ("can't get ip6forwarding value");
+      return -1;
+    }
+  return ip6forwarding;
+}
+
+int
+ipforward_ipv6_on ()
+{
+  int len;
+  int ip6forwarding = 1;
+
+  len = sizeof ip6forwarding;
+  if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) 
+    {
+      zlog_warn ("can't get ip6forwarding value");
+      return -1;
+    }
+  return ip6forwarding;
+}
+
+int
+ipforward_ipv6_off ()
+{
+  int len;
+  int ip6forwarding = 0;
+
+  len = sizeof ip6forwarding;
+  if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) 
+    {
+      zlog_warn ("can't get ip6forwarding value");
+      return -1;
+    }
+  return ip6forwarding;
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/irdp.c b/zebra/irdp.c
new file mode 100644 (file)
index 0000000..1b3bf23
--- /dev/null
@@ -0,0 +1,569 @@
+/* ICMP Router Discovery Messages
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include <netinet/ip_icmp.h>
+
+#include "if.h"
+#include "stream.h"
+#include "memory.h"
+#include "command.h"
+#include "log.h"
+#include "sockunion.h"
+#include "sockopt.h"
+
+#include "zebra/irdp.h"
+
+/* Default does nothing. */
+int irdp_mode = IRDP_NONE;
+
+/* Timer interval of irdp. */
+int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
+
+/* Max solicitations */
+int max_solicitations = MAX_SOLICITATIONS;
+
+#define IRDP_SOLICIT_PACKET_SIZE 8
+
+static struct irdp *irdp_head = NULL;
+
+extern int in_cksum (void *ptr, int nbytes);
+
+char *icmp_type_str[] = 
+{
+  "Echo Reply",
+  "ICMP 1",
+  "ICMP 2",
+  "Dest Unreachable",
+  "Source Quench",
+  "Redirect",
+  "ICMP 6",
+  "ICMP 7",
+  "Echo",
+  "Router Advertise",
+  "Router Solicitation",
+  "Time Exceeded",
+  "Parameter Problem",
+  "Timestamp",
+  "Timestamp Reply",
+  "Info Request",
+  "Info Reply",
+  "Netmask Request",
+  "Netmask Reply",
+};
+
+char *
+icmp_type (int type)
+{
+  if (type < 0 || type >= (sizeof icmp_type_str / sizeof (char *))) {
+    return "OUT-OF-RANGE";
+  }
+  return icmp_type_str [type];
+}
+
+/* */
+void
+irdp_add_interface ()
+{
+  ;
+}
+
+/* */
+void
+irdp_delete_interface ()
+{
+
+}
+
+struct irdp *
+irdp_route_new ()
+{
+  struct irdp *new = XMALLOC (0, sizeof (struct irdp));
+  memset (new, 0, sizeof (struct irdp));
+  return new;
+}
+
+void
+irdp_route_free (struct irdp *route)
+{
+  XFREE (0, route);
+}
+
+void
+route_delete ()
+{
+
+}
+
+void
+route_init ()
+{
+  
+}
+
+void
+route_add (struct in_addr addr, unsigned long pref)
+{
+  struct irdp *new = irdp_route_new();
+  
+  new->prefix = addr;
+  new->pref = pref;
+
+  printf ("address %s\n", inet_ntoa (new->prefix));
+  printf ("pref %ld\n", new->pref);
+}
+
+void
+route_age (int time)
+{
+  struct irdp *p;
+
+  for (p = irdp_head; p != NULL; p = p->next) {
+    if (p->timer < time) {
+      /* fire */
+    } else {
+      p->timer -= time;
+    }
+  }
+}
+
+#define FLAG_TEST(a)  ((ifp->flags & (a)) == (a))
+
+void
+send_multicast (struct interface *ifp, int sock, struct stream *s, int size)
+{
+  struct sockaddr_in sin;
+  struct in_addr addr;
+  int nbytes;
+  struct connected *connected;
+  listnode node;
+  
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      connected = getdata (node);
+    }
+
+  if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
+                 addr, 0, ifp->ifindex) < 0) 
+    {
+      perror ("setsockopt");
+      exit (1);
+    }
+
+  sin.sin_addr.s_addr = htonl (INADDR_ALLRTRS_GROUP);
+  sin.sin_family = AF_INET;
+
+  nbytes = sendto (sock, s->data, size, 0,
+                  (struct sockaddr *) &sin, sizeof (struct sockaddr));
+
+  if (nbytes != size) 
+    {
+      perror ("sendto");
+      exit (1);
+    }
+}
+
+void
+send_broadcast ()
+{
+  struct sockaddr_in sin;
+
+  printf ("broadcast\n");
+  inet_aton ("255.255.255.255", &sin.sin_addr);
+}
+
+void
+irdp_send_solicit (int sock, struct stream *s, int size)
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (FLAG_TEST (IFF_UP | IFF_MULTICAST)) 
+       {
+         send_multicast (ifp, sock, s, size);
+       }
+      else if (FLAG_TEST (IFF_UP | IFF_BROADCAST)) 
+       {
+         send_broadcast ();
+       }
+    }
+}
+
+int
+ipv4_multicast_join (int sock, 
+                    struct in_addr group, 
+                    struct in_addr ifa,
+                    unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (sock, IP_ADD_MEMBERSHIP, 
+                   ifa, group.saddr, ifindex);
+
+  if (ret < 0) 
+    zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP");
+
+  return ret;
+}
+
+/* multicast packet recieve socket */
+int
+irdp_multicast_socket (int sock, struct in_addr group)
+{
+  struct interface *ifp;
+  listnode node;
+  struct in_addr addr;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if ((ifp->flags & IFF_UP) && (ifp->flags & IFF_MULTICAST)) 
+       {
+         ipv4_multicast_join (sock, group, addr, ifp->ifindex);
+       }
+    }
+  return 0;
+}
+
+struct 
+{
+  u_char type;
+  u_char code;
+  u_int16_t checksum;
+  u_char number;
+  u_char entry;
+  u_int16_t lifetime;
+} radv;
+
+void
+irdp_set (int sock)
+{
+  struct in_addr irdp_group;
+
+  switch (irdp_mode) 
+    {
+    case IRDP_HOST:
+      irdp_group.s_addr = htonl (INADDR_ALLHOSTS_GROUP);
+      break;
+    case IRDP_ROUTER:
+      irdp_group.s_addr = htonl (INADDR_ALLRTRS_GROUP);
+      break;
+    case IRDP_NONE:
+    default:
+      return;
+    }
+  irdp_multicast_socket (sock, irdp_group);
+}
+
+/* Make ICMP Router Solicitation Message. */
+int
+make_solicit_packet (struct stream *s)
+{
+  int size;
+  int checksum;
+
+  stream_putc (s, ICMP_ROUTERSOLICIT); /* Type. */
+  stream_putc (s, 0);          /* Code. */
+  stream_putw (s, 0);          /* Checksum. */
+  stream_putl (s, 0);          /* Reserved. */
+
+  /* in_cksum return network byte order value */
+  size = IRDP_SOLICIT_PACKET_SIZE;
+  checksum = in_cksum (s->data, size);
+  stream_putw_at (s, checksum, 2);
+
+  return IRDP_SOLICIT_PACKET_SIZE;
+}
+
+void
+irdp_solicit (int sock)
+{
+  struct stream *s;
+
+  s = stream_new (IRDP_SOLICIT_PACKET_SIZE);
+  make_solicit_packet (s);
+  irdp_send_solicit (sock, s, IRDP_SOLICIT_PACKET_SIZE);
+}
+
+#define ICMP_MINLEN 8
+
+/* check validity of the packet */
+int
+irdp_valid_check (char *packet, size_t size, struct sockaddr_in *from)
+{
+  struct icmp *icmp;
+
+  icmp = (struct icmp *) packet;
+
+  if (in_cksum (packet, size)) {
+    zlog_warn ("ICMP %s packet from %s: Bad checksum, silently ignored",
+              icmp_type (icmp->icmp_type),
+              inet_ntoa (from->sin_addr));
+    return -1;
+  }
+
+  if (icmp->icmp_code != 0) {
+    zlog_warn ("ICMP %s packet from %s: Bad ICMP type code, silently ignored",
+              icmp_type (icmp->icmp_type),
+              inet_ntoa (from->sin_addr));
+    return -1;
+  }
+
+  if (size < ICMP_MINLEN) {
+    zlog_warn ("ICMP %s packet from %s: IMCP message length is short",
+              icmp_type (icmp->icmp_type),
+              inet_ntoa (from->sin_addr));
+    return -1;
+  }
+  return 0;
+}
+
+int
+irdp_solicit_recv (struct stream *s, int size, struct sockaddr_in *from)
+{
+  if (irdp_valid_check (s->data, size, from)) {
+    return 1;
+  }
+  return 0;
+}
+
+void
+irdp_advert_recv (struct stream *s, int size, struct sockaddr_in *from)
+{
+  int i;
+  struct in_addr addr;
+  long pref;
+
+  if (irdp_valid_check (s->data, size, from) < 0) {
+    return;
+  }
+
+  radv.type = stream_getc (s);
+  radv.code =  stream_getc (s);
+  radv.checksum = stream_getw (s);
+  radv.number = stream_getc (s);
+  radv.entry = stream_getc (s);
+  radv.lifetime = stream_getw (s);
+
+  printf ("type : %s\n", icmp_type (radv.type));
+  printf ("number: %d\n", radv.number);
+  printf ("entry: %d\n", radv.entry);
+  printf ("lifetime: %d\n", radv.entry);
+
+  for (i = 0; i < radv.number; i++) 
+    {
+      addr.s_addr = stream_getl (s);
+      pref = stream_getl (s);
+      route_add (addr, ntohl (pref));
+    }
+  /* Packet size check is needed at here. */
+}
+
+void
+irdp_packet_process (char *buf, int size, struct sockaddr_in *from)
+{
+  struct ip *ip;
+  struct icmp *icmp;
+  int hlen;
+  struct stream *s = NULL;
+
+  ip = (struct ip *)buf;
+  hlen = ip->ip_hl << 2;
+
+  if (size < hlen + ICMP_MINLEN)
+    zlog_err ("ICMP relpy length is short\n");
+
+  icmp = (struct icmp *)(buf + hlen);
+
+  stream_forward (s, hlen);
+  
+  switch (icmp->icmp_type) 
+    {
+    case ICMP_ROUTERADVERT:
+      irdp_advert_recv (s, size - hlen, from);
+      break;
+    case ICMP_ROUTERSOLICIT:
+      irdp_solicit_recv (s, size - hlen, from);
+      break;
+    }
+}
+
+/* Make socket for ICMP Router Discovery. */
+int
+irdp_make_socket ()
+{
+  int sock;
+  struct protoent *pent;
+
+  if ((pent = getprotobyname ("icmp")) == NULL) {
+    perror ("getprotobyname");
+    exit (1);
+  }
+
+  if ((sock = socket (AF_INET, SOCK_RAW, pent->p_proto)) < 0) 
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  return sock;
+}
+
+/* recv routine */
+int
+irdp_recv (int sock)
+{
+#define PACKET_BUF 4096
+  int nbytes;
+  struct sockaddr_in from;
+  int fromlen;
+  char buf[PACKET_BUF];
+
+  fromlen = sizeof (from);
+  nbytes = recvfrom (sock, (char *)buf, PACKET_BUF, 0,
+                    (struct sockaddr *)&from, &fromlen);
+
+  if (nbytes < 0) 
+    {
+      perror ("recvfrom");
+      exit (1);
+    }
+
+  irdp_packet_process (buf, nbytes, &from);
+
+  return 0;
+}
+
+/* irdp packet recv loop */
+void
+irdp_loop (int sock)
+{
+  while (1) 
+    {
+      irdp_recv (sock);
+    }
+}
+\f
+DEFUN (ip_irdp,
+       ip_irdp_cmd,
+       "ip irdp",
+       IP_STR
+       "ICMP Router discovery on this interface\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_multicast,
+       ip_irdp_multicast_cmd,
+       "ip irdp multicast",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Send IRDP advertisement to the multicast address\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_holdtime,
+       ip_irdp_holdtime_cmd,
+       "ip irdp holdtime <0-9000>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set holdtime value\n"
+       "Holdtime value in seconds. Default is 1800 seconds\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_maxadvertinterval,
+       ip_irdp_maxadvertinterval_cmd,
+       "ip irdp maxadvertinterval (0|<4-1800>)",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set maximum time between advertisement\n"
+       "Maximum advertisement interval in seconds\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_minadvertinterval,
+       ip_irdp_minadvertinterval_cmd,
+       "ip irdp minadvertinterval <3-1800>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set minimum time between advertisement\n"
+       "Minimum advertisement interval in seconds\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_irdp_preference,
+       ip_irdp_preference_cmd,
+       /* "ip irdp preference <-2147483648-2147483647>", */
+       "ip irdp preference <0-2147483647>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Set default preference level for this interface\n"
+       "Preference level\n")
+{
+  return CMD_SUCCESS;
+}
+
+#if 0
+DEFUN (ip_irdp_address,
+       ip_irdp_address_cmd,
+       "ip irdp address A.B.C.D",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Specify IRDP address and preference to proxy-advertise\n"
+       "Set IRDP address for proxy-advertise\n")
+{
+  return CMD_SUCCESS;
+}
+#endif /* 0 */
+
+DEFUN (ip_irdp_address_preference,
+       ip_irdp_address_preference_cmd,
+       "ip irdp address A.B.C.D <0-2147483647>",
+       IP_STR
+       "ICMP Router discovery on this interface\n"
+       "Specify IRDP address and preference to proxy-advertise\n"
+       "Set IRDP address for proxy-advertise\n"
+       "Preference level\n")
+{
+  return CMD_SUCCESS;
+}
+\f
+void
+irdp_init ()
+{
+  install_element (INTERFACE_NODE, &ip_irdp_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_preference_cmd);
+  install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd);
+}
diff --git a/zebra/irdp.h b/zebra/irdp.h
new file mode 100644 (file)
index 0000000..0fad581
--- /dev/null
@@ -0,0 +1,148 @@
+/* ICMP Router Discovery Messages
+ * Copyright (C) 1997, 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/* ICMP Messages */
+#ifndef ICMP_ROUTERADVERT
+#define ICMP_ROUTERADVERT 9
+#endif /* ICMP_ROUTERADVERT */
+
+#ifndef ICMP_ROUTERSOLICIT
+#define ICMP_ROUTERSOLICIT 10
+#endif /* ICMP_ROUTERSOLICT */
+
+/* Multicast groups */
+#ifndef INADDR_ALLHOSTS_GROUP
+#define INADDR_ALLHOSTS_GROUP 0xe0000001    /* 224.0.0.1 */
+#endif /* INADDR_ALLHOSTS_GROUP */
+
+#ifndef INADDR_ALLRTRS_GROUP
+#define INADDR_ALLRTRS_GROUP  0xe0000002    /* 224.0.0.2 */
+#endif /* INADDR_ALLRTRS_GROUP */
+
+/* Comments comes from RFC1256 ICMP Router Discovery Messages. */
+struct irdp_router_interface 
+{
+  /* The IP destination address to be used for multicast Router
+     Advertisements sent from the interface.  The only permissible
+     values are the all-systems multicast address, 224.0.0.1, or the
+     limited-broadcast address, 255.255.255.255.  (The all-systems
+     address is preferred wherever possible, i.e., on any link where
+     all listening hosts support IP multicast.)
+
+     Default: 224.0.0.1 if the router supports IP multicast on the
+     interface, else 255.255.255.255 */
+
+  struct in_addr AdvertisementAddress;
+
+  /* The maximum time allowed between sending multicast Router
+     Advertisements from the interface, in seconds.  Must be no less
+     than 4 seconds and no greater than 1800 seconds.
+
+     Default: 600 seconds */
+
+  unsigned long MaxAdvertisementInterval;
+
+  /* The minimum time allowed between sending unsolicited multicast
+     Router Advertisements from the interface, in seconds.  Must be no
+     less than 3 seconds and no greater than MaxAdvertisementInterval.
+
+     Default: 0.75 * MaxAdvertisementInterval */
+
+  unsigned long MinAdvertisementInterval;
+
+
+  /* The value to be placed in the Lifetime field of Router
+     Advertisements sent from the interface, in seconds.  Must be no
+     less than MaxAdvertisementInterval and no greater than 9000
+     seconds.
+
+     Default: 3 * MaxAdvertisementInterval */
+
+  unsigned long AdvertisementLifetime;
+
+  /* A flag indicating whether or not the address is to be advertised.
+
+     Default: TRUE */
+
+  int Advertise;
+
+
+  /* The preferability of the address as a default router address,
+     relative to other router addresses on the same subnet.  A 32-bit,
+     signed, twos-complement integer, with higher values meaning more
+     preferable.  The minimum value (hex 80000000) is used to indicate
+     that the address, even though it may be advertised, is not to be
+     used by neighboring hosts as a default router address.
+
+     Default: 0 */
+
+  unsigned long PreferenceLevel;
+};
+
+struct irdp_host_interface 
+{
+  /* A flag indicating whether or not the host is to perform ICMP router
+     discovery on the interface. */
+  int PerformRouerDiscovery;
+  
+  /* The IP destination address to be used for sending Router
+     Solicitations from the interface.  The only permissible values
+     are the all-routers multicast address, 224.0.0.2, or the
+     limited-broadcast address, 255.255.255.255.  (The all-routers
+     address is preferred wherever possible, i.e., on any link where
+     all advertising routers support IP multicast.)  */
+  unsigned long SolicitationAddress;
+};
+
+
+/* Route preference structure */
+struct irdp 
+{
+  struct in_addr prefix;
+  long pref;           /* preference level */
+  long timer;                  /* lifetime timer */
+
+  struct irdp *next;           /* doubly linked list */
+  struct irdp *prev;           /* doubly linked list */
+};
+
+/* Default irdp packet interval */
+#define IRDP_DEFAULT_INTERVAL 300
+
+/* Router constants from RFC1256 */
+#define MAX_INITIAL_ADVERT_INTERVAL 16
+#define MAX_INITIAL_ADVERTISEMENTS   3
+#define MAX_RESPONSE_DELAY           2
+
+/* Host constants from RFC1256 */
+#define MAX_SOLICITATION_DELAY       1
+#define SOLICITATION_INTERVAL        3
+#define MAX_SOLICITATIONS            3
+
+enum
+{
+  IRDP_NONE,
+  IRDP_ROUTER,
+  IRDP_HOST,
+};
+
+/* default is host mode */
+extern int irdp_mode;
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
new file mode 100644 (file)
index 0000000..23b2153
--- /dev/null
@@ -0,0 +1,20 @@
+/* Kernel communication using netlink interface.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
new file mode 100644 (file)
index 0000000..a47f4f6
--- /dev/null
@@ -0,0 +1,811 @@
+/* Kernel communication using routing socket.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "sockunion.h"
+#include "connected.h"
+#include "memory.h"
+#include "ioctl.h"
+#include "log.h"
+#include "str.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/interface.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+
+/* Socket length roundup function. */
+#define ROUNDUP(a) \
+  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+/* And this macro is wrapper for handling sa_len. */
+#ifdef HAVE_SA_LEN
+#define WRAPUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
+#else
+#define WRAPUP(X)   ROUNDUP(sizeof (struct sockaddr))
+#endif /* HAVE_SA_LEN */
+
+/* Routing socket message types. */
+struct message rtm_type_str[] =
+{
+  {RTM_ADD,      "RTM_ADD"},
+  {RTM_DELETE,   "RTM_DELETE"},
+  {RTM_CHANGE,   "RTM_CHANGE"},
+  {RTM_GET,      "RTM_GET"},
+  {RTM_LOSING,   "RTM_LOSING"},
+  {RTM_REDIRECT, "RTM_REDIRECT"},
+  {RTM_MISS,     "RTM_MISS"},
+  {RTM_LOCK,     "RTM_LOCK"},
+  {RTM_OLDADD,   "RTM_OLDADD"},
+  {RTM_OLDDEL,   "RTM_OLDDEL"},
+  {RTM_RESOLVE,  "RTM_RESOLVE"},
+  {RTM_NEWADDR,  "RTM_NEWADDR"},
+  {RTM_DELADDR,  "RTM_DELADDR"},
+  {RTM_IFINFO,   "RTM_IFINFO"},
+#ifdef RTM_OIFINFO
+  {RTM_OIFINFO,   "RTM_OIFINFO"},
+#endif /* RTM_OIFINFO */
+#ifdef RTM_NEWMADDR
+  {RTM_NEWMADDR, "RTM_NEWMADDR"},
+#endif /* RTM_NEWMADDR */
+#ifdef RTM_DELMADDR
+  {RTM_DELMADDR, "RTM_DELMADDR"},
+#endif /* RTM_DELMADDR */
+#ifdef RTM_IFANNOUNCE
+  {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},
+#endif /* RTM_IFANNOUNCE */
+  {0,            NULL}
+};
+
+struct message rtm_flag_str[] =
+{
+  {RTF_UP,        "UP"},
+  {RTF_GATEWAY,   "GATEWAY"},
+  {RTF_HOST,      "HOST"},
+  {RTF_REJECT,    "REJECT"},
+  {RTF_DYNAMIC,   "DYNAMIC"},
+  {RTF_MODIFIED,  "MODIFIED"},
+  {RTF_DONE,      "DONE"},
+#ifdef RTF_MASK
+  {RTF_MASK,      "MASK"},
+#endif /* RTF_MASK */
+  {RTF_CLONING,   "CLONING"},
+  {RTF_XRESOLVE,  "XRESOLVE"},
+  {RTF_LLINFO,    "LLINFO"},
+  {RTF_STATIC,    "STATIC"},
+  {RTF_BLACKHOLE, "BLACKHOLE"},
+  {RTF_PROTO1,    "PROTO1"},
+  {RTF_PROTO2,    "PROTO2"},
+#ifdef RTF_PRCLONING
+  {RTF_PRCLONING, "PRCLONING"},
+#endif /* RTF_PRCLONING */
+#ifdef RTF_WASCLONED
+  {RTF_WASCLONED, "WASCLONED"},
+#endif /* RTF_WASCLONED */
+#ifdef RTF_PROTO3
+  {RTF_PROTO3,    "PROTO3"},
+#endif /* RTF_PROTO3 */
+#ifdef RTF_PINNED
+  {RTF_PINNED,    "PINNED"},
+#endif /* RTF_PINNED */
+#ifdef RTF_LOCAL
+  {RTF_LOCAL,    "LOCAL"},
+#endif /* RTF_LOCAL */
+#ifdef RTF_BROADCAST
+  {RTF_BROADCAST, "BROADCAST"},
+#endif /* RTF_BROADCAST */
+#ifdef RTF_MULTICAST
+  {RTF_MULTICAST, "MULTICAST"},
+#endif /* RTF_MULTICAST */
+  {0,             NULL}
+};
+
+/* Kernel routing update socket. */
+int routing_sock = -1;
+
+/* Yes I'm checking ugly routing socket behavior. */
+/* #define DEBUG */
+
+/* Supported address family check. */
+static int
+af_check (int family)
+{
+  if (family == AF_INET)
+    return 1;
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    return 1;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+\f
+/* Dump routing table flag for debug purpose. */
+void
+rtm_flag_dump (int flag)
+{
+  struct message *mes;
+  static char buf[BUFSIZ];
+
+  for (mes = rtm_flag_str; mes->key != 0; mes++)
+    {
+      if (mes->key & flag)
+       {
+         strlcat (buf, mes->str, BUFSIZ);
+         strlcat (buf, " ", BUFSIZ);
+       }
+    }
+  zlog_info ("Kernel: %s", buf);
+}
+
+#ifdef RTM_IFANNOUNCE
+/* Interface adding function */
+int
+ifan_read (struct if_announcemsghdr *ifan)
+{
+  struct interface *ifp;
+
+  ifp = if_lookup_by_index (ifan->ifan_index);
+  if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
+    {
+      /* Create Interface */
+      ifp = if_get_by_name (ifan->ifan_name);
+      ifp->ifindex = ifan->ifan_index;
+
+      if_add_update (ifp);
+    }
+  else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
+    {
+      if_delete_update (ifp);
+      if_delete (ifp);
+    }
+
+  if_get_flags (ifp);
+  if_get_mtu (ifp);
+  if_get_metric (ifp);
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
+
+  return 0;
+}
+#endif /* RTM_IFANNOUNCE */
+
+/* Interface adding function called from interface_list. */
+int
+ifm_read (struct if_msghdr *ifm)
+{
+  struct interface *ifp;
+  struct sockaddr_dl *sdl = NULL;
+
+  sdl = (struct sockaddr_dl *)(ifm + 1);
+
+  /* Use sdl index. */
+  ifp = if_lookup_by_index (ifm->ifm_index);
+
+  if (ifp == NULL)
+    {
+      /* Check interface's address.*/
+      if (! (ifm->ifm_addrs & RTA_IFP))
+       {
+         zlog_warn ("There must be RTA_IFP address for ifindex %d\n",
+                    ifm->ifm_index);
+         return -1;
+       }
+
+      ifp = if_create ();
+
+      strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen);
+      ifp->ifindex = ifm->ifm_index;
+      ifp->flags = ifm->ifm_flags;
+#if defined(__bsdi__)
+      if_kvm_get_mtu (ifp);
+#else
+      if_get_mtu (ifp);
+#endif /* __bsdi__ */
+      if_get_metric (ifp);
+
+      /* Fetch hardware address. */
+      if (sdl->sdl_family != AF_LINK)
+       {
+         zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK");
+         return -1;
+       }
+      memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
+
+      if_add_update (ifp);
+    }
+  else
+    {
+      /* There is a case of promisc, allmulti flag modification. */
+      if (if_is_up (ifp))
+       {
+         ifp->flags = ifm->ifm_flags;
+         if (! if_is_up (ifp))
+           if_down (ifp);
+       }
+      else
+       {
+         ifp->flags = ifm->ifm_flags;
+         if (if_is_up (ifp))
+           if_up (ifp);
+       }
+    }
+  
+#ifdef HAVE_NET_RT_IFLIST
+  ifp->stats = ifm->ifm_data;
+#endif /* HAVE_NET_RT_IFLIST */
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
+
+  return 0;
+}
+\f
+/* Address read from struct ifa_msghdr. */
+void
+ifam_read_mesg (struct ifa_msghdr *ifm,
+               union sockunion *addr,
+               union sockunion *mask,
+               union sockunion *dest)
+{
+  caddr_t pnt, end;
+
+  pnt = (caddr_t)(ifm + 1);
+  end = ((caddr_t)ifm) + ifm->ifam_msglen;
+
+#define IFAMADDRGET(X,R) \
+    if (ifm->ifam_addrs & (R)) \
+      { \
+        int len = WRAPUP(pnt); \
+        if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
+          memcpy ((caddr_t)(X), pnt, len); \
+        pnt += len; \
+      }
+#define IFAMMASKGET(X,R) \
+    if (ifm->ifam_addrs & (R)) \
+      { \
+       int len = WRAPUP(pnt); \
+        if ((X) != NULL) \
+         memcpy ((caddr_t)(X), pnt, len); \
+       pnt += len; \
+      }
+
+  /* Be sure structure is cleared */
+  memset (mask, 0, sizeof (union sockunion));
+  memset (addr, 0, sizeof (union sockunion));
+  memset (dest, 0, sizeof (union sockunion));
+
+  /* We fetch each socket variable into sockunion. */
+  IFAMADDRGET (NULL, RTA_DST);
+  IFAMADDRGET (NULL, RTA_GATEWAY);
+  IFAMMASKGET (mask, RTA_NETMASK);
+  IFAMADDRGET (NULL, RTA_GENMASK);
+  IFAMADDRGET (NULL, RTA_IFP);
+  IFAMADDRGET (addr, RTA_IFA);
+  IFAMADDRGET (NULL, RTA_AUTHOR);
+  IFAMADDRGET (dest, RTA_BRD);
+
+  /* Assert read up end point matches to end point */
+  if (pnt != end)
+    zlog_warn ("ifam_read() does't read all socket data");
+}
+
+/* Interface's address information get. */
+int
+ifam_read (struct ifa_msghdr *ifam)
+{
+  struct interface *ifp;
+  union sockunion addr, mask, gate;
+
+  /* Check does this interface exist or not. */
+  ifp = if_lookup_by_index (ifam->ifam_index);
+  if (ifp == NULL) 
+    {
+      zlog_warn ("no interface for index %d", ifam->ifam_index); 
+      return -1;
+    }
+
+  /* Allocate and read address information. */
+  ifam_read_mesg (ifam, &addr, &mask, &gate);
+
+  /* Check interface flag for implicit up of the interface. */
+  if_refresh (ifp);
+
+  /* Add connected address. */
+  switch (sockunion_family (&addr))
+    {
+    case AF_INET:
+      if (ifam->ifam_type == RTM_NEWADDR)
+       connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, 
+                           ip_masklen (mask.sin.sin_addr),
+                           &gate.sin.sin_addr, NULL);
+      else
+       connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, 
+                              ip_masklen (mask.sin.sin_addr),
+                              &gate.sin.sin_addr, NULL);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      /* Unset interface index from link-local address when IPv6 stack
+        is KAME. */
+      if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr))
+       SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0);
+
+      if (ifam->ifam_type == RTM_NEWADDR)
+       connected_add_ipv6 (ifp,
+                           &addr.sin6.sin6_addr, 
+                           ip6_masklen (mask.sin6.sin6_addr),
+                           &gate.sin6.sin6_addr);
+      else
+       connected_delete_ipv6 (ifp,
+                              &addr.sin6.sin6_addr, 
+                              ip6_masklen (mask.sin6.sin6_addr),
+                              &gate.sin6.sin6_addr);
+      break;
+#endif /* HAVE_IPV6 */
+    default:
+      /* Unsupported family silently ignore... */
+      break;
+    }
+  return 0;
+}
+\f
+/* Interface function for reading kernel routing table information. */
+int
+rtm_read_mesg (struct rt_msghdr *rtm,
+              union sockunion *dest,
+              union sockunion *mask,
+              union sockunion *gate)
+{
+  caddr_t pnt, end;
+
+  /* Pnt points out socket data start point. */
+  pnt = (caddr_t)(rtm + 1);
+  end = ((caddr_t)rtm) + rtm->rtm_msglen;
+
+  /* rt_msghdr version check. */
+  if (rtm->rtm_version != RTM_VERSION) 
+      zlog (NULL, LOG_WARNING,
+             "Routing message version different %d should be %d."
+             "This may cause problem\n", rtm->rtm_version, RTM_VERSION);
+
+#define RTMADDRGET(X,R) \
+    if (rtm->rtm_addrs & (R)) \
+      { \
+       int len = WRAPUP (pnt); \
+        if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
+         memcpy ((caddr_t)(X), pnt, len); \
+       pnt += len; \
+      }
+#define RTMMASKGET(X,R) \
+    if (rtm->rtm_addrs & (R)) \
+      { \
+       int len = WRAPUP (pnt); \
+        if ((X) != NULL) \
+         memcpy ((caddr_t)(X), pnt, len); \
+       pnt += len; \
+      }
+
+  /* Be sure structure is cleared */
+  memset (dest, 0, sizeof (union sockunion));
+  memset (gate, 0, sizeof (union sockunion));
+  memset (mask, 0, sizeof (union sockunion));
+
+  /* We fetch each socket variable into sockunion. */
+  RTMADDRGET (dest, RTA_DST);
+  RTMADDRGET (gate, RTA_GATEWAY);
+  RTMMASKGET (mask, RTA_NETMASK);
+  RTMADDRGET (NULL, RTA_GENMASK);
+  RTMADDRGET (NULL, RTA_IFP);
+  RTMADDRGET (NULL, RTA_IFA);
+  RTMADDRGET (NULL, RTA_AUTHOR);
+  RTMADDRGET (NULL, RTA_BRD);
+
+  /* If there is netmask information set it's family same as
+     destination family*/
+  if (rtm->rtm_addrs & RTA_NETMASK)
+    mask->sa.sa_family = dest->sa.sa_family;
+
+  /* Assert read up to the end of pointer. */
+  if (pnt != end) 
+      zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data.");
+
+  return rtm->rtm_flags;
+}
+
+void
+rtm_read (struct rt_msghdr *rtm)
+{
+  int flags;
+  u_char zebra_flags;
+  union sockunion dest, mask, gate;
+
+  zebra_flags = 0;
+
+  /* Discard self send message. */
+  if (rtm->rtm_type != RTM_GET 
+      && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
+    return;
+
+  /* Read destination and netmask and gateway from rtm message
+     structure. */
+  flags = rtm_read_mesg (rtm, &dest, &mask, &gate);
+
+#ifdef RTF_CLONED      /*bsdi, netbsd 1.6*/
+  if (flags & RTF_CLONED)
+    return;
+#endif
+#ifdef RTF_WASCLONED   /*freebsd*/
+  if (flags & RTF_WASCLONED)
+    return;
+#endif
+
+  if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP))
+    return;
+
+  /* This is connected route. */
+  if (! (flags & RTF_GATEWAY))
+      return;
+
+  if (flags & RTF_PROTO1)
+    SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE);
+
+  /* This is persistent route. */
+  if (flags & RTF_STATIC)
+    SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC);
+
+  if (dest.sa.sa_family == AF_INET)
+    {
+      struct prefix_ipv4 p;
+
+      p.family = AF_INET;
+      p.prefix = dest.sin.sin_addr;
+      if (flags & RTF_HOST)
+       p.prefixlen = IPV4_MAX_PREFIXLEN;
+      else
+       p.prefixlen = ip_masklen (mask.sin.sin_addr);
+
+      if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
+       rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
+                     &p, &gate.sin.sin_addr, 0, 0, 0, 0);
+      else
+       rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
+                     &p, &gate.sin.sin_addr, 0, 0);
+    }
+#ifdef HAVE_IPV6
+  if (dest.sa.sa_family == AF_INET6)
+    {
+      struct prefix_ipv6 p;
+      unsigned int ifindex = 0;
+
+      p.family = AF_INET6;
+      p.prefix = dest.sin6.sin6_addr;
+      if (flags & RTF_HOST)
+       p.prefixlen = IPV6_MAX_PREFIXLEN;
+      else
+       p.prefixlen = ip6_masklen (mask.sin6.sin6_addr);
+
+#ifdef KAME
+      if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr))
+       {
+         ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr);
+         SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0);
+       }
+#endif /* KAME */
+
+      if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
+       rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
+                     &p, &gate.sin6.sin6_addr, ifindex, 0);
+      else
+       rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
+                        &p, &gate.sin6.sin6_addr, ifindex, 0);
+    }
+#endif /* HAVE_IPV6 */
+}
+
+/* Interface function for the kernel routing table updates.  Support
+   for RTM_CHANGE will be needed. */
+int
+rtm_write (int message,
+          union sockunion *dest,
+          union sockunion *mask,
+          union sockunion *gate,
+          unsigned int index,
+          int zebra_flags,
+          int metric)
+{
+  int ret;
+  caddr_t pnt;
+  struct interface *ifp;
+  struct sockaddr_in tmp_gate;
+#ifdef HAVE_IPV6
+  struct sockaddr_in6 tmp_gate6;
+#endif /* HAVE_IPV6 */
+
+  /* Sequencial number of routing message. */
+  static int msg_seq = 0;
+
+  /* Struct of rt_msghdr and buffer for storing socket's data. */
+  struct 
+  {
+    struct rt_msghdr rtm;
+    char buf[512];
+  } msg;
+  
+  memset (&tmp_gate, 0, sizeof (struct sockaddr_in));
+  tmp_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  tmp_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+#ifdef HAVE_IPV6
+  memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6));
+  tmp_gate6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  tmp_gate6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+#endif /* HAVE_IPV6 */
+
+  if (routing_sock < 0)
+    return ZEBRA_ERR_EPERM;
+
+  /* Clear and set rt_msghdr values */
+  memset (&msg, 0, sizeof (struct rt_msghdr));
+  msg.rtm.rtm_version = RTM_VERSION;
+  msg.rtm.rtm_type = message;
+  msg.rtm.rtm_seq = msg_seq++;
+  msg.rtm.rtm_addrs = RTA_DST;
+  msg.rtm.rtm_addrs |= RTA_GATEWAY;
+  msg.rtm.rtm_flags = RTF_UP;
+  msg.rtm.rtm_index = index;
+
+  if (metric != 0)
+    {
+      msg.rtm.rtm_rmx.rmx_hopcount = metric;
+      msg.rtm.rtm_inits |= RTV_HOPCOUNT;
+    }
+
+  ifp = if_lookup_by_index (index);
+
+  if (gate && message == RTM_ADD)
+    msg.rtm.rtm_flags |= RTF_GATEWAY;
+
+  if (! gate && message == RTM_ADD && ifp &&
+      (ifp->flags & IFF_POINTOPOINT) == 0)
+    msg.rtm.rtm_flags |= RTF_CLONING;
+
+  /* If no protocol specific gateway is specified, use link
+     address for gateway. */
+  if (! gate)
+    {
+      if (!ifp)
+        {
+          zlog_warn ("no gateway found for interface index %d", index);
+          return -1;
+        }
+      gate = (union sockunion *) & ifp->sdl;
+    }
+
+  if (mask)
+    msg.rtm.rtm_addrs |= RTA_NETMASK;
+  else if (message == RTM_ADD) 
+    msg.rtm.rtm_flags |= RTF_HOST;
+
+  /* Tagging route with flags */
+  msg.rtm.rtm_flags |= (RTF_PROTO1);
+
+  /* Additional flags. */
+  if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
+    msg.rtm.rtm_flags |= RTF_BLACKHOLE;
+
+#ifdef HAVE_SIN_LEN
+#define SOCKADDRSET(X,R) \
+  if (msg.rtm.rtm_addrs & (R)) \
+    { \
+      int len = ROUNDUP ((X)->sa.sa_len); \
+      memcpy (pnt, (caddr_t)(X), len); \
+      pnt += len; \
+    }
+#else 
+#define SOCKADDRSET(X,R) \
+  if (msg.rtm.rtm_addrs & (R)) \
+    { \
+      int len = ROUNDUP (sizeof((X)->sa)); \
+      memcpy (pnt, (caddr_t)(X), len); \
+      pnt += len; \
+    }
+#endif /* HAVE_SIN_LEN */
+
+  pnt = (caddr_t) msg.buf;
+
+  /* Write each socket data into rtm message buffer */
+  SOCKADDRSET (dest, RTA_DST);
+  SOCKADDRSET (gate, RTA_GATEWAY);
+  SOCKADDRSET (mask, RTA_NETMASK);
+
+  msg.rtm.rtm_msglen = pnt - (caddr_t) &msg;
+
+  ret = write (routing_sock, &msg, msg.rtm.rtm_msglen);
+
+  if (ret != msg.rtm.rtm_msglen) 
+    {
+      if (errno == EEXIST) 
+       return ZEBRA_ERR_RTEXIST;
+      if (errno == ENETUNREACH)
+       return ZEBRA_ERR_RTUNREACH;
+      
+      zlog_warn ("write : %s (%d)", strerror (errno), errno);
+      return -1;
+    }
+  return 0;
+}
+
+\f
+#include "thread.h"
+#include "zebra/zserv.h"
+
+extern struct thread_master *master;
+
+/* For debug purpose. */
+void
+rtmsg_debug (struct rt_msghdr *rtm)
+{
+  char *type = "Unknown";
+  struct message *mes;
+
+  for (mes = rtm_type_str; mes->str; mes++)
+    if (mes->key == rtm->rtm_type)
+      {
+       type = mes->str;
+       break;
+      }
+
+  zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
+  rtm_flag_dump (rtm->rtm_flags);
+  zlog_info ("Kernel: message seq %d", rtm->rtm_seq);
+  zlog_info ("Kernel: pid %d", rtm->rtm_pid);
+}
+
+/* This is pretty gross, better suggestions welcome -- mhandler */
+#ifndef RTAX_MAX
+#ifdef RTA_NUMBITS
+#define RTAX_MAX       RTA_NUMBITS
+#else
+#define RTAX_MAX       8
+#endif /* RTA_NUMBITS */
+#endif /* RTAX_MAX */
+
+/* Kernel routing table and interface updates via routing socket. */
+int
+kernel_read (struct thread *thread)
+{
+  int sock;
+  int nbytes;
+  struct rt_msghdr *rtm;
+
+  union 
+  {
+    /* Routing information. */
+    struct 
+    {
+      struct rt_msghdr rtm;
+      struct sockaddr addr[RTAX_MAX];
+    } r;
+
+    /* Interface information. */
+    struct
+    {
+      struct if_msghdr ifm;
+      struct sockaddr addr[RTAX_MAX];
+    } im;
+
+    /* Interface address information. */
+    struct
+    {
+      struct ifa_msghdr ifa;
+      struct sockaddr addr[RTAX_MAX];
+    } ia;
+
+#ifdef RTM_IFANNOUNCE
+    /* Interface arrival/departure */
+    struct
+    {
+      struct if_announcemsghdr ifan;
+      struct sockaddr addr[RTAX_MAX];
+    } ian;
+#endif /* RTM_IFANNOUNCE */
+
+  } buf;
+
+  /* Fetch routing socket. */
+  sock = THREAD_FD (thread);
+
+  nbytes= read (sock, &buf, sizeof buf);
+
+  if (nbytes <= 0)
+    {
+      if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
+       zlog_warn ("routing socket error: %s", strerror (errno));
+      return 0;
+    }
+
+  thread_add_read (master, kernel_read, NULL, sock);
+
+#ifdef DEBUG
+  rtmsg_debug (&buf.r.rtm);
+#endif /* DEBUG */
+
+  rtm = &buf.r.rtm;
+
+  switch (rtm->rtm_type)
+    {
+    case RTM_ADD:
+    case RTM_DELETE:
+      rtm_read (rtm);
+      break;
+    case RTM_IFINFO:
+      ifm_read (&buf.im.ifm);
+      break;
+    case RTM_NEWADDR:
+    case RTM_DELADDR:
+      ifam_read (&buf.ia.ifa);
+      break;
+#ifdef RTM_IFANNOUNCE
+    case RTM_IFANNOUNCE:
+      ifan_read (&buf.ian.ifan);
+      break;
+#endif /* RTM_IFANNOUNCE */
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* Make routing socket. */
+void
+routing_socket ()
+{
+  routing_sock = socket (AF_ROUTE, SOCK_RAW, 0);
+
+  if (routing_sock < 0) 
+    {
+      zlog_warn ("Can't init kernel routing socket");
+      return;
+    }
+
+  if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) 
+    zlog_warn ("Can't set O_NONBLOCK to routing socket");
+
+  /* kernel_read needs rewrite. */
+  thread_add_read (master, kernel_read, NULL, routing_sock);
+}
+
+/* Exported interface function.  This function simply calls
+   routing_socket (). */
+void
+kernel_init ()
+{
+  routing_socket ();
+}
diff --git a/zebra/main.c b/zebra/main.c
new file mode 100644 (file)
index 0000000..25d8b6d
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * zebra daemon main routine.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+#include "getopt.h"
+#include "command.h"
+#include "thread.h"
+#include "filter.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* process id. */
+pid_t old_pid;
+pid_t pid;
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* Don't delete kernel route. */
+int keep_kernel_mode = 0;
+
+/* Command line options. */
+struct option longopts[] = 
+{
+  { "batch",       no_argument,       NULL, 'b'},
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "keep_kernel", no_argument,       NULL, 'k'},
+  { "log_mode",    no_argument,       NULL, 'l'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "help",        no_argument,       NULL, 'h'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "retain",      no_argument,       NULL, 'r'},
+  { "version",     no_argument,       NULL, 'v'},
+  { 0 }
+};
+
+/* Default configuration file path. */
+char config_current[] = DEFAULT_CONFIG_FILE;
+char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_ZEBRA_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages kernel routing table management and \
+redistribution between different routing protocols.\n\n\
+-b, --batch        Runs in batch mode\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-k, --keep_kernel  Don't delete old routes which installed by zebra.\n\
+-l, --log_mode     Set verbose log mode flag\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-r, --retain       When program terminates, retain added route by zebra.\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+
+  exit (status);
+}
+\f
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog_info ("SIGHUP received");
+
+  /* Reload of config file. */
+  ;
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  /* Decrared in rib.c */
+  void rib_close ();
+
+  zlog_info ("Terminating on signal");
+
+  if (!retain_mode)
+    rib_close ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+  signal_set (SIGUSR1, sigusr1);
+}
+\f
+/* Main startup routine. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  char *vty_addr = NULL;
+  int vty_port = 0;
+  int batch_mode = 0;
+  int daemon_mode = 0;
+  char *config_file = NULL;
+  char *progname;
+  struct thread thread;
+  void rib_weed_tables ();
+  void zebra_vty_init ();
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* preserve my name */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  zlog_default = openzlog (progname, ZLOG_STDOUT, ZLOG_ZEBRA,
+                          LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  while (1) 
+    {
+      int opt;
+  
+      opt = getopt_long (argc, argv, "bdklf:hA:P:rv", longopts, 0);
+
+      if (opt == EOF)
+       break;
+
+      switch (opt) 
+       {
+       case 0:
+         break;
+       case 'b':
+         batch_mode = 1;
+       case 'd':
+         daemon_mode = 1;
+         break;
+       case 'k':
+         keep_kernel_mode = 1;
+         break;
+       case 'l':
+         /* log_mode = 1; */
+         break;
+       case 'f':
+         config_file = optarg;
+         break;
+       case 'A':
+         vty_addr = optarg;
+         break;
+        case 'i':
+          pid_file = optarg;
+          break;
+       case 'P':
+         vty_port = atoi (optarg);
+         break;
+       case 'r':
+         retain_mode = 1;
+         break;
+       case 'v':
+         print_version (progname);
+         exit (0);
+         break;
+       case 'h':
+         usage (progname, 0);
+         break;
+       default:
+         usage (progname, 1);
+         break;
+       }
+    }
+
+  /* Make master thread emulator. */
+  master = thread_master_create ();
+
+  /* Vty related initialize. */
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  memory_init ();
+
+  /* Zebra related initialize. */
+  zebra_init ();
+  rib_init ();
+  zebra_if_init ();
+  zebra_debug_init ();
+  zebra_vty_init ();
+  access_list_init ();
+  rtadv_init ();
+
+  /* For debug purpose. */
+  /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
+
+  /* Make kernel routing socket. */
+  kernel_init ();
+  interface_list ();
+  route_read ();
+
+  /* Sort VTY commands. */
+  sort_node ();
+
+#ifdef HAVE_SNMP
+  zebra_snmp_init ();
+#endif /* HAVE_SNMP */
+
+  /* Clean up self inserted route. */
+  if (! keep_kernel_mode)
+    rib_sweep_route ();
+
+  /* Configuration file read*/
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Clean up rib. */
+  rib_weed_tables ();
+
+  /* Exit when zebra is working in batch mode. */
+  if (batch_mode)
+    exit (0);
+
+  /* Needed for BSD routing socket. */
+  old_pid = getpid ();
+
+  /* Daemonize. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Output pid of zebra. */
+  pid_output (pid_file);
+
+  /* Needed for BSD routing socket. */
+  pid = getpid ();
+
+  /* Make vty server socket. */
+  vty_serv_sock (vty_addr,
+                vty_port ? vty_port : ZEBRA_VTY_PORT, ZEBRA_VTYSH_PATH);
+
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached... */
+  exit (0);
+}
diff --git a/zebra/mtu_kvm.c b/zebra/mtu_kvm.c
new file mode 100644 (file)
index 0000000..3731dab
--- /dev/null
@@ -0,0 +1,97 @@
+/* MTU get using kvm_read.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include <kvm.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "if.h"
+
+/* get interface MTU to use kvm_read */
+void
+if_kvm_get_mtu (struct interface *ifp)
+{
+  kvm_t *kvmd;
+  struct ifnet ifnet;
+  unsigned long ifnetaddr;
+  int len;
+  char ifname[IFNAMSIZ];
+  char tname[INTERFACE_NAMSIZ + 1];
+  char buf[_POSIX2_LINE_MAX];
+  struct nlist nl[] = 
+  {
+    {"_ifnet"},
+    {""}
+  };
+
+  ifp->mtu = -1;
+  
+  kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf);
+
+  if (kvmd == NULL) 
+    return ;
+  
+  kvm_nlist(kvmd, nl);
+  ifnetaddr = nl[0].n_value;
+  if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0) 
+    {
+      kvm_close (kvmd);
+      return ;
+    }
+  while(ifnetaddr != 0) 
+    {
+      if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0) 
+       {
+         kvm_close (kvmd);
+         return ;
+       }
+
+      if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0) 
+       {
+         kvm_close (kvmd);
+         return ;
+       }
+
+      len = snprintf (tname, INTERFACE_NAMSIZ + 1, 
+                     "%s%d", ifname, ifnet.if_unit);
+
+      if (strncmp (tname, ifp->name, len) == 0)
+       break;
+
+      ifnetaddr = (u_long)ifnet.if_next;
+    }
+
+  kvm_close (kvmd);
+
+  if (ifnetaddr == 0) 
+    {
+      return ;
+    }
+
+  ifp->mtu = ifnet.if_mtu;
+}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
new file mode 100644 (file)
index 0000000..a3d4bad
--- /dev/null
@@ -0,0 +1,410 @@
+/* Redistribution Handler
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "stream.h"
+#include "zclient.h"
+#include "linklist.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+int
+zebra_check_addr (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    {
+      u_int32_t addr;
+
+      addr = p->u.prefix4.s_addr;
+      addr = ntohl (addr);
+
+      if (IPV4_NET127 (addr) || IN_CLASSD (addr))
+       return 0;
+    }
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    {
+      if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6))
+       return 0;
+      if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
+       return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return 1;
+}
+
+int
+is_default (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0)
+      return 1;
+#ifdef HAVE_IPV6
+#if 0  /* IPv6 default separation is now pending until protocol daemon
+          can handle that. */
+  if (p->family == AF_INET6)
+    if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0)
+      return 1;
+#endif /* 0 */
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+void
+zebra_redistribute_default (struct zserv *client)
+{
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *newrib;
+#ifdef HAVE_IPV6
+  struct prefix_ipv6 p6;
+#endif /* HAVE_IPV6 */
+
+
+  /* Lookup default route. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (table)
+    {
+      rn = route_node_lookup (table, (struct prefix *)&p);
+      if (rn)
+       {
+         for (newrib = rn->info; newrib; newrib = newrib->next)
+           if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+               && newrib->distance != DISTANCE_INFINITY)
+             zsend_ipv4_add_multipath (client, &rn->p, newrib);
+         route_unlock_node (rn);
+       }
+    }
+
+#ifdef HAVE_IPV6
+  /* Lookup default route. */
+  memset (&p6, 0, sizeof (struct prefix_ipv6));
+  p6.family = AF_INET6;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (table)
+    {
+      rn = route_node_lookup (table, (struct prefix *)&p6);
+      if (rn)
+       {
+         for (newrib = rn->info; newrib; newrib = newrib->next)
+           if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+               && newrib->distance != DISTANCE_INFINITY)
+             zsend_ipv6_add_multipath (client, &rn->p, newrib);
+         route_unlock_node (rn);
+       }
+    }
+#endif /* HAVE_IPV6 */
+}
+
+/* Redistribute routes. */
+void
+zebra_redistribute (struct zserv *client, int type)
+{
+  struct rib *newrib;
+  struct route_table *table;
+  struct route_node *rn;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (newrib = rn->info; newrib; newrib = newrib->next)
+       if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) 
+           && newrib->type == type 
+           && newrib->distance != DISTANCE_INFINITY
+           && zebra_check_addr (&rn->p))
+         zsend_ipv4_add_multipath (client, &rn->p, newrib);
+  
+#ifdef HAVE_IPV6
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (newrib = rn->info; newrib; newrib = newrib->next)
+       if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
+           && newrib->type == type 
+           && newrib->distance != DISTANCE_INFINITY
+           && zebra_check_addr (&rn->p))
+         zsend_ipv6_add_multipath (client, &rn->p, newrib);
+#endif /* HAVE_IPV6 */
+}
+
+extern list client_list;
+
+void
+redistribute_add (struct prefix *p, struct rib *rib)
+{
+  listnode node;
+  struct zserv *client;
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      {
+       if (is_default (p))
+         {
+           if (client->redist_default || client->redist[rib->type])
+             {
+               if (p->family == AF_INET)
+                 zsend_ipv4_add_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+               if (p->family == AF_INET6)
+                 zsend_ipv6_add_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */   
+             }
+         }
+       else if (client->redist[rib->type])
+         {
+           if (p->family == AF_INET)
+             zsend_ipv4_add_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+           if (p->family == AF_INET6)
+             zsend_ipv6_add_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */   
+         }
+      }
+}
+
+void
+redistribute_delete (struct prefix *p, struct rib *rib)
+{
+  listnode node;
+  struct zserv *client;
+
+  /* Add DISTANCE_INFINITY check. */
+  if (rib->distance == DISTANCE_INFINITY)
+    return;
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      {
+       if (is_default (p))
+         {
+           if (client->redist_default || client->redist[rib->type])
+             {
+               if (p->family == AF_INET)
+                 zsend_ipv4_delete_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+               if (p->family == AF_INET6)
+                 zsend_ipv6_delete_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */   
+             }
+         }
+       else if (client->redist[rib->type])
+         {
+           if (p->family == AF_INET)
+             zsend_ipv4_delete_multipath (client, p, rib);
+#ifdef HAVE_IPV6
+           if (p->family == AF_INET6)
+             zsend_ipv6_delete_multipath (client, p, rib);
+#endif /* HAVE_IPV6 */   
+         }
+      }
+}
+
+void
+zebra_redistribute_add (int command, struct zserv *client, int length)
+{
+  int type;
+
+  type = stream_getc (client->ibuf);
+
+  switch (type)
+    {
+    case ZEBRA_ROUTE_KERNEL:
+    case ZEBRA_ROUTE_CONNECT:
+    case ZEBRA_ROUTE_STATIC:
+    case ZEBRA_ROUTE_RIP:
+    case ZEBRA_ROUTE_RIPNG:
+    case ZEBRA_ROUTE_OSPF:
+    case ZEBRA_ROUTE_OSPF6:
+    case ZEBRA_ROUTE_BGP:
+      if (! client->redist[type])
+       {
+         client->redist[type] = 1;
+         zebra_redistribute (client, type);
+       }
+      break;
+    default:
+      break;
+    }
+}     
+
+void
+zebra_redistribute_delete (int command, struct zserv *client, int length)
+{
+  int type;
+
+  type = stream_getc (client->ibuf);
+
+  switch (type)
+    {
+    case ZEBRA_ROUTE_KERNEL:
+    case ZEBRA_ROUTE_CONNECT:
+    case ZEBRA_ROUTE_STATIC:
+    case ZEBRA_ROUTE_RIP:
+    case ZEBRA_ROUTE_RIPNG:
+    case ZEBRA_ROUTE_OSPF:
+    case ZEBRA_ROUTE_OSPF6:
+    case ZEBRA_ROUTE_BGP:
+      client->redist[type] = 0;
+      break;
+    default:
+      break;
+    }
+}     
+
+void
+zebra_redistribute_default_add (int command, struct zserv *client, int length)
+{
+  client->redist_default = 1;
+  zebra_redistribute_default (client);
+}     
+
+void
+zebra_redistribute_default_delete (int command, struct zserv *client,
+                                  int length)
+{
+  client->redist_default = 0;;
+}     
+
+/* Interface up information. */
+void
+zebra_interface_up_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name);
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_interface_up (client, ifp);
+}
+
+/* Interface down information. */
+void
+zebra_interface_down_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name);
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      zsend_interface_down (client, ifp);
+}
+
+/* Interface information update. */
+void
+zebra_interface_add_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name);
+    
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo)
+       zsend_interface_add (client, ifp);
+}
+
+void
+zebra_interface_delete_update (struct interface *ifp)
+{
+  listnode node;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name);
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo)
+       zsend_interface_delete (client, ifp);
+}
+
+/* Interface address addition. */
+void
+zebra_interface_address_add_update (struct interface *ifp,
+                                   struct connected *ifc)
+{
+  listnode node;
+  struct zserv *client;
+  struct prefix *p;
+  char buf[BUFSIZ];
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    {
+      p = ifc->address;
+      zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s",
+                inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                p->prefixlen, ifc->ifp->name);
+    }
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+       zsend_interface_address_add (client, ifp, ifc);
+}
+
+/* Interface address deletion. */
+void
+zebra_interface_address_delete_update (struct interface *ifp,
+                                      struct connected *ifc)
+{
+  listnode node;
+  struct zserv *client;
+  struct prefix *p;
+  char buf[BUFSIZ];
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    {
+      p = ifc->address;
+      zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s",
+                inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                p->prefixlen, ifc->ifp->name);
+    }
+
+  for (node = listhead (client_list); node; nextnode (node))
+    if ((client = getdata (node)) != NULL)
+      if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+       zsend_interface_address_delete (client, ifp, ifc);
+}
diff --git a/zebra/redistribute.h b/zebra/redistribute.h
new file mode 100644 (file)
index 0000000..8b45cf3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Redistribution Handler
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_REDISTRIBUTE_H
+#define _ZEBRA_REDISTRIBUTE_H
+
+#include "table.h"
+
+void zebra_redistribute_add (int, struct zserv *, int);
+void zebra_redistribute_delete (int, struct zserv *, int);
+
+void zebra_redistribute_default_add (int, struct zserv *, int);
+void zebra_redistribute_default_delete (int, struct zserv *, int);
+
+void redistribute_add (struct prefix *, struct rib *);
+void redistribute_delete (struct prefix *, struct rib *);
+
+void zebra_interface_up_update (struct interface *);
+void zebra_interface_down_update (struct interface *);
+
+void zebra_interface_add_update (struct interface *);
+void zebra_interface_delete_update (struct interface *);
+
+void zebra_interface_address_add_update (struct interface *,
+                                        struct connected *);
+void zebra_interface_address_delete_update (struct interface *,
+                                           struct connected *c);
+
+#endif /* _ZEBRA_REDISTRIBUTE_H */
+
diff --git a/zebra/rib.h b/zebra/rib.h
new file mode 100644 (file)
index 0000000..f501261
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Routing Information Base header
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_RIB_H
+#define _ZEBRA_RIB_H
+
+#define DISTANCE_INFINITY  255
+
+/* Routing information base. */
+struct rib
+{
+  /* Link list. */
+  struct rib *next;
+  struct rib *prev;
+
+  /* Type fo this route. */
+  int type;
+
+  /* Which routing table */
+  int table;                   
+
+  /* Distance. */
+  u_char distance;
+
+  /* Flags of this route.  This flag's definition is in lib/zebra.h
+     ZEBRA_FLAG_* */
+  u_char flags;
+
+  /* Metric */
+  u_int32_t metric;
+
+  /* Uptime. */
+  time_t uptime;
+
+  /* Refrence count. */
+  unsigned long refcnt;
+
+  /* Nexthop information. */
+  u_char nexthop_num;
+  u_char nexthop_active_num;
+  u_char nexthop_fib_num;
+
+  struct nexthop *nexthop;
+};
+
+/* Static route information. */
+struct static_ipv4
+{
+  /* For linked list. */
+  struct static_ipv4 *prev;
+  struct static_ipv4 *next;
+
+  /* Administrative distance. */
+  u_char distance;
+
+  /* Flag for this static route's type. */
+  u_char type;
+#define STATIC_IPV4_GATEWAY     1
+#define STATIC_IPV4_IFNAME      2
+#define STATIC_IPV4_BLACKHOLE   3
+
+  /* Nexthop value. */
+  union 
+  {
+    struct in_addr ipv4;
+    char *ifname;
+  } gate;
+};
+
+#ifdef HAVE_IPV6
+/* Static route information. */
+struct static_ipv6
+{
+  /* For linked list. */
+  struct static_ipv6 *prev;
+  struct static_ipv6 *next;
+
+  /* Administrative distance. */
+  u_char distance;
+
+  /* Flag for this static route's type. */
+  u_char type;
+#define STATIC_IPV6_GATEWAY          1
+#define STATIC_IPV6_GATEWAY_IFNAME   2
+#define STATIC_IPV6_IFNAME           3
+
+  /* Nexthop value. */
+  struct in6_addr ipv6;
+  char *ifname;
+};
+#endif /* HAVE_IPV6 */
+
+/* Nexthop structure. */
+struct nexthop
+{
+  struct nexthop *next;
+  struct nexthop *prev;
+
+  u_char type;
+#define NEXTHOP_TYPE_IFINDEX        1 /* Directly connected.  */
+#define NEXTHOP_TYPE_IFNAME         2 /* Interface route.  */
+#define NEXTHOP_TYPE_IPV4           3 /* IPv4 nexthop.  */
+#define NEXTHOP_TYPE_IPV4_IFINDEX   4 /* IPv4 nexthop with ifindex.  */
+#define NEXTHOP_TYPE_IPV4_IFNAME    5 /* IPv4 nexthop with ifname.  */
+#define NEXTHOP_TYPE_IPV6           6 /* IPv6 nexthop.  */
+#define NEXTHOP_TYPE_IPV6_IFINDEX   7 /* IPv6 nexthop with ifindex.  */
+#define NEXTHOP_TYPE_IPV6_IFNAME    8 /* IPv6 nexthop with ifname.  */
+#define NEXTHOP_TYPE_BLACKHOLE      9 /* Null0 nexthop.  */
+
+  u_char flags;
+#define NEXTHOP_FLAG_ACTIVE     (1 << 0) /* This nexthop is alive. */
+#define NEXTHOP_FLAG_FIB        (1 << 1) /* FIB nexthop. */
+#define NEXTHOP_FLAG_RECURSIVE  (1 << 2) /* Recursive nexthop. */
+
+  /* Interface index. */
+  unsigned int ifindex;
+  char *ifname;
+
+  /* Nexthop address or interface name. */
+  union
+  {
+    struct in_addr ipv4;
+#ifdef HAVE_IPV6
+    struct in6_addr ipv6;
+#endif /* HAVE_IPV6*/
+  } gate;
+
+  /* Recursive lookup nexthop. */
+  u_char rtype;
+  unsigned int rifindex;
+  union
+  {
+    struct in_addr ipv4;
+#ifdef HAVE_IPV6
+    struct in6_addr ipv6;
+#endif /* HAVE_IPV6 */
+  } rgate;
+
+  struct nexthop *indirect;
+};
+
+/* Routing table instance.  */
+struct vrf
+{
+  /* Identifier.  This is same as routing table vector index.  */
+  u_int32_t id;
+
+  /* Routing table name.  */
+  char *name;
+
+  /* Description.  */
+  char *desc;
+
+  /* FIB identifier.  */
+  u_char fib_id;
+
+  /* Routing table.  */
+  struct route_table *table[AFI_MAX][SAFI_MAX];
+
+  /* Static route configuration.  */
+  struct route_table *stable[AFI_MAX][SAFI_MAX];
+};
+
+struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
+struct nexthop *nexthop_ifname_add (struct rib *, char *);
+struct nexthop *nexthop_blackhole_add (struct rib *);
+struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *);
+#ifdef HAVE_IPV6
+struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *);
+#endif /* HAVE_IPV6 */
+
+struct vrf *vrf_lookup (u_int32_t);
+struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id);
+struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id);
+
+int
+rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
+             struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+             u_int32_t, u_char);
+
+int
+rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
+
+int
+rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+                struct in_addr *gate, unsigned int ifindex, u_int32_t);
+
+struct rib *
+rib_match_ipv4 (struct in_addr);
+
+struct rib *
+rib_lookup_ipv4 (struct prefix_ipv4 *);
+
+void rib_update ();
+void rib_sweep_route ();
+void rib_close ();
+void rib_init ();
+
+int
+static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+                u_char distance, u_int32_t vrf_id);
+
+int
+static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+                   u_char distance, u_int32_t vrf_id);
+
+#ifdef HAVE_IPV6
+int
+rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+             struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
+
+int
+rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+                struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
+
+struct rib *rib_lookup_ipv6 (struct in6_addr *);
+
+struct rib *rib_match_ipv6 (struct in6_addr *);
+
+extern struct route_table *rib_table_ipv6;
+
+int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                char *ifname, u_char distance, u_int32_t vrf_id);
+
+int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                   char *ifname, u_char distance, u_int32_t vrf_id);
+
+#endif /* HAVE_IPV6 */
+
+#endif /*_ZEBRA_RIB_H */
diff --git a/zebra/rt.h b/zebra/rt.h
new file mode 100644 (file)
index 0000000..faaddab
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * kernel routing table update prototype.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_RT_H
+#define _ZEBRA_RT_H
+
+int kernel_add_ipv4 (struct prefix *, struct rib *);
+int kernel_delete_ipv4 (struct prefix *, struct rib *);
+int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int);
+int kernel_address_add_ipv4 (struct interface *, struct connected *);
+int kernel_address_delete_ipv4 (struct interface *, struct connected *);
+
+#ifdef HAVE_IPV6
+int kernel_add_ipv6 (struct prefix *, struct rib *);
+int kernel_delete_ipv6 (struct prefix *, struct rib *);
+int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+                           unsigned int index, int flags, int table);
+
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_RT_H */
diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c
new file mode 100644 (file)
index 0000000..d470572
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * kernel routing table update by ioctl().
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "log.h"
+#include "if.h"
+
+#include "zebra/rib.h"
+#include "zebra/debug.h"
+
+/* Initialize of kernel interface.  There is no kernel communication
+   support under ioctl().  So this is dummy stub function. */
+void
+kernel_init ()
+{
+  return;
+}
+
+/* Dummy function of routing socket. */
+void
+kernel_read (int sock)
+{
+  return;
+}
+
+#if 0
+/* Initialization prototype of struct sockaddr_in. */
+static struct sockaddr_in sin_proto =
+{
+#ifdef HAVE_SIN_LEN
+  sizeof (struct sockaddr_in), 
+#endif /* HAVE_SIN_LEN */
+  AF_INET, 0, {0}, {0}
+};
+#endif /* 0 */
+
+/* Solaris has ortentry. */
+#ifdef HAVE_OLD_RTENTRY
+#define rtentry ortentry
+#endif /* HAVE_OLD_RTENTRY */
+
+/* Interface to ioctl route message. */
+int
+kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
+                 int index, int flags)
+{
+  int ret;
+  int sock;
+  struct rtentry rtentry;
+  struct sockaddr_in sin_dest, sin_mask, sin_gate;
+
+  memset (&rtentry, 0, sizeof (struct rtentry));
+
+  /* Make destination. */
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+  sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  sin_dest.sin_addr = dest->prefix;
+
+  /* Make gateway. */
+  if (gate)
+    {
+      memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+      sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+      sin_gate.sin_addr = *gate;
+    }
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+  sin_mask.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
+
+  /* Set destination address, mask and gateway.*/
+  memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
+  if (gate)
+    memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
+#ifndef SUNOS_5
+  memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS_5 */
+
+  /* Routing entry flag set. */
+  if (dest->prefixlen == 32)
+    rtentry.rt_flags |= RTF_HOST;
+
+  if (gate && gate->s_addr != INADDR_ANY)
+    rtentry.rt_flags |= RTF_GATEWAY;
+
+  rtentry.rt_flags |= RTF_UP;
+
+  /* Additional flags */
+  rtentry.rt_flags |= flags;
+
+
+  /* For tagging route. */
+  /* rtentry.rt_flags |= RTF_DYNAMIC; */
+
+  /* Open socket for ioctl. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message by ioctl(). */
+  ret = ioctl (sock, SIOCADDRT, &rtentry);
+  if (ret < 0)
+    {
+      switch (errno) 
+       {
+       case EEXIST:
+         close (sock);
+         return ZEBRA_ERR_RTEXIST;
+         break;
+       case ENETUNREACH:
+         close (sock);
+         return ZEBRA_ERR_RTUNREACH;
+         break;
+       case EPERM:
+         close (sock);
+         return ZEBRA_ERR_EPERM;
+         break;
+       }
+
+      close (sock);
+      zlog_warn ("write : %s (%d)", strerror (errno), errno);
+      return 1;
+    }
+  close (sock);
+
+  return ret;
+}
+
+/* Interface to ioctl route message. */
+int
+kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
+{
+  int ret;
+  int sock;
+  struct rtentry rtentry;
+  struct sockaddr_in sin_dest, sin_mask, sin_gate;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+  struct interface *ifp;
+
+  memset (&rtentry, 0, sizeof (struct rtentry));
+
+  /* Make destination. */
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+  sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  sin_dest.sin_addr = p->u.prefix4;
+
+  if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
+    {
+      SET_FLAG (rtentry.rt_flags, RTF_REJECT);
+
+      if (cmd == SIOCADDRT)
+       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+         SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+      goto skip;
+    }
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if ((cmd == SIOCADDRT 
+          && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+         || (cmd == SIOCDELRT
+             && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+       {
+         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+           {
+             if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
+                 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+               {
+                 sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+                 sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+                 sin_gate.sin_addr = nexthop->rgate.ipv4;
+                 rtentry.rt_flags |= RTF_GATEWAY;
+               }
+             if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
+               {
+                 ifp = if_lookup_by_index (nexthop->rifindex);
+                 if (ifp)
+                   rtentry.rt_dev = ifp->name;
+                 else
+                   return -1;
+               }
+           }
+         else
+           {
+             if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
+                 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+               {
+                 sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+                 sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+                 sin_gate.sin_addr = nexthop->gate.ipv4;
+                 rtentry.rt_flags |= RTF_GATEWAY;
+               }
+             if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->type == NEXTHOP_TYPE_IFNAME)
+               {
+                 ifp = if_lookup_by_index (nexthop->ifindex);
+                 if (ifp)
+                   rtentry.rt_dev = ifp->name;
+                 else
+                   return -1;
+               }
+           }
+
+         if (cmd == SIOCADDRT)
+           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+         nexthop_num++;
+         break;
+       }
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("netlink_route_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+ skip:
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+  sin_mask.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_mask.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  masklen2ip (p->prefixlen, &sin_mask.sin_addr);
+
+  /* Set destination address, mask and gateway.*/
+  memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
+
+  if (rtentry.rt_flags & RTF_GATEWAY)
+    memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
+
+#ifndef SUNOS_5
+  memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS_5 */
+
+  /* Metric.  It seems metric minus one value is installed... */
+  rtentry.rt_metric = rib->metric;
+
+  /* Routing entry flag set. */
+  if (p->prefixlen == 32)
+    rtentry.rt_flags |= RTF_HOST;
+
+  rtentry.rt_flags |= RTF_UP;
+
+  /* Additional flags */
+  /* rtentry.rt_flags |= flags; */
+
+  /* For tagging route. */
+  /* rtentry.rt_flags |= RTF_DYNAMIC; */
+
+  /* Open socket for ioctl. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message by ioctl(). */
+  ret = ioctl (sock, cmd, &rtentry);
+  if (ret < 0)
+    {
+      switch (errno) 
+       {
+       case EEXIST:
+         close (sock);
+         return ZEBRA_ERR_RTEXIST;
+         break;
+       case ENETUNREACH:
+         close (sock);
+         return ZEBRA_ERR_RTUNREACH;
+         break;
+       case EPERM:
+         close (sock);
+         return ZEBRA_ERR_EPERM;
+         break;
+       }
+
+      close (sock);
+      zlog_warn ("write : %s (%d)", strerror (errno), errno);
+      return ret;
+    }
+  close (sock);
+
+  return ret;
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
+}
+\f
+#ifdef HAVE_IPV6
+
+/* Below is hack for GNU libc definition and Linux 2.1.X header. */
+#undef RTF_DEFAULT
+#undef RTF_ADDRCONF
+
+#include <asm/types.h>
+
+#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+/* struct in6_rtmsg will be declared in net/route.h. */
+#else
+#include <linux/ipv6_route.h>
+#endif
+
+int
+kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
+                  int index, int flags)
+{
+  int ret;
+  int sock;
+  struct in6_rtmsg rtm;
+    
+  memset (&rtm, 0, sizeof (struct in6_rtmsg));
+
+  rtm.rtmsg_flags |= RTF_UP;
+  rtm.rtmsg_metric = 1;
+  memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
+  rtm.rtmsg_dst_len = dest->prefixlen;
+
+  /* We need link local index. But this should be done caller...
+  if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
+    {
+      index = if_index_address (&rtm.rtmsg_gateway);
+      rtm.rtmsg_ifindex = index;
+    }
+  else
+    rtm.rtmsg_ifindex = 0;
+  */
+
+  rtm.rtmsg_flags |= RTF_GATEWAY;
+
+  /* For tagging route. */
+  /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
+
+  memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
+
+  if (index)
+    rtm.rtmsg_ifindex = index;
+  else
+    rtm.rtmsg_ifindex = 0;
+
+  rtm.rtmsg_metric = 1;
+  
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message via ioctl. */
+  ret = ioctl (sock, type, &rtm);
+  if (ret < 0)
+    {
+      zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", 
+          strerror(errno));
+      ret = errno;
+      close (sock);
+      return ret;
+    }
+  close (sock);
+
+  return ret;
+}
+
+int
+kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
+                            int family)
+{
+  int ret;
+  int sock;
+  struct in6_rtmsg rtm;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+    
+  memset (&rtm, 0, sizeof (struct in6_rtmsg));
+
+  rtm.rtmsg_flags |= RTF_UP;
+  rtm.rtmsg_metric = rib->metric;
+  memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
+  rtm.rtmsg_dst_len = p->prefixlen;
+
+  /* We need link local index. But this should be done caller...
+  if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
+    {
+      index = if_index_address (&rtm.rtmsg_gateway);
+      rtm.rtmsg_ifindex = index;
+    }
+  else
+    rtm.rtmsg_ifindex = 0;
+  */
+
+  rtm.rtmsg_flags |= RTF_GATEWAY;
+
+  /* For tagging route. */
+  /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if ((cmd == SIOCADDRT 
+          && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+         || (cmd == SIOCDELRT
+             && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+       {
+         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+           {
+             if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+               {
+                 memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
+                         sizeof (struct in6_addr));
+               }
+             if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+               rtm.rtmsg_ifindex = nexthop->rifindex;
+             else
+               rtm.rtmsg_ifindex = 0;
+             
+           }
+         else
+           {
+             if (nexthop->type == NEXTHOP_TYPE_IPV6
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+               {
+                 memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
+                         sizeof (struct in6_addr));
+               }
+             if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->type == NEXTHOP_TYPE_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+               rtm.rtmsg_ifindex = nexthop->ifindex;
+             else
+               rtm.rtmsg_ifindex = 0;
+           }
+
+         if (cmd == SIOCADDRT)
+           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+         nexthop_num++;
+         break;
+       }
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("netlink_route_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+  sock = socket (AF_INET6, SOCK_DGRAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("can't make socket\n");
+      return -1;
+    }
+
+  /* Send message via ioctl. */
+  ret = ioctl (sock, cmd, &rtm);
+  if (ret < 0)
+    {
+      zlog_warn ("can't %s ipv6 route: %s\n",
+                cmd == SIOCADDRT ? "add" : "delete", 
+          strerror(errno));
+      ret = errno;
+      close (sock);
+      return ret;
+    }
+  close (sock);
+
+  return ret;
+}
+
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+                   int index, int flags, int table)
+{
+  return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
new file mode 100644 (file)
index 0000000..baca175
--- /dev/null
@@ -0,0 +1,1482 @@
+/* Kernel routing table updates using netlink over GNU/Linux system.
+ * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* Hack for GNU libc version 2. */
+#ifndef MSG_TRUNC
+#define MSG_TRUNC      0x20
+#endif /* MSG_TRUNC */
+
+#include "linklist.h"
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "connected.h"
+#include "table.h"
+#include "rib.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/interface.h"
+#include "zebra/debug.h"
+
+/* Socket interface to kernel */
+struct nlsock
+{
+  int sock;
+  int seq;
+  struct sockaddr_nl snl;
+  char *name;
+} netlink =    { -1, 0, {0}, "netlink-listen" },       /* kernel messages */
+  netlink_cmd = { -1, 0, {0}, "netlink-cmd" },          /* command channel */
+  netlink_addr = {-1, 0, {0}, "netlink-addr" };                /* address channel */
+
+struct message nlmsg_str[] =
+{
+  {RTM_NEWROUTE, "RTM_NEWROUTE"},
+  {RTM_DELROUTE, "RTM_DELROUTE"},
+  {RTM_GETROUTE, "RTM_GETROUTE"},
+  {RTM_NEWLINK,  "RTM_NEWLINK"},
+  {RTM_DELLINK,  "RTM_DELLINK"},
+  {RTM_GETLINK,  "RTM_GETLINK"},
+  {RTM_NEWADDR,  "RTM_NEWADDR"},
+  {RTM_DELADDR,  "RTM_DELADDR"},
+  {RTM_GETADDR,  "RTM_GETADDR"},
+  {0,            NULL}
+};
+
+extern int rtm_table_default;
+
+/* Make socket for Linux netlink interface. */
+static int
+netlink_socket (struct nlsock *nl, unsigned long groups)
+{
+  int ret;
+  struct sockaddr_nl snl;
+  int sock;
+  int namelen;
+
+  sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
+           strerror (errno));
+      return -1;
+    }
+
+  ret = fcntl (sock, F_SETFL, O_NONBLOCK);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
+           strerror (errno));
+      close (sock);
+      return -1;
+    }
+  
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+  snl.nl_groups = groups;
+
+  /* Bind the socket to the netlink structure for anything. */
+  ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", 
+           nl->name, snl.nl_groups, strerror (errno));
+      close (sock);
+      return -1;
+    }
+
+  /* multiple netlink sockets will have different nl_pid */
+  namelen = sizeof snl;
+  ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);
+  if (ret < 0 || namelen != sizeof snl)
+    {
+      zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
+           strerror (errno));
+      close (sock);
+      return -1;
+    }
+
+  nl->snl = snl;
+  nl->sock = sock;
+  return ret;
+}
+
+/* Get type specified information from netlink. */
+static int
+netlink_request (int family, int type, struct nlsock *nl)
+{
+  int ret;
+  struct sockaddr_nl snl;
+
+  struct
+  {
+    struct nlmsghdr nlh;
+    struct rtgenmsg g;
+  } req;
+
+
+  /* Check netlink socket. */
+  if (nl->sock < 0)
+    {
+      zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
+      return -1;
+    }
+
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+
+  req.nlh.nlmsg_len = sizeof req;
+  req.nlh.nlmsg_type = type;
+  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+  req.nlh.nlmsg_pid = 0;
+  req.nlh.nlmsg_seq = ++nl->seq;
+  req.g.rtgen_family = family;
+  ret = sendto (nl->sock, (void*) &req, sizeof req, 0, 
+               (struct sockaddr*) &snl, sizeof snl);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno));
+      return -1;
+    }
+  return 0;
+}
+
+/* Receive message from netlink interface and pass those information
+   to the given function. */
+static int
+netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
+                   struct nlsock *nl)
+{
+  int status;
+  int ret = 0;
+  int error;
+
+  while (1)
+    {
+      char buf[4096];
+      struct iovec iov = { buf, sizeof buf };
+      struct sockaddr_nl snl;
+      struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};
+      struct nlmsghdr *h;
+
+      status = recvmsg (nl->sock, &msg, 0);
+
+      if (status < 0)
+       {
+         if (errno == EINTR)
+           continue;
+         if (errno == EWOULDBLOCK || errno == EAGAIN)
+           break;
+         zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
+         continue;
+       }
+
+      if (status == 0)
+       {
+         zlog (NULL, LOG_ERR, "%s EOF", nl->name);
+         return -1;
+       }
+
+      if (msg.msg_namelen != sizeof snl)
+       {
+         zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
+              nl->name, msg.msg_namelen);
+         return -1;
+       }
+
+      for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status); 
+          h = NLMSG_NEXT (h, status))
+       {
+         /* Finish of reading. */
+         if (h->nlmsg_type == NLMSG_DONE)
+           return ret;
+
+         /* Error handling. */
+         if (h->nlmsg_type == NLMSG_ERROR)
+           {
+             struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
+             
+              /* If the error field is zero, then this is an ACK */
+              if (err->error == 0) 
+                {
+                  if (IS_ZEBRA_DEBUG_KERNEL) 
+                    {  
+                      zlog_info("%s: %s ACK: type=%s(%u), seq=%u, pid=%d", 
+                        __FUNCTION__, nl->name,
+                        lookup (nlmsg_str, err->msg.nlmsg_type),
+                        err->msg.nlmsg_type, err->msg.nlmsg_seq,
+                       err->msg.nlmsg_pid);
+                    }
+                
+                  /* return if not a multipart message, otherwise continue */  
+                  if(!(h->nlmsg_flags & NLM_F_MULTI)) 
+                    { 
+                      return 0;    
+                    }
+                  continue; 
+                }
+              
+              if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
+               {
+                 zlog (NULL, LOG_ERR, "%s error: message truncated",
+                       nl->name);
+                 return -1;
+               }
+             zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d",
+                   nl->name, strerror (-err->error),
+                   lookup (nlmsg_str, err->msg.nlmsg_type),
+                   err->msg.nlmsg_type, err->msg.nlmsg_seq,
+                   err->msg.nlmsg_pid);
+             /*
+             ret = -1;
+             continue;
+             */
+             return -1;
+           }
+
+         /* OK we got netlink message. */
+         if (IS_ZEBRA_DEBUG_KERNEL)
+           zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
+                     nl->name,
+                     lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
+                     h->nlmsg_seq, h->nlmsg_pid);
+
+         /* skip unsolicited messages originating from command socket */
+         if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
+           {
+             if (IS_ZEBRA_DEBUG_KERNEL)
+               zlog_info ("netlink_parse_info: %s packet comes from %s",
+                         nl->name, netlink_cmd.name);
+             continue;
+           }
+
+         error = (*filter) (&snl, h);
+         if (error < 0)
+           {
+             zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
+             ret = error;
+           }
+       }
+
+      /* After error care. */
+      if (msg.msg_flags & MSG_TRUNC)
+       {
+         zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
+         continue;
+       }
+      if (status)
+       {
+         zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
+               status);
+         return -1;
+       }
+    }
+  return ret;
+}
+
+/* Utility function for parse rtattr. */
+static void
+netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len)
+{
+  while (RTA_OK(rta, len)) 
+    {
+      if (rta->rta_type <= max)
+       tb[rta->rta_type] = rta;
+      rta = RTA_NEXT(rta,len);
+    }
+}
+
+/* Called from interface_lookup_netlink().  This function is only used
+   during bootstrap. */
+int
+netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct ifinfomsg *ifi;
+  struct rtattr *tb[IFLA_MAX + 1];
+  struct interface *ifp;
+  char *name;
+  int i;
+
+  ifi = NLMSG_DATA (h);
+
+  if (h->nlmsg_type != RTM_NEWLINK)
+    return 0;
+
+  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
+  if (len < 0)
+    return -1;
+
+  /* Looking up interface name. */
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+  if (tb[IFLA_IFNAME] == NULL)
+    return -1;
+  name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+
+  /* Add interface. */
+  ifp = if_get_by_name (name);
+  
+  ifp->ifindex = ifi->ifi_index;
+  ifp->flags = ifi->ifi_flags & 0x0000fffff;
+  ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+  ifp->metric = 1;
+
+  /* Hardware type and address. */
+  ifp->hw_type = ifi->ifi_type;
+
+  if (tb[IFLA_ADDRESS])
+    {
+      int hw_addr_len;
+
+      hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+
+      if (hw_addr_len > INTERFACE_HWADDR_MAX)
+       zlog_warn ("Hardware address is too large: %d", hw_addr_len);
+      else
+       {      
+         ifp->hw_addr_len = hw_addr_len;
+         memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len);
+
+         for (i = 0; i < hw_addr_len; i++)
+           if (ifp->hw_addr[i] != 0)
+             break;
+
+         if (i == hw_addr_len)
+           ifp->hw_addr_len = 0;
+         else
+           ifp->hw_addr_len = hw_addr_len;
+       }
+    }
+
+  if_add_update (ifp);
+
+  return 0;
+}
+
+/* Lookup interface IPv4/IPv6 address. */
+int
+netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct ifaddrmsg *ifa;
+  struct rtattr *tb [IFA_MAX + 1];
+  struct interface *ifp;
+  void *addr = NULL;
+  void *broad = NULL;
+  u_char flags = 0;
+  char *label = NULL;
+
+  ifa = NLMSG_DATA (h);
+
+  if (ifa->ifa_family != AF_INET 
+#ifdef HAVE_IPV6
+      && ifa->ifa_family != AF_INET6
+#endif /* HAVE_IPV6 */
+      )
+    return 0;
+
+  if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
+    return 0;
+
+  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg));
+  if (len < 0)
+    return -1;
+
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
+
+  ifp = if_lookup_by_index (ifa->ifa_index);
+  if (ifp == NULL)
+    {
+      zlog_err ("netlink_interface_addr can't find interface by index %d",
+               ifa->ifa_index);
+      return -1;
+    }
+
+  if (tb[IFA_ADDRESS] == NULL)
+    tb[IFA_ADDRESS] = tb[IFA_LOCAL];
+
+  if (ifp->flags & IFF_POINTOPOINT)
+    {
+      if (tb[IFA_LOCAL])
+       {
+         addr = RTA_DATA (tb[IFA_LOCAL]);
+         if (tb[IFA_ADDRESS]) 
+           broad = RTA_DATA (tb[IFA_ADDRESS]);
+         else
+           broad = NULL;
+       }
+      else
+       {
+         if (tb[IFA_ADDRESS])
+           addr = RTA_DATA (tb[IFA_ADDRESS]);
+         else
+           addr = NULL;
+       }
+    }
+  else
+    {
+      if (tb[IFA_ADDRESS])
+       addr = RTA_DATA (tb[IFA_ADDRESS]);
+      else
+       addr = NULL;
+
+      if (tb[IFA_BROADCAST])
+       broad = RTA_DATA(tb[IFA_BROADCAST]);
+      else
+       broad = NULL;
+    }
+
+  /* Flags. */
+  if (ifa->ifa_flags & IFA_F_SECONDARY)
+    SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
+
+  /* Label */
+  if (tb[IFA_LABEL])
+    label = (char *) RTA_DATA (tb[IFA_LABEL]);
+
+  if (ifp && label && strcmp (ifp->name, label) == 0)
+    label = NULL;
+
+  /* Register interface address to the interface. */
+  if (ifa->ifa_family == AF_INET)
+    {
+      if (h->nlmsg_type == RTM_NEWADDR) 
+       connected_add_ipv4 (ifp, flags,
+                           (struct in_addr *) addr, ifa->ifa_prefixlen, 
+                           (struct in_addr *) broad, label);
+      else 
+       connected_delete_ipv4 (ifp, flags,
+                              (struct in_addr *) addr, ifa->ifa_prefixlen, 
+                              (struct in_addr *) broad, label);
+    }
+#ifdef HAVE_IPV6
+  if (ifa->ifa_family == AF_INET6)
+    {
+      if (h->nlmsg_type == RTM_NEWADDR)
+       connected_add_ipv6 (ifp, 
+                           (struct in6_addr *) addr, ifa->ifa_prefixlen, 
+                           (struct in6_addr *) broad);
+      else
+       connected_delete_ipv6 (ifp, 
+                              (struct in6_addr *) addr, ifa->ifa_prefixlen, 
+                              (struct in6_addr *) broad);
+    }
+#endif /* HAVE_IPV6*/
+
+  return 0;
+}
+
+/* Looking up routing table by netlink interface. */
+int
+netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct rtmsg *rtm;
+  struct rtattr *tb [RTA_MAX + 1];
+  u_char flags = 0;
+  
+  char anyaddr[16] = {0};
+
+  int index;
+  int table;
+  void *dest;
+  void *gate;
+
+  rtm = NLMSG_DATA (h);
+
+  if (h->nlmsg_type != RTM_NEWROUTE)
+    return 0;
+  if (rtm->rtm_type != RTN_UNICAST)
+    return 0;
+
+  table = rtm->rtm_table;
+#if 0          /* we weed them out later in rib_weed_tables () */
+  if (table != RT_TABLE_MAIN && table != rtm_table_default)
+    return 0;
+#endif
+
+  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
+  if (len < 0)
+    return -1;
+
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+  if (rtm->rtm_flags & RTM_F_CLONED)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_REDIRECT)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_KERNEL)
+    return 0;
+
+  if (rtm->rtm_src_len != 0)
+    return 0;
+
+  /* Route which inserted by Zebra. */
+  if (rtm->rtm_protocol == RTPROT_ZEBRA)
+    flags |= ZEBRA_FLAG_SELFROUTE;
+  
+  index = 0;
+  dest = NULL;
+  gate = NULL;
+
+  if (tb[RTA_OIF])
+    index = *(int *) RTA_DATA (tb[RTA_OIF]);
+
+  if (tb[RTA_DST])
+    dest = RTA_DATA (tb[RTA_DST]);
+  else
+    dest = anyaddr;
+
+  /* Multipath treatment is needed. */
+  if (tb[RTA_GATEWAY])
+    gate = RTA_DATA (tb[RTA_GATEWAY]);
+
+  if (rtm->rtm_family == AF_INET)
+    {
+      struct prefix_ipv4 p;
+      p.family = AF_INET;
+      memcpy (&p.prefix, dest, 4);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0);
+    }
+#ifdef HAVE_IPV6
+  if (rtm->rtm_family == AF_INET6)
+    {
+      struct prefix_ipv6 p;
+      p.family = AF_INET6;
+      memcpy (&p.prefix, dest, 16);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
+    }
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+struct message rtproto_str [] = 
+{
+  {RTPROT_REDIRECT, "redirect"},
+  {RTPROT_KERNEL,   "kernel"},
+  {RTPROT_BOOT,     "boot"},
+  {RTPROT_STATIC,   "static"},
+  {RTPROT_GATED,    "GateD"},
+  {RTPROT_RA,       "router advertisement"},
+  {RTPROT_MRT,      "MRT"},
+  {RTPROT_ZEBRA,    "Zebra"},
+#ifdef RTPROT_BIRD
+  {RTPROT_BIRD,     "BIRD"},
+#endif /* RTPROT_BIRD */
+  {0,               NULL}
+};
+
+/* Routing information change from the kernel. */
+int
+netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct rtmsg *rtm;
+  struct rtattr *tb [RTA_MAX + 1];
+  
+  char anyaddr[16] = {0};
+
+  int index;
+  int table;
+  void *dest;
+  void *gate;
+
+  rtm = NLMSG_DATA (h);
+
+  if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
+    {
+      /* If this is not route add/delete message print warning. */
+      zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
+      return 0;
+    }
+
+  /* Connected route. */
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_info ("%s %s %s proto %s",
+              h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
+              rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
+              rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
+              lookup (rtproto_str, rtm->rtm_protocol));
+
+  if (rtm->rtm_type != RTN_UNICAST)
+    {
+      return 0;
+    }
+
+  table = rtm->rtm_table;
+  if (table != RT_TABLE_MAIN && table != rtm_table_default)
+    {
+      return 0;
+    }
+
+  len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
+  if (len < 0)
+    return -1;
+
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+  if (rtm->rtm_flags & RTM_F_CLONED)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_REDIRECT)
+    return 0;
+  if (rtm->rtm_protocol == RTPROT_KERNEL)
+    return 0;
+
+  if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
+    return 0;
+
+  if (rtm->rtm_src_len != 0)
+    {
+      zlog_warn ("netlink_route_change(): no src len");
+      return 0;
+    }
+  
+  index = 0;
+  dest = NULL;
+  gate = NULL;
+
+  if (tb[RTA_OIF])
+    index = *(int *) RTA_DATA (tb[RTA_OIF]);
+
+  if (tb[RTA_DST])
+    dest = RTA_DATA (tb[RTA_DST]);
+  else
+    dest = anyaddr;
+
+  if (tb[RTA_GATEWAY])
+    gate = RTA_DATA (tb[RTA_GATEWAY]);
+
+  if (rtm->rtm_family == AF_INET)
+    {
+      struct prefix_ipv4 p;
+      p.family = AF_INET;
+      memcpy (&p.prefix, dest, 4);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       {
+         if (h->nlmsg_type == RTM_NEWROUTE)
+           zlog_info ("RTM_NEWROUTE %s/%d",
+                      inet_ntoa (p.prefix), p.prefixlen);
+         else
+           zlog_info ("RTM_DELROUTE %s/%d",
+                      inet_ntoa (p.prefix), p.prefixlen);
+       }
+
+      if (h->nlmsg_type == RTM_NEWROUTE)
+       rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+      else
+       rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+    }
+
+#ifdef HAVE_IPV6
+  if (rtm->rtm_family == AF_INET6)
+    {
+      struct prefix_ipv6 p;
+      char buf[BUFSIZ];
+
+      p.family = AF_INET6;
+      memcpy (&p.prefix, dest, 16);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       {
+         if (h->nlmsg_type == RTM_NEWROUTE)
+           zlog_info ("RTM_NEWROUTE %s/%d",
+                      inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
+                      p.prefixlen);
+         else
+           zlog_info ("RTM_DELROUTE %s/%d",
+                      inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
+                      p.prefixlen);
+       }
+
+      if (h->nlmsg_type == RTM_NEWROUTE)
+       rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+      else
+       rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+    }
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+int
+netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  int len;
+  struct ifinfomsg *ifi;
+  struct rtattr *tb [IFLA_MAX + 1];
+  struct interface *ifp;
+  char *name;
+
+  ifi = NLMSG_DATA (h);
+
+  if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
+    {
+      /* If this is not link add/delete message so print warning. */
+      zlog_warn ("netlink_link_change: wrong kernel message %d\n",
+                h->nlmsg_type);
+      return 0;
+    }
+
+  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
+  if (len < 0)
+    return -1;
+
+  /* Looking up interface name. */
+  memset (tb, 0, sizeof tb);
+  netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
+  if (tb[IFLA_IFNAME] == NULL)
+    return -1;
+  name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+
+  /* Add interface. */
+  if (h->nlmsg_type == RTM_NEWLINK)
+    {
+      ifp = if_lookup_by_name (name);
+
+      if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+       {
+         if (ifp == NULL)
+           ifp = if_get_by_name (name);
+
+         ifp->ifindex = ifi->ifi_index;
+         ifp->flags = ifi->ifi_flags & 0x0000fffff;
+         ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+         ifp->metric = 1;
+
+         /* If new link is added. */
+         if_add_update(ifp);
+       }      
+      else
+       {
+         /* Interface status change. */
+         ifp->ifindex = ifi->ifi_index;
+         ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
+         ifp->metric = 1;
+
+         if (if_is_up (ifp))
+           {
+             ifp->flags = ifi->ifi_flags & 0x0000fffff;
+             if (! if_is_up (ifp))
+               if_down (ifp);
+           }
+         else
+           {
+             ifp->flags = ifi->ifi_flags & 0x0000fffff;
+             if (if_is_up (ifp))
+               if_up (ifp);
+           }
+       }
+    }
+  else
+    {
+      /* RTM_DELLINK. */
+      ifp = if_lookup_by_name (name);
+
+      if (ifp == NULL)
+       {
+         zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
+                name);
+         return 0;
+       }
+      
+      if_delete_update (ifp);
+    }
+
+  return 0;
+}
+
+int
+netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  switch (h->nlmsg_type)
+    {
+    case RTM_NEWROUTE:
+      return netlink_route_change (snl, h);
+      break;
+    case RTM_DELROUTE:
+      return netlink_route_change (snl, h);
+      break;
+    case RTM_NEWLINK:
+      return netlink_link_change (snl, h);
+      break;
+    case RTM_DELLINK:
+      return netlink_link_change (snl, h);
+      break;
+    case RTM_NEWADDR:
+      return netlink_interface_addr (snl, h);
+      break;
+    case RTM_DELADDR:
+      return netlink_interface_addr (snl, h);
+      break;
+    default:
+      zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
+      break;
+    }
+  return 0;
+}
+
+/* Interface lookup by netlink socket. */
+int
+interface_lookup_netlink ()
+{
+  int ret;
+
+  /* Get interface information. */
+  ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+
+  /* Get IPv4 address of the interfaces. */
+  ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+
+#ifdef HAVE_IPV6
+  /* Get IPv6 address of the interfaces. */
+  ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+/* Routing table read function using netlink interface.  Only called
+   bootstrap time. */
+int
+netlink_route_read ()
+{
+  int ret;
+
+  /* Get IPv4 routing table. */
+  ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+
+#ifdef HAVE_IPV6
+  /* Get IPv6 routing table. */
+  ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+  if (ret < 0)
+    return ret;
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+/* Utility function  comes from iproute2. 
+   Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
+int
+addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
+{
+  int len;
+  struct rtattr *rta;
+
+  len = RTA_LENGTH(alen);
+
+  if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
+    return -1;
+
+  rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
+  rta->rta_type = type;
+  rta->rta_len = len;
+  memcpy (RTA_DATA(rta), data, alen);
+  n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+  return 0;
+}
+
+int
+rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
+{
+  int len;
+  struct rtattr *subrta;
+
+  len = RTA_LENGTH(alen);
+
+  if (RTA_ALIGN(rta->rta_len) + len > maxlen)
+    return -1;
+
+  subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len));
+  subrta->rta_type = type;
+  subrta->rta_len = len;
+  memcpy (RTA_DATA(subrta), data, alen);
+  rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
+
+  return 0;
+}
+
+/* Utility function comes from iproute2. 
+   Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
+int
+addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
+{
+  int len;
+  struct rtattr *rta;
+  
+  len = RTA_LENGTH(4);
+  
+  if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
+    return -1;
+
+  rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
+  rta->rta_type = type;
+  rta->rta_len = len;
+  memcpy (RTA_DATA(rta), &data, 4);
+  n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+  return 0;
+}
+
+static int
+netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
+{
+  zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
+  return 0;
+}
+
+/* sendmsg() to netlink socket then recvmsg(). */
+int
+netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
+{
+  int status;
+  struct sockaddr_nl snl;
+  struct iovec iov = { (void*) n, n->nlmsg_len };
+  struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
+  int flags = 0;
+  
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+  
+  n->nlmsg_seq = ++netlink_cmd.seq;
+
+  /* Request an acknowledgement by setting NLM_F_ACK */
+  n->nlmsg_flags |= NLM_F_ACK;
+  
+  if (IS_ZEBRA_DEBUG_KERNEL) 
+    zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
+             lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
+             n->nlmsg_seq);
+
+  /* Send message to netlink interface. */
+  status = sendmsg (nl->sock, &msg, 0);
+  if (status < 0)
+    {
+      zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
+           strerror (errno));
+      return -1;
+    }
+  
+  /* 
+   * Change socket flags for blocking I/O. 
+   * This ensures we wait for a reply in netlink_parse_info().
+   */
+  if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) 
+    {
+      zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", 
+              __FUNCTION__, __LINE__, strerror (errno));
+    }
+  flags &= ~O_NONBLOCK;
+  if(fcntl(nl->sock, F_SETFL, flags) < 0) 
+    {
+      zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", 
+              __FUNCTION__, __LINE__, strerror (errno));
+    }
+
+  /* 
+   * Get reply from netlink socket. 
+   * The reply should either be an acknowlegement or an error.
+   */
+  status = netlink_parse_info (netlink_talk_filter, nl);
+  
+  /* Restore socket flags for nonblocking I/O */
+  flags |= O_NONBLOCK;
+  if(fcntl(nl->sock, F_SETFL, flags) < 0) 
+    {
+      zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", 
+              __FUNCTION__, __LINE__, strerror (errno));
+    }
+  
+  return status;
+}
+
+/* Routing table change via netlink interface. */
+int
+netlink_route (int cmd, int family, void *dest, int length, void *gate,
+              int index, int zebra_flags, int table)
+{
+  int ret;
+  int bytelen;
+  struct sockaddr_nl snl;
+  int discard;
+
+  struct 
+  {
+    struct nlmsghdr n;
+    struct rtmsg r;
+    char buf[1024];
+  } req;
+
+  memset (&req, 0, sizeof req);
+
+  bytelen = (family == AF_INET ? 4 : 16);
+
+  req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+  req.n.nlmsg_type = cmd;
+  req.r.rtm_family = family;
+  req.r.rtm_table = table;
+  req.r.rtm_dst_len = length;
+
+  if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
+    discard = 1;
+  else
+    discard = 0;
+
+  if (cmd == RTM_NEWROUTE) 
+    {
+      req.r.rtm_protocol = RTPROT_ZEBRA;
+      req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+
+      if (discard)
+       req.r.rtm_type = RTN_BLACKHOLE;
+      else
+       req.r.rtm_type = RTN_UNICAST;
+    }
+
+  if (dest)
+    addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
+
+  if (! discard)
+    {
+      if (gate)
+       addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
+      if (index > 0)
+       addattr32 (&req.n, sizeof req, RTA_OIF, index);
+    }
+
+  /* Destination netlink address. */
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+
+  /* Talk to netlink socket. */
+  ret = netlink_talk (&req.n, &netlink);
+  if (ret < 0)
+    return -1;
+
+  return 0;
+}
+
+/* Routing table change via netlink interface. */
+int
+netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
+                        int family)
+{
+  int bytelen;
+  struct sockaddr_nl snl;
+  struct nexthop *nexthop = NULL;
+  int nexthop_num = 0;
+  struct nlsock *nl;
+  int discard;
+
+  struct 
+  {
+    struct nlmsghdr n;
+    struct rtmsg r;
+    char buf[1024];
+  } req;
+
+  memset (&req, 0, sizeof req);
+
+  bytelen = (family == AF_INET ? 4 : 16);
+
+  req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+  req.n.nlmsg_type = cmd;
+  req.r.rtm_family = family;
+  req.r.rtm_table = rib->table;
+  req.r.rtm_dst_len = p->prefixlen;
+
+  if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
+    discard = 1;
+  else
+    discard = 0;
+
+  if (cmd == RTM_NEWROUTE) 
+    {
+      req.r.rtm_protocol = RTPROT_ZEBRA;
+      req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+
+      if (discard)
+       req.r.rtm_type = RTN_BLACKHOLE;
+      else
+       req.r.rtm_type = RTN_UNICAST;
+    }
+
+  addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
+
+  /* Metric. */
+  addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
+
+  if (discard)
+    {
+      if (cmd == RTM_NEWROUTE)
+       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+         SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+      goto skip;
+    }
+
+  /* Multipath case. */
+  if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
+    {
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       {
+         if ((cmd == RTM_NEWROUTE 
+              && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+             || (cmd == RTM_DELROUTE
+                 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+           {
+             if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+               {
+                 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+                   addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+                              &nexthop->rgate.ipv4, bytelen);
+#ifdef HAVE_IPV6
+                 if (nexthop->rtype == NEXTHOP_TYPE_IPV6 
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX 
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+                   addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+                              &nexthop->rgate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+                 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                     || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+                   addattr32 (&req.n, sizeof req, RTA_OIF,
+                              nexthop->rifindex);
+               }
+             else
+               {
+                 if (nexthop->type == NEXTHOP_TYPE_IPV4 
+                     || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+                   addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+                              &nexthop->gate.ipv4, bytelen);
+#ifdef HAVE_IPV6
+                 if (nexthop->type == NEXTHOP_TYPE_IPV6 
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+                   addattr_l (&req.n, sizeof req, RTA_GATEWAY,
+                              &nexthop->gate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+                 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+                     || nexthop->type == NEXTHOP_TYPE_IFNAME
+                     || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+                   addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
+               }
+
+             if (cmd == RTM_NEWROUTE)
+               SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+             nexthop_num++;
+             break;
+           }
+       }
+    }
+  else
+    {
+      char buf[1024];
+      struct rtattr *rta = (void *) buf;
+      struct rtnexthop *rtnh;
+
+      rta->rta_type = RTA_MULTIPATH;
+      rta->rta_len = RTA_LENGTH(0);
+      rtnh = RTA_DATA(rta);
+
+      nexthop_num = 0;
+      for (nexthop = rib->nexthop;
+          nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
+          nexthop = nexthop->next)
+       {
+         if ((cmd == RTM_NEWROUTE 
+              && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+             || (cmd == RTM_DELROUTE
+                 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
+           {
+             nexthop_num++;
+
+             rtnh->rtnh_len = sizeof (*rtnh);
+             rtnh->rtnh_flags = 0;
+             rtnh->rtnh_hops = 0;
+             rta->rta_len += rtnh->rtnh_len;
+
+             if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+               {
+                 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+                   {
+                     rta_addattr_l (rta, 4096, RTA_GATEWAY,
+                                    &nexthop->rgate.ipv4, bytelen);
+                     rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+                   }
+#ifdef HAVE_IPV6
+                 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+                   rta_addattr_l (rta, 4096, RTA_GATEWAY,
+                                  &nexthop->rgate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+                 /* ifindex */
+                 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                     || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+                     || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
+                   rtnh->rtnh_ifindex = nexthop->rifindex;
+                 else
+                   rtnh->rtnh_ifindex = 0;
+               }
+             else
+               {
+                 if (nexthop->type == NEXTHOP_TYPE_IPV4
+                     || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+                   {
+                     rta_addattr_l (rta, 4096, RTA_GATEWAY,
+                                    &nexthop->gate.ipv4, bytelen);
+                     rtnh->rtnh_len += sizeof (struct rtattr) + 4;
+                   }
+#ifdef HAVE_IPV6
+                 if (nexthop->type == NEXTHOP_TYPE_IPV6
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+                   rta_addattr_l (rta, 4096, RTA_GATEWAY,
+                                  &nexthop->gate.ipv6, bytelen);
+#endif /* HAVE_IPV6 */
+                 /* ifindex */
+                 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+                     || nexthop->type == NEXTHOP_TYPE_IFNAME
+                     || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                     || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+                   rtnh->rtnh_ifindex = nexthop->ifindex;
+                 else
+                   rtnh->rtnh_ifindex = 0;
+               }
+             rtnh = RTNH_NEXT(rtnh);
+
+             if (cmd == RTM_NEWROUTE)
+               SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+           }
+       }
+
+      if (rta->rta_len > RTA_LENGTH (0))
+       addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta),
+                  RTA_PAYLOAD(rta));
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("netlink_route_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+ skip:
+
+  /* Destination netlink address. */
+  memset (&snl, 0, sizeof snl);
+  snl.nl_family = AF_NETLINK;
+
+  if (family == AF_INET)
+    nl = &netlink_cmd;
+  else
+    nl = &netlink;
+
+  /* Talk to netlink socket. */
+  return netlink_talk (&req.n, nl);
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+                       int index, int flags, int table)
+{
+  return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, dest->prefixlen,
+                       gate, index, flags, table);
+}
+#endif /* HAVE_IPV6 */
+\f
+/* Interface address modification. */
+int
+netlink_address (int cmd, int family, struct interface *ifp,
+                struct connected *ifc)
+{
+  int bytelen;
+  struct prefix *p;
+
+  struct 
+  {
+    struct nlmsghdr n;
+    struct ifaddrmsg ifa;
+    char buf[1024];
+  } req;
+
+  p = ifc->address;
+  memset (&req, 0, sizeof req);
+
+  bytelen = (family == AF_INET ? 4 : 16);
+
+  req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ifaddrmsg));
+  req.n.nlmsg_flags = NLM_F_REQUEST;
+  req.n.nlmsg_type = cmd;
+  req.ifa.ifa_family = family;
+
+  req.ifa.ifa_index = ifp->ifindex;
+  req.ifa.ifa_prefixlen = p->prefixlen;
+
+  addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
+
+  if (family == AF_INET && cmd == RTM_NEWADDR)
+    {
+      if (if_is_broadcast (ifp) && ifc->destination)
+       {
+         p = ifc->destination;
+         addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen);
+       }
+    }
+
+  if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
+    SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
+    
+  if (ifc->label)
+    addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
+              strlen (ifc->label) + 1);
+
+  return netlink_talk (&req.n, &netlink_cmd);
+}
+
+int
+kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
+}
+
+int
+kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+  return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
+}
+
+#include "thread.h"
+
+extern struct thread_master *master;
+
+/* Kernel route reflection. */
+int
+kernel_read (struct thread *thread)
+{
+  int ret;
+  int sock;
+
+  sock = THREAD_FD (thread);
+  ret = netlink_parse_info (netlink_information_fetch, &netlink);
+  thread_add_read (master, kernel_read, NULL, netlink.sock);
+
+  return 0;
+}
+
+/* Exported interface function.  This function simply calls
+   netlink_socket (). */
+void
+kernel_init ()
+{
+  unsigned long groups;
+
+  groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR;
+#ifdef HAVE_IPV6
+  groups |= RTMGRP_IPV6_ROUTE|RTMGRP_IPV6_IFADDR;
+#endif /* HAVE_IPV6 */
+  netlink_socket (&netlink, groups);
+  netlink_socket (&netlink_cmd, 0);
+
+  /* Register kernel socket. */
+  if (netlink.sock > 0)
+    thread_add_read (master, kernel_read, NULL, netlink.sock);
+}
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
new file mode 100644 (file)
index 0000000..fe88be8
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Kernel routing table updates by routing socket.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "sockunion.h"
+#include "log.h"
+#include "str.h"
+
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+
+int
+rtm_write (int message,
+          union sockunion *dest,
+          union sockunion *mask,
+          union sockunion *gate,
+          unsigned int index,
+          int zebra_flags,
+          int metric);
+
+/* Adjust netmask socket length. Return value is a adjusted sin_len
+   value. */
+int
+sin_masklen (struct in_addr mask)
+{
+  char *p, *lim;
+  int len;
+  struct sockaddr_in sin;
+
+  if (mask.s_addr == 0) 
+    return sizeof (long);
+
+  sin.sin_addr = mask;
+  len = sizeof (struct sockaddr_in);
+
+  lim = (char *) &sin.sin_addr;
+  p = lim + sizeof (sin.sin_addr);
+
+  while (*--p == 0 && p >= lim) 
+    len--;
+  return len;
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
+
+{
+  struct sockaddr_in *mask;
+  struct sockaddr_in sin_dest, sin_mask, sin_gate;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+  unsigned int ifindex = 0;
+  int gate = 0;
+  int error;
+
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+  sin_dest.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_dest.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  sin_dest.sin_addr = p->u.prefix4;
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in));
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in));
+  sin_gate.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin_gate.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      gate = 0;
+
+      if ((cmd == RTM_ADD
+          && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+         || (cmd == RTM_DELETE
+#if 0
+             && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+#endif
+             ))
+       {
+         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+           {
+             if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
+                 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+               {
+                 sin_gate.sin_addr = nexthop->rgate.ipv4;
+                 gate = 1;
+               }
+             if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
+               ifindex = nexthop->rifindex;
+           }
+         else
+           {
+             if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
+                 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+               {
+                 sin_gate.sin_addr = nexthop->gate.ipv4;
+                 gate = 1;
+               }
+             if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->type == NEXTHOP_TYPE_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+               ifindex = nexthop->ifindex;
+             if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
+               {
+                 struct in_addr loopback;
+
+                 loopback.s_addr = htonl (INADDR_LOOPBACK);
+                 sin_gate.sin_addr = loopback;
+                 gate = 1;
+               }
+           }
+
+         if (cmd == RTM_ADD)
+           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+         if (gate && p->prefixlen == 32)
+           mask = NULL;
+         else
+           {
+             masklen2ip (p->prefixlen, &sin_mask.sin_addr);
+             sin_mask.sin_family = AF_UNSPEC;
+#ifdef HAVE_SIN_LEN
+             sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
+#endif /* HAVE_SIN_LEN */
+             mask = &sin_mask;
+           }
+       }
+
+      error = rtm_write (cmd,
+                       (union sockunion *)&sin_dest, 
+                       (union sockunion *)mask, 
+                       gate ? (union sockunion *)&sin_gate : NULL,
+                       ifindex,
+                       rib->flags,
+                       rib->metric);
+
+#if 0
+      if (error)
+       {
+         zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
+           nexthop_num, error);
+       }
+#endif
+
+      nexthop_num++;
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
+      return 0;
+    }
+
+  return 0; /*XXX*/
+}
+
+int
+kernel_add_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
+}
+
+int
+kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
+}
+
+#ifdef HAVE_IPV6
+
+/* Calculate sin6_len value for netmask socket value. */
+int
+sin6_masklen (struct in6_addr mask)
+{
+  struct sockaddr_in6 sin6;
+  char *p, *lim;
+  int len;
+
+#if defined (INRIA)
+  if (IN_ANYADDR6 (mask)) 
+    return sizeof (long);
+#else /* ! INRIA */
+  if (IN6_IS_ADDR_UNSPECIFIED (&mask)) 
+    return sizeof (long);
+#endif /* ! INRIA */
+
+  sin6.sin6_addr = mask;
+  len = sizeof (struct sockaddr_in6);
+
+  lim = (char *) & sin6.sin6_addr;
+  p = lim + sizeof (sin6.sin6_addr);
+
+  while (*--p == 0 && p >= lim) 
+    len--;
+
+  return len;
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
+                struct in6_addr *gate, int index, int flags)
+{
+  struct sockaddr_in6 *mask;
+  struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
+  sin_dest.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  sin_dest.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
+  sin_gate.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  sin_gate.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+
+  sin_dest.sin6_addr = dest->prefix;
+
+  if (gate)
+    memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
+
+  /* Under kame set interface index to link local address. */
+#ifdef KAME
+
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+  do { \
+    (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+    (a).s6_addr[3] = (i) & 0xff; \
+  } while (0)
+
+  if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
+    SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
+#endif /* KAME */
+
+  if (gate && dest->prefixlen == 128)
+    mask = NULL;
+  else
+    {
+      masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
+      sin_mask.sin6_family = AF_UNSPEC;
+#ifdef SIN6_LEN
+      sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
+#endif /* SIN6_LEN */
+      mask = &sin_mask;
+    }
+
+  return rtm_write (message, 
+                   (union sockunion *) &sin_dest,
+                   (union sockunion *) mask,
+                   gate ? (union sockunion *)&sin_gate : NULL,
+                   index,
+                   flags,
+                   0);
+}
+
+/* Interface between zebra message and rtm message. */
+int
+kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
+                          int family)
+{
+  struct sockaddr_in6 *mask;
+  struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+  struct nexthop *nexthop;
+  int nexthop_num = 0;
+  unsigned int ifindex = 0;
+  int gate = 0;
+  int error;
+
+  memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
+  sin_dest.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  sin_dest.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  sin_dest.sin6_addr = p->u.prefix6;
+
+  memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
+
+  memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
+  sin_gate.sin6_family = AF_INET6;
+#ifdef HAVE_SIN_LEN
+  sin_gate.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* HAVE_SIN_LEN */
+
+  /* Make gateway. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      gate = 0;
+
+      if ((cmd == RTM_ADD
+          && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+         || (cmd == RTM_DELETE
+#if 0
+             && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+#endif
+             ))
+       {
+         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+           {
+             if (nexthop->rtype == NEXTHOP_TYPE_IPV6
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+               {
+                 sin_gate.sin6_addr = nexthop->rgate.ipv6;
+                 gate = 1;
+               }
+             if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+               ifindex = nexthop->rifindex;
+           }
+         else
+           {
+             if (nexthop->type == NEXTHOP_TYPE_IPV6
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+               {
+                 sin_gate.sin6_addr = nexthop->gate.ipv6;
+                 gate = 1;
+               }
+             if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+                 || nexthop->type == NEXTHOP_TYPE_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+               ifindex = nexthop->ifindex;
+           }
+
+         if (cmd == RTM_ADD)
+           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+       }
+
+      /* Under kame set interface index to link local address. */
+#ifdef KAME
+
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+      do { \
+       (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+       (a).s6_addr[3] = (i) & 0xff; \
+      } while (0)
+
+      if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
+       SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
+#endif /* KAME */
+
+      if (gate && p->prefixlen == 128)
+       mask = NULL;
+      else
+       {
+         masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
+         sin_mask.sin6_family = AF_UNSPEC;
+#ifdef SIN6_LEN
+         sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
+#endif /* SIN6_LEN */
+         mask = &sin_mask;
+       }
+
+      error = rtm_write (cmd,
+                       (union sockunion *) &sin_dest,
+                       (union sockunion *) mask,
+                       gate ? (union sockunion *)&sin_gate : NULL,
+                       ifindex,
+                       rib->flags,
+                       rib->metric);
+
+#if 0
+      if (error)
+       {
+         zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
+           nexthop_num, error);
+       }
+#endif
+
+      nexthop_num++;
+    }
+
+  /* If there is no useful nexthop then return. */
+  if (nexthop_num == 0)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
+      return 0;
+    }
+
+  return 0; /*XXX*/
+}
+
+int
+kernel_add_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
+}
+
+int
+kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
+}
+
+/* Delete IPv6 route from the kernel. */
+int
+kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+                   int index, int flags, int table)
+{
+  return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
+}
+#endif /* HAVE_IPV6 */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
new file mode 100644 (file)
index 0000000..8f4b377
--- /dev/null
@@ -0,0 +1,1112 @@
+/* Router advertisement
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "sockopt.h"
+#include "thread.h"
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "command.h"
+
+#include "zebra/interface.h"
+#include "zebra/rtadv.h"
+#include "zebra/debug.h"
+
+#if defined (HAVE_IPV6) && defined (RTADV)
+
+/* If RFC2133 definition is used. */
+#ifndef IPV6_JOIN_GROUP
+#define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP 
+#endif
+#ifndef IPV6_LEAVE_GROUP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP 
+#endif
+
+#define ALLNODE   "ff02::1"
+#define ALLROUTER "ff02::2"
+
+enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ};
+
+void rtadv_event (enum rtadv_event, int);
+
+int if_join_all_router (int, struct interface *);
+int if_leave_all_router (int, struct interface *);
+\f
+/* Structure which hold status of router advertisement. */
+struct rtadv
+{
+  int sock;
+
+  int adv_if_count;
+
+  struct thread *ra_read;
+  struct thread *ra_timer;
+};
+
+struct rtadv *rtadv = NULL;
+\f
+struct rtadv *
+rtadv_new ()
+{
+  struct rtadv *new;
+  new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
+  memset (new, 0, sizeof (struct rtadv));
+  return new;
+}
+
+void
+rtadv_free (struct rtadv *rtadv)
+{
+  XFREE (MTYPE_TMP, rtadv);
+}
+
+int
+rtadv_recv_packet (int sock, u_char *buf, int buflen,
+                  struct sockaddr_in6 *from, unsigned int *ifindex,
+                  int *hoplimit)
+{
+  int ret;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr  *cmsgptr;
+  struct in6_addr dst;
+
+  char adata[1024];
+
+  /* Fill in message and iovec. */
+  msg.msg_name = (void *) from;
+  msg.msg_namelen = sizeof (struct sockaddr_in6);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = buflen;
+
+  /* If recvmsg fail return minus value. */
+  ret = recvmsg (sock, &msg, 0);
+  if (ret < 0)
+    return ret;
+
+  for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+       cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) 
+    {
+      /* I want interface index which this packet comes from. */
+      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+         cmsgptr->cmsg_type == IPV6_PKTINFO) 
+       {
+         struct in6_pktinfo *ptr;
+         
+         ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
+         *ifindex = ptr->ipi6_ifindex;
+         memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
+        }
+
+      /* Incoming packet's hop limit. */
+      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+         cmsgptr->cmsg_type == IPV6_HOPLIMIT)
+       *hoplimit = *((int *) CMSG_DATA (cmsgptr));
+    }
+  return ret;
+}
+
+#define RTADV_MSG_SIZE 4096
+
+/* Send router advertisement packet. */
+void
+rtadv_send_packet (int sock, struct interface *ifp)
+{
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr  *cmsgptr;
+  struct in6_pktinfo *pkt;
+  struct sockaddr_in6 addr;
+#if HAVE_SOCKADDR_DL
+  struct sockaddr_dl *sdl;
+#endif /* HAVE_SOCKADDR_DL */
+  char adata [sizeof (struct cmsghdr) + sizeof (struct in6_pktinfo)];
+  unsigned char buf[RTADV_MSG_SIZE];
+  struct nd_router_advert *rtadv;
+  int ret;
+  int len = 0;
+  struct zebra_if *zif;
+  u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+  listnode node;
+
+  /* Logging of packet. */
+  if (IS_ZEBRA_DEBUG_PACKET)
+    zlog_info ("Router advertisement send to %s", ifp->name);
+
+  /* Fill in sockaddr_in6. */
+  memset (&addr, 0, sizeof (struct sockaddr_in6));
+  addr.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  addr.sin6_len = sizeof (struct sockaddr_in6);
+#endif /* SIN6_LEN */
+  addr.sin6_port = htons (IPPROTO_ICMPV6);
+  memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
+
+  /* Fetch interface information. */
+  zif = ifp->info;
+
+  /* Make router advertisement message. */
+  rtadv = (struct nd_router_advert *) buf;
+
+  rtadv->nd_ra_type = ND_ROUTER_ADVERT;
+  rtadv->nd_ra_code = 0;
+  rtadv->nd_ra_cksum = 0;
+
+  rtadv->nd_ra_curhoplimit = 64;
+  rtadv->nd_ra_flags_reserved = 0;
+  if (zif->rtadv.AdvManagedFlag)
+    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
+  if (zif->rtadv.AdvOtherConfigFlag)
+    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
+  rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
+  rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
+  rtadv->nd_ra_retransmit = htonl (0);
+
+  len = sizeof (struct nd_router_advert);
+
+  /* Fill in prefix. */
+  for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
+    {
+      struct nd_opt_prefix_info *pinfo;
+      struct rtadv_prefix *rprefix;
+
+      rprefix = getdata (node);
+
+      pinfo = (struct nd_opt_prefix_info *) (buf + len);
+
+      pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+      pinfo->nd_opt_pi_len = 4;
+      pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
+
+      pinfo->nd_opt_pi_flags_reserved = 0;
+      if (rprefix->AdvOnLinkFlag)
+       pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
+      if (rprefix->AdvAutonomousFlag)
+       pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
+
+      pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
+      pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
+      pinfo->nd_opt_pi_reserved2 = 0;
+
+      memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
+             sizeof (struct in6_addr));
+
+#ifdef DEBUG
+      {
+       u_char buf[INET6_ADDRSTRLEN];
+
+       zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN));
+
+      }
+#endif /* DEBUG */
+
+      len += sizeof (struct nd_opt_prefix_info);
+    }
+
+  /* Hardware address. */
+#ifdef HAVE_SOCKADDR_DL
+  sdl = &ifp->sdl;
+  if (sdl != NULL && sdl->sdl_alen != 0)
+    {
+      buf[len++] = ND_OPT_SOURCE_LINKADDR;
+      buf[len++] = (sdl->sdl_alen + 2) >> 3;
+
+      memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
+      len += sdl->sdl_alen;
+    }
+#else
+  if (ifp->hw_addr_len != 0)
+    {
+      buf[len++] = ND_OPT_SOURCE_LINKADDR;
+      buf[len++] = (ifp->hw_addr_len + 2) >> 3;
+
+      memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
+      len += ifp->hw_addr_len;
+    }
+#endif /* HAVE_SOCKADDR_DL */
+
+  msg.msg_name = (void *) &addr;
+  msg.msg_namelen = sizeof (struct sockaddr_in6);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = len;
+
+  cmsgptr = (struct cmsghdr *)adata;
+  cmsgptr->cmsg_len = sizeof adata;
+  cmsgptr->cmsg_level = IPPROTO_IPV6;
+  cmsgptr->cmsg_type = IPV6_PKTINFO;
+  pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
+  memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
+  pkt->ipi6_ifindex = ifp->ifindex;
+
+  ret = sendmsg (sock, &msg, 0);
+  if (ret <0)
+    perror ("sendmsg");
+}
+
+int
+rtadv_timer (struct thread *thread)
+{
+  listnode node;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  rtadv->ra_timer = NULL;
+  rtadv_event (RTADV_TIMER, 1);
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if (if_is_loopback (ifp))
+       continue;
+
+      zif = ifp->info;
+
+      if (zif->rtadv.AdvSendAdvertisements)
+       if (--zif->rtadv.AdvIntervalTimer <= 0)
+         {
+           zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+           rtadv_send_packet (rtadv->sock, ifp);
+         }
+    }
+  return 0;
+}
+
+void
+rtadv_process_solicit (struct interface *ifp)
+{
+  zlog_info ("Router solicitation received on %s", ifp->name);
+
+  rtadv_send_packet (rtadv->sock, ifp);
+}
+
+void
+rtadv_process_advert ()
+{
+  zlog_info ("Router advertisement received");
+}
+
+void
+rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit)
+{
+  struct icmp6_hdr *icmph;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  /* Interface search. */
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    {
+      zlog_warn ("Unknown interface index: %d", ifindex);
+      return;
+    }
+
+  if (if_is_loopback (ifp))
+    return;
+
+  /* Check interface configuration. */
+  zif = ifp->info;
+  if (! zif->rtadv.AdvSendAdvertisements)
+    return;
+
+  /* ICMP message length check. */
+  if (len < sizeof (struct icmp6_hdr))
+    {
+      zlog_warn ("Invalid ICMPV6 packet length: %d", len);
+      return;
+    }
+
+  icmph = (struct icmp6_hdr *) buf;
+
+  /* ICMP message type check. */
+  if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
+      icmph->icmp6_type != ND_ROUTER_ADVERT)
+    {
+      zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
+      return;
+    }
+
+  /* Hoplimit check. */
+  if (hoplimit >= 0 && hoplimit != 255)
+    {
+      zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
+                hoplimit);
+      return;
+    }
+
+  /* Check ICMP message type. */
+  if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
+    rtadv_process_solicit (ifp);
+  else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
+    rtadv_process_advert ();
+
+  return;
+}
+
+int
+rtadv_read (struct thread *thread)
+{
+  int sock;
+  int len;
+  u_char buf[RTADV_MSG_SIZE];
+  struct sockaddr_in6 from;
+  unsigned int ifindex;
+  int hoplimit = -1;
+
+  sock = THREAD_FD (thread);
+  rtadv->ra_read = NULL;
+
+  /* Register myself. */
+  rtadv_event (RTADV_READ, sock);
+
+  len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
+
+  if (len < 0) 
+    {
+      zlog_warn ("router solicitation recv failed: %s.", strerror (errno));
+      return len;
+    }
+
+  rtadv_process_packet (buf, len, ifindex, hoplimit);
+
+  return 0;
+}
+
+int
+rtadv_make_socket (void)
+{
+  int sock;
+  int ret;
+  struct icmp6_filter filter;
+
+  sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+
+  /* When we can't make ICMPV6 socket simply back.  Router
+     advertisement feature will not be supported. */
+  if (sock < 0)
+    return -1;
+
+  ret = setsockopt_ipv6_pktinfo (sock, 1);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_checksum (sock, 2);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_multicast_loop (sock, 0);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_unicast_hops (sock, 255);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_multicast_hops (sock, 255);
+  if (ret < 0)
+    return ret;
+  ret = setsockopt_ipv6_hoplimit (sock, 1);
+  if (ret < 0)
+    return ret;
+
+  ICMP6_FILTER_SETBLOCKALL(&filter);
+  ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
+  ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
+
+  ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+                   sizeof (struct icmp6_filter));
+  if (ret < 0)
+    {
+      zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno));
+      return ret;
+    }
+
+  return sock;
+}
+\f
+struct rtadv_prefix *
+rtadv_prefix_new ()
+{
+  struct rtadv_prefix *new;
+
+  new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
+  memset (new, 0, sizeof (struct rtadv_prefix));
+
+  return new;
+}
+
+void
+rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
+{
+  XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
+}
+
+struct rtadv_prefix *
+rtadv_prefix_lookup (list rplist, struct prefix *p)
+{
+  listnode node;
+  struct rtadv_prefix *rprefix;
+
+  for (node = listhead (rplist); node; node = nextnode (node))
+    {
+      rprefix = getdata (node);
+      if (prefix_same (&rprefix->prefix, p))
+       return rprefix;
+    }
+  return NULL;
+}
+
+struct rtadv_prefix *
+rtadv_prefix_get (list rplist, struct prefix *p)
+{
+  struct rtadv_prefix *rprefix;
+  
+  rprefix = rtadv_prefix_lookup (rplist, p);
+  if (rprefix)
+    return rprefix;
+
+  rprefix = rtadv_prefix_new ();
+  memcpy (&rprefix->prefix, p, sizeof (struct prefix));
+  listnode_add (rplist, rprefix);
+
+  return rprefix;
+}
+
+void
+rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
+{
+  struct rtadv_prefix *rprefix;
+  
+  rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
+
+  /* Set parameters. */
+  rprefix->AdvValidLifetime = rp->AdvValidLifetime;
+  rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
+  rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
+  rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
+}
+
+int
+rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
+{
+  struct rtadv_prefix *rprefix;
+  
+  rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
+  if (rprefix != NULL)
+    {
+      listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
+      rtadv_prefix_free (rprefix);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+DEFUN (ipv6_nd_suppress_ra,
+       ipv6_nd_suppress_ra_cmd,
+       "ipv6 nd suppress-ra",
+       IP_STR
+       "Neighbor discovery\n"
+       "Suppress Router Advertisement\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = vty->index;
+  zif = ifp->info;
+
+  if (if_is_loopback (ifp))
+    {
+      vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (zif->rtadv.AdvSendAdvertisements)
+    {
+      zif->rtadv.AdvSendAdvertisements = 0;
+      zif->rtadv.AdvIntervalTimer = 0;
+      rtadv->adv_if_count--;
+
+      if_leave_all_router (rtadv->sock, ifp);
+
+      if (rtadv->adv_if_count == 0)
+       rtadv_event (RTADV_STOP, 0);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ipv6_nd_suppress_ra,
+       no_ipv6_nd_send_ra_cmd,
+       "no ipv6 nd send-ra",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Send Router Advertisement\n")
+
+DEFUN (no_ipv6_nd_suppress_ra,
+       no_ipv6_nd_suppress_ra_cmd,
+       "no ipv6 nd suppress-ra",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Suppress Router Advertisement\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = vty->index;
+  zif = ifp->info;
+
+  if (if_is_loopback (ifp))
+    {
+      vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (! zif->rtadv.AdvSendAdvertisements)
+    {
+      zif->rtadv.AdvSendAdvertisements = 1;
+      zif->rtadv.AdvIntervalTimer = 0;
+      rtadv->adv_if_count++;
+
+      if_join_all_router (rtadv->sock, ifp);
+
+      if (rtadv->adv_if_count == 1)
+       rtadv_event (RTADV_START, rtadv->sock);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_nd_suppress_ra,
+       ipv6_nd_send_ra_cmd,
+       "ipv6 nd send-ra",
+       IP_STR
+       "Neighbor discovery\n"
+       "Send Router Advertisement\n")
+
+DEFUN (ipv6_nd_ra_interval,
+       ipv6_nd_ra_interval_cmd,
+       "ipv6 nd ra-interval SECONDS",
+       IP_STR
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n"
+       "Router Advertisement interval in seconds\n")
+{
+  int interval;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  interval = atoi (argv[0]);
+
+  if (interval < 0)
+    {
+      vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.MaxRtrAdvInterval = interval;
+  zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
+  zif->rtadv.AdvIntervalTimer = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_ra_interval,
+       no_ipv6_nd_ra_interval_cmd,
+       "no ipv6 nd ra-interval",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
+  zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
+  zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_ra_lifetime,
+       ipv6_nd_ra_lifetime_cmd,
+       "ipv6 nd ra-lifetime SECONDS",
+       IP_STR
+       "Neighbor discovery\n"
+       "Router lifetime\n"
+       "Router lifetime in seconds\n")
+{
+  int lifetime;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  lifetime = atoi (argv[0]);
+
+  if (lifetime < 0 || lifetime > 0xffff)
+    {
+      vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.AdvDefaultLifetime = lifetime;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_ra_lifetime,
+       no_ipv6_nd_ra_lifetime_cmd,
+       "no ipv6 nd ra-lifetime",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Router lifetime\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_reachable_time,
+       ipv6_nd_reachable_time_cmd,
+       "ipv6 nd reachable-time MILLISECONDS",
+       IP_STR
+       "Neighbor discovery\n"
+       "Reachable time\n"
+       "Reachable time in milliseconds\n")
+{
+  u_int32_t rtime;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  rtime = (u_int32_t) atol (argv[0]);
+
+  if (rtime > RTADV_MAX_REACHABLE_TIME)
+    {
+      vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.AdvReachableTime = rtime;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_reachable_time,
+       no_ipv6_nd_reachable_time_cmd,
+       "no ipv6 nd reachable-time",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Reachable time\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvReachableTime = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_managed_config_flag,
+       ipv6_nd_managed_config_flag_cmd,
+       "ipv6 nd managed-config-flag",
+       IP_STR
+       "Neighbor discovery\n"
+       "Managed address configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvManagedFlag = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_managed_config_flag,
+       no_ipv6_nd_managed_config_flag_cmd,
+       "no ipv6 nd managed-config-flag",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Managed address configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvManagedFlag = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_other_config_flag,
+       ipv6_nd_other_config_flag_cmd,
+       "ipv6 nd other-config-flag",
+       IP_STR
+       "Neighbor discovery\n"
+       "Other statefull configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvOtherConfigFlag = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_other_config_flag,
+       no_ipv6_nd_other_config_flag_cmd,
+       "no ipv6 nd other-config-flag",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Other statefull configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvOtherConfigFlag = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_prefix_advertisement,
+       ipv6_nd_prefix_advertisement_cmd,
+       "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]",
+       IP_STR
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Valid lifetime in seconds\n"
+       "Preferred lifetime in seconds\n"
+       "On link flag\n"
+       "Autonomous address-configuration flag\n")
+{
+  int i;
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *zebra_if;
+  struct rtadv_prefix rp;
+
+  ifp = (struct interface *) vty->index;
+  zebra_if = ifp->info;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 1)
+    {
+      rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
+      rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
+      rp.AdvOnLinkFlag = 1;
+      rp.AdvAutonomousFlag = 1;
+    }
+  else
+    {
+      rp.AdvValidLifetime = (u_int32_t) atol (argv[1]);
+      rp.AdvPreferredLifetime = (u_int32_t) atol (argv[2]);
+      if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
+       {
+         vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+
+      rp.AdvOnLinkFlag = 0;
+      rp.AdvAutonomousFlag = 0;
+      for (i = 3; i < argc; i++)
+       {
+         if (! strcmp (argv[i], "onlink"))
+           rp.AdvOnLinkFlag = 1;
+         else if (! strcmp (argv[i], "autoconfig"))
+           rp.AdvAutonomousFlag = 1;
+       }
+    }
+
+  rtadv_prefix_set (zebra_if, &rp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (ipv6_nd_prefix_advertisement,
+       ipv6_nd_prefix_advertisement_no_val_cmd,
+       "ipv6 nd prefix-advertisement IPV6PREFIX",
+       IP_STR
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n")
+
+DEFUN (no_ipv6_nd_prefix_advertisement,
+       no_ipv6_nd_prefix_advertisement_cmd,
+       "no ipv6 nd prefix-advertisement IPV6PREFIX",
+       NO_STR
+       IP_STR
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n")
+{
+  int ret;
+  struct interface *ifp;
+  struct zebra_if *zebra_if;
+  struct rtadv_prefix rp;
+
+  ifp = (struct interface *) vty->index;
+  zebra_if = ifp->info;
+
+  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = rtadv_prefix_reset (zebra_if, &rp);
+  if (!ret)
+    {
+      vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Write configuration about router advertisement. */
+void
+rtadv_config_write (struct vty *vty, struct interface *ifp)
+{
+  struct zebra_if *zif;
+  listnode node;
+  struct rtadv_prefix *rprefix;
+  u_char buf[INET6_ADDRSTRLEN];
+
+  if (! rtadv)
+    return;
+
+  zif = ifp->info;
+
+  if (! if_is_loopback (ifp))
+    {
+      if (zif->rtadv.AdvSendAdvertisements)
+       vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
+      else
+       vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
+    }
+
+  if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
+    vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
+            VTY_NEWLINE);
+
+  if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
+    vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
+            VTY_NEWLINE);
+
+  if (zif->rtadv.AdvReachableTime)
+    vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
+            VTY_NEWLINE);
+
+  if (zif->rtadv.AdvManagedFlag)
+    vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
+
+  if (zif->rtadv.AdvOtherConfigFlag)
+    vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
+
+  for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
+    {
+      rprefix = getdata (node);
+      vty_out (vty, " ipv6 nd prefix-advertisement %s/%d %d %d",
+              inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, 
+                         buf, INET6_ADDRSTRLEN),
+              rprefix->prefix.prefixlen,
+              rprefix->AdvValidLifetime,
+              rprefix->AdvPreferredLifetime);
+      if (rprefix->AdvOnLinkFlag)
+       vty_out (vty, " onlink");
+      if (rprefix->AdvAutonomousFlag)
+       vty_out (vty, " autoconfig");
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+extern struct thread_master *master;
+
+void
+rtadv_event (enum rtadv_event event, int val)
+{
+  switch (event)
+    {
+    case RTADV_START:
+      if (! rtadv->ra_read)
+       rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val);
+      if (! rtadv->ra_timer)
+       rtadv->ra_timer = thread_add_event (master, rtadv_timer, NULL, 0);
+      break;
+    case RTADV_STOP:
+      if (rtadv->ra_timer)
+       {
+         thread_cancel (rtadv->ra_timer);
+         rtadv->ra_timer = NULL;
+       }
+      if (rtadv->ra_read)
+       {
+         thread_cancel (rtadv->ra_read);
+         rtadv->ra_read = NULL;
+       }
+      break;
+    case RTADV_TIMER:
+      if (! rtadv->ra_timer)
+       rtadv->ra_timer = thread_add_timer (master, rtadv_timer, NULL, val);
+      break;
+    case RTADV_READ:
+      if (! rtadv->ra_read)
+       rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val);
+      break;
+    default:
+      break;
+    }
+  return;
+}
+
+void
+rtadv_init ()
+{
+  int sock;
+
+  sock = rtadv_make_socket ();
+  if (sock < 0)
+    return;
+
+  rtadv = rtadv_new ();
+  rtadv->sock = sock;
+
+  install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd);
+}
+
+int
+if_join_all_router (int sock, struct interface *ifp)
+{
+  int ret;
+
+  struct ipv6_mreq mreq;
+
+  memset (&mreq, 0, sizeof (struct ipv6_mreq));
+  inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
+  mreq.ipv6mr_interface = ifp->ifindex;
+
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 
+                   (char *) &mreq, sizeof mreq);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
+
+  zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
+
+  return 0;
+}
+
+int
+if_leave_all_router (int sock, struct interface *ifp)
+{
+  int ret;
+
+  struct ipv6_mreq mreq;
+
+  memset (&mreq, 0, sizeof (struct ipv6_mreq));
+  inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
+  mreq.ipv6mr_interface = ifp->ifindex;
+
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 
+                   (char *) &mreq, sizeof mreq);
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno));
+
+  zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
+
+  return 0;
+}
+
+#else
+void
+rtadv_init ()
+{
+  /* Empty.*/;
+}
+#endif /* RTADV && HAVE_IPV6 */
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
new file mode 100644 (file)
index 0000000..859b2d7
--- /dev/null
@@ -0,0 +1,49 @@
+/* Router advertisement
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_RTADV_H
+#define _ZEBRA_RTADV_H
+
+/* Router advertisement prefix. */
+struct rtadv_prefix
+{
+  /* Prefix to be advertised. */
+  struct prefix prefix;
+  
+  /* The value to be placed in the Valid Lifetime in the Prefix */
+  u_int32_t AdvValidLifetime;
+#define RTADV_VALID_LIFETIME 2592000
+
+  /* The value to be placed in the on-link flag */
+  int AdvOnLinkFlag;
+
+  /* The value to be placed in the Preferred Lifetime in the Prefix
+     Information option, in seconds.*/
+  u_int32_t AdvPreferredLifetime;
+#define RTADV_PREFERRED_LIFETIME 604800
+
+  /* The value to be placed in the Autonomous Flag. */
+  int AdvAutonomousFlag;
+};
+
+void rtadv_config_write (struct vty *, struct interface *);
+
+#endif /* _ZEBRA_RTADV_H */
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
new file mode 100644 (file)
index 0000000..435eed8
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Kernel routing table readup by getmsg(2)
+ * Copyright (C) 1999 Michael Handler
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "log.h"
+#include "if.h"
+
+#include "zebra/rib.h"
+
+#include <sys/stream.h>
+#include <sys/tihdr.h>
+
+/* Solaris defines these in both <netinet/in.h> and <inet/in.h>, sigh */
+#ifdef SUNOS_5
+#include <sys/tiuser.h>
+#ifndef T_CURRENT
+#define T_CURRENT       MI_T_CURRENT
+#endif /* T_CURRENT */
+#ifndef IRE_CACHE
+#define IRE_CACHE               0x0020  /* Cached Route entry */
+#endif /* IRE_CACHE */
+#ifndef IRE_HOST_REDIRECT
+#define IRE_HOST_REDIRECT       0x0200  /* Host route entry from redirects */
+#endif /* IRE_HOST_REDIRECT */
+#ifndef IRE_CACHETABLE
+#define IRE_CACHETABLE          (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \
+                                 IRE_LOOPBACK)
+#endif /* IRE_CACHETABLE */
+#undef IPOPT_EOL
+#undef IPOPT_NOP
+#undef IPOPT_LSRR
+#undef IPOPT_RR
+#undef IPOPT_SSRR
+#endif /* SUNOS_5 */
+
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/mib2.h>
+
+/* device to read IP routing table from */
+#ifndef _PATH_GETMSG_ROUTE
+#define _PATH_GETMSG_ROUTE     "/dev/ip"
+#endif /* _PATH_GETMSG_ROUTE */
+
+#define RT_BUFSIZ              8192
+
+void handle_route_entry (mib2_ipRouteEntry_t *routeEntry)
+{
+       struct prefix_ipv4      prefix;
+       struct in_addr          tmpaddr, gateway;
+       u_char                  zebra_flags = 0;
+
+       if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE)
+               return;
+
+       if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT)
+               zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+       prefix.family = AF_INET;
+
+       tmpaddr.s_addr = routeEntry->ipRouteDest;
+       prefix.prefix = tmpaddr;
+
+       tmpaddr.s_addr = routeEntry->ipRouteMask;
+       prefix.prefixlen = ip_masklen (tmpaddr);
+
+       gateway.s_addr = routeEntry->ipRouteNextHop;
+
+       rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
+                     &gateway, 0, 0, 0, 0);
+}
+
+void route_read ()
+{
+       char                    storage[RT_BUFSIZ];
+
+       struct T_optmgmt_req    *TLIreq = (struct T_optmgmt_req *) storage;
+       struct T_optmgmt_ack    *TLIack = (struct T_optmgmt_ack *) storage;
+       struct T_error_ack      *TLIerr = (struct T_error_ack *) storage;
+
+       struct opthdr           *MIB2hdr;
+
+       mib2_ipRouteEntry_t     *routeEntry, *lastRouteEntry;
+
+       struct strbuf           msgdata;
+       int                     flags, dev, retval, process;
+
+       if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) {
+               zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE,
+                       strerror (errno));
+               return;
+       }
+
+       TLIreq->PRIM_type = T_OPTMGMT_REQ;
+       TLIreq->OPT_offset = sizeof (struct T_optmgmt_req);
+       TLIreq->OPT_length = sizeof (struct opthdr);
+       TLIreq->MGMT_flags = T_CURRENT;
+
+       MIB2hdr = (struct opthdr *) &TLIreq[1];
+
+       MIB2hdr->level = MIB2_IP;
+       MIB2hdr->name = 0;
+       MIB2hdr->len = 0;
+       
+       msgdata.buf = storage;
+       msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr);
+
+       flags = 0;
+
+       if (putmsg (dev, &msgdata, NULL, flags) == -1) {
+               zlog_warn ("putmsg failed: %s", strerror (errno));
+               goto exit;
+       }
+
+       MIB2hdr = (struct opthdr *) &TLIack[1];
+       msgdata.maxlen = sizeof (storage);
+
+       while (1) {
+               flags = 0;
+               retval = getmsg (dev, &msgdata, NULL, &flags);
+
+               if (retval == -1) {
+                       zlog_warn ("getmsg(ctl) failed: %s", strerror (errno));
+                       goto exit;
+               }
+
+               /* This is normal loop termination */
+               if (retval == 0 &&
+                       msgdata.len >= sizeof (struct T_optmgmt_ack) &&
+                       TLIack->PRIM_type == T_OPTMGMT_ACK &&
+                       TLIack->MGMT_flags == T_SUCCESS &&
+                       MIB2hdr->len == 0)
+                       break;
+
+               if (msgdata.len >= sizeof (struct T_error_ack) &&
+                       TLIerr->PRIM_type == T_ERROR_ACK) {
+                       zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s",
+                               strerror ((TLIerr->TLI_error == TSYSERR)
+                               ? TLIerr->UNIX_error : EPROTO));
+                       break;
+               }
+
+               /* should dump more debugging info to the log statement,
+                  like what GateD does in this instance, but not
+                  critical yet. */
+               if (retval != MOREDATA ||
+                       msgdata.len < sizeof (struct T_optmgmt_ack) ||
+                       TLIack->PRIM_type != T_OPTMGMT_ACK ||
+                       TLIack->MGMT_flags != T_SUCCESS) {
+                       errno = ENOMSG;
+                       zlog_warn ("getmsg(ctl) returned bizarreness");
+                       break;
+               }
+
+               /* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable
+                  entry, see <inet/mib2.h>. "This isn't the MIB data
+                  you're looking for." */
+               process = (MIB2hdr->level == MIB2_IP &&
+                       MIB2hdr->name == MIB2_IP_21) ? 1 : 0;
+
+               /* getmsg writes the data buffer out completely, not
+                  to the closest smaller multiple. Unless reassembling
+                  data structures across buffer boundaries is your idea
+                  of a good time, set maxlen to the closest smaller
+                  multiple of the size of the datastructure you're
+                  retrieving. */
+               msgdata.maxlen = sizeof (storage) - (sizeof (storage)
+                       % sizeof (mib2_ipRouteEntry_t));
+
+               msgdata.len = 0;
+               flags = 0;
+
+               do {
+                       retval = getmsg (dev, NULL, &msgdata, &flags);
+
+                       if (retval == -1) {
+                               zlog_warn ("getmsg(data) failed: %s",
+                                       strerror (errno));
+                               goto exit;
+                       }
+
+                       if (!(retval == 0 || retval == MOREDATA)) {
+                               zlog_warn ("getmsg(data) returned %d", retval);
+                               goto exit;
+                       }
+
+                       if (process) {
+                               if (msgdata.len %
+                                       sizeof (mib2_ipRouteEntry_t) != 0) {
+                                       zlog_warn ("getmsg(data) returned "
+"msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len);
+                                       goto exit;
+                               }
+
+                               routeEntry = (mib2_ipRouteEntry_t *)
+                                       msgdata.buf;
+                               lastRouteEntry = (mib2_ipRouteEntry_t *)
+                                       (msgdata.buf + msgdata.len);
+                               do {
+                                       handle_route_entry (routeEntry);
+                               } while (++routeEntry < lastRouteEntry);
+                       }
+               } while (retval == MOREDATA);
+       }
+
+exit:
+       close (dev);
+}
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
new file mode 100644 (file)
index 0000000..0b255a5
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Kernel routing table readup by netlink
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+/* Extern from rt_netlink.c */
+void netlink_route_read ();
+
+void route_read ()
+{
+  netlink_route_read ();
+}
diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c
new file mode 100644 (file)
index 0000000..320152e
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Kernel routing readup by /proc filesystem
+ * Copyright (C) 1997 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "log.h"
+#include "if.h"
+#include "rib.h"
+
+/* Proc file system to read IPv4 routing table. */
+#ifndef _PATH_PROCNET_ROUTE
+#define _PATH_PROCNET_ROUTE      "/proc/net/route"
+#endif /* _PATH_PROCNET_ROUTE */
+
+/* Proc file system to read IPv6 routing table. */
+#ifndef _PATH_PROCNET_ROUTE6
+#define _PATH_PROCNET_ROUTE6     "/proc/net/ipv6_route"
+#endif /* _PATH_PROCNET_ROUTE6 */
+
+/* To read interface's name */
+#define INTERFACE_NAMSIZ 20  
+
+/* Reading buffer for one routing entry. */
+#define RT_BUFSIZ 1024
+
+/* Kernel routing table read up by /proc filesystem. */
+int
+proc_route_read ()
+{
+  FILE *fp;
+  char buf[RT_BUFSIZ];
+  char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9];
+  int flags, refcnt, use, metric, mtu, window, rtt;
+
+  /* Open /proc filesystem */
+  fp = fopen (_PATH_PROCNET_ROUTE, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, strerror (errno));
+      return -1;
+    }
+  
+  /* Drop first label line. */
+  fgets (buf, RT_BUFSIZ, fp);
+
+  while (fgets (buf, RT_BUFSIZ, fp) != NULL)
+    {
+      int n;
+      struct prefix_ipv4 p;
+      struct in_addr tmpmask;
+      struct in_addr gateway;
+      u_char zebra_flags = 0;
+
+      n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d",
+                 iface, dest, gate, &flags, &refcnt, &use, &metric, 
+                 mask, &mtu, &window, &rtt);
+      if (n != 11)
+       {       
+         zlog_warn ("can't read all of routing information\n");
+         continue;
+       }
+      if (! (flags & RTF_UP))
+       continue;
+      if (! (flags & RTF_GATEWAY))
+       continue;
+
+      if (flags & RTF_DYNAMIC)
+       zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+      p.family = AF_INET;
+      sscanf (dest, "%lX", (unsigned long *)&p.prefix);
+      sscanf (mask, "%lX", (unsigned long *)&tmpmask);
+      p.prefixlen = ip_masklen (tmpmask);
+      sscanf (gate, "%lX", (unsigned long *)&gateway);
+
+      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0);
+    }
+
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+proc_ipv6_route_read ()
+{
+  FILE *fp;
+  char buf [RT_BUFSIZ];
+
+  /* Open /proc filesystem */
+  fp = fopen (_PATH_PROCNET_ROUTE6, "r");
+  if (fp == NULL)
+    {
+      zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6, 
+               strerror (errno));
+      return -1;
+    }
+  
+  /* There is no title line, so we don't drop first line.  */
+  while (fgets (buf, RT_BUFSIZ, fp) != NULL)
+    {
+      int n;
+      char dest[33], src[33], gate[33];
+      char iface[INTERFACE_NAMSIZ];
+      int dest_plen, src_plen;
+      int metric, use, refcnt, flags;
+      struct prefix_ipv6 p;
+      struct in6_addr gateway;
+      u_char zebra_flags = 0;
+
+      /* Linux 2.1.x write this information at net/ipv6/route.c
+         rt6_info_node () */
+      n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s",
+                 dest, &dest_plen, src, &src_plen, gate,
+                 &metric, &use, &refcnt, &flags, iface);
+
+      if (n != 10)
+       {       
+         /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */
+         continue;
+       }
+
+      if (! (flags & RTF_UP))
+       continue;
+      if (! (flags & RTF_GATEWAY))
+       continue;
+
+      if (flags & RTF_DYNAMIC)
+       zebra_flags |= ZEBRA_FLAG_SELFROUTE;
+
+      p.family = AF_INET6;
+      str2in6_addr (dest, &p.prefix);
+      str2in6_addr (gate, &gateway);
+      p.prefixlen = dest_plen;
+
+      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0);
+    }
+
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+void
+route_read ()
+{
+  proc_route_read ();
+#ifdef HAVE_IPV6
+  proc_ipv6_route_read ();
+#endif /* HAVE_IPV6 */
+}
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
new file mode 100644 (file)
index 0000000..970c0aa
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Kernel routing table read by sysctl function.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+
+/* Kernel routing table read up by sysctl function. */
+int
+route_read ()
+{
+  caddr_t buf, end, ref;
+  size_t bufsiz;
+  struct rt_msghdr *rtm;
+  void rtm_read (struct rt_msghdr *);
+  
+#define MIBSIZ 6
+  int mib[MIBSIZ] = 
+  {
+    CTL_NET,
+    PF_ROUTE,
+    0,
+    0,
+    NET_RT_DUMP,
+    0
+  };
+                     
+  /* Get buffer size. */
+  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog_warn ("sysctl fail: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Allocate buffer. */
+  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
+  
+  /* Read routing table information by calling sysctl(). */
+  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
+    {
+      zlog_warn ("sysctl() fail by %s", strerror (errno));
+      return -1;
+    }
+
+  for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) 
+    {
+      rtm = (struct rt_msghdr *) buf;
+      rtm_read (rtm);
+    }
+
+  /* Free buffer. */
+  XFREE (MTYPE_TMP, ref);
+
+  return 0;
+}
diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample
new file mode 100644 (file)
index 0000000..a5d0732
--- /dev/null
@@ -0,0 +1,25 @@
+! -*- zebra -*-
+!
+! zebra sample configuration file
+!
+! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
+!
+hostname Router
+password zebra
+enable password zebra
+!
+! Interface's description. 
+!
+!interface lo
+! description test of desc.
+!
+!interface sit0
+! multicast
+
+!
+! Static default route sample.
+!
+!ip route 0.0.0.0/0 203.181.89.241
+!
+
+!log file zebra.log
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
new file mode 100644 (file)
index 0000000..ec07e2e
--- /dev/null
@@ -0,0 +1,2199 @@
+/* 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 "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+/* Default rtm_table for all clients */
+extern int rtm_table_default;
+
+/* Each route type's string and default distance value. */
+struct
+{  
+  int key;
+  int distance;
+} route_info[] =
+{
+  {ZEBRA_ROUTE_SYSTEM,    0},
+  {ZEBRA_ROUTE_KERNEL,    0},
+  {ZEBRA_ROUTE_CONNECT,   0},
+  {ZEBRA_ROUTE_STATIC,    1},
+  {ZEBRA_ROUTE_RIP,     120},
+  {ZEBRA_ROUTE_RIPNG,   120},
+  {ZEBRA_ROUTE_OSPF,    110},
+  {ZEBRA_ROUTE_OSPF6,   110},
+  {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */}
+};
+\f
+/* Vector for routing table.  */
+vector vrf_vector;
+
+/* Allocate new VRF.  */
+struct vrf *
+vrf_alloc (char *name)
+{
+  struct vrf *vrf;
+
+  vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
+
+  /* Put name.  */
+  if (name)
+    vrf->name = XSTRDUP (MTYPE_VRF_NAME, name);
+
+  /* Allocate routing table and static table.  */
+  vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init ();
+  vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init ();
+  vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init ();
+  vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init ();
+
+  return vrf;
+}
+
+/* Free VRF.  */
+void
+vrf_free (struct vrf *vrf)
+{
+  if (vrf->name)
+    XFREE (MTYPE_VRF_NAME, vrf->name);
+  XFREE (MTYPE_VRF, vrf);
+}
+
+/* Lookup VRF by identifier.  */
+struct vrf *
+vrf_lookup (u_int32_t id)
+{
+  return vector_lookup (vrf_vector, id);
+}
+
+/* Lookup VRF by name.  */
+struct vrf *
+vrf_lookup_by_name (char *name)
+{
+  int i;
+  struct vrf *vrf;
+
+  for (i = 0; i < vector_max (vrf_vector); i++)
+    if ((vrf = vector_slot (vrf_vector, i)) != NULL)
+      if (vrf->name && name && strcmp (vrf->name, name) == 0)
+       return vrf;
+  return NULL;
+}
+
+/* Initialize VRF.  */
+void
+vrf_init ()
+{
+  struct vrf *default_table;
+
+  /* Allocate VRF vector.  */
+  vrf_vector = vector_init (1);
+
+  /* Allocate default main table.  */
+  default_table = vrf_alloc ("Default-IP-Routing-Table");
+
+  /* Default table index must be 0.  */
+  vector_set_index (vrf_vector, 0, default_table);
+}
+
+/* Lookup route table.  */
+struct route_table *
+vrf_table (afi_t afi, safi_t safi, u_int32_t id)
+{
+  struct vrf *vrf;
+
+  vrf = vrf_lookup (id);
+  if (! vrf)
+    return NULL;
+
+  return vrf->table[afi][safi];
+}
+
+/* Lookup static route table.  */
+struct route_table *
+vrf_static_table (afi_t afi, safi_t safi, u_int32_t id)
+{
+  struct vrf *vrf;
+
+  vrf = vrf_lookup (id);
+  if (! vrf)
+    return NULL;
+
+  return vrf->stable[afi][safi];
+}
+\f
+/* Add nexthop to the end of the list.  */
+void
+nexthop_add (struct rib *rib, struct nexthop *nexthop)
+{
+  struct nexthop *last;
+
+  for (last = rib->nexthop; last && last->next; last = last->next)
+    ;
+  if (last)
+    last->next = nexthop;
+  else
+    rib->nexthop = nexthop;
+  nexthop->prev = last;
+
+  rib->nexthop_num++;
+}
+
+/* Delete specified nexthop from the list. */
+void
+nexthop_delete (struct rib *rib, struct nexthop *nexthop)
+{
+  if (nexthop->next)
+    nexthop->next->prev = nexthop->prev;
+  if (nexthop->prev)
+    nexthop->prev->next = nexthop->next;
+  else
+    rib->nexthop = nexthop->next;
+  rib->nexthop_num--;
+}
+
+/* Free nexthop. */
+void
+nexthop_free (struct nexthop *nexthop)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IFNAME && nexthop->ifname)
+    free (nexthop->ifname);
+  XFREE (MTYPE_NEXTHOP, nexthop);
+}
+
+struct nexthop *
+nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IFINDEX;
+  nexthop->ifindex = ifindex;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ifname_add (struct rib *rib, char *ifname)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IFNAME;
+  nexthop->ifname = strdup (ifname);
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV4;
+  nexthop->gate.ipv4 = *ipv4;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, 
+                         unsigned int ifindex)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+  nexthop->gate.ipv4 = *ipv4;
+  nexthop->ifindex = ifindex;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+#ifdef HAVE_IPV6
+struct nexthop *
+nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV6;
+  nexthop->gate.ipv6 = *ipv6;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
+                        char *ifname)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
+  nexthop->gate.ipv6 = *ipv6;
+  nexthop->ifname = XSTRDUP (0, ifname);
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
+                         unsigned int ifindex)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+  nexthop->gate.ipv6 = *ipv6;
+  nexthop->ifindex = ifindex;
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+#endif /* HAVE_IPV6 */
+
+
+struct nexthop *
+nexthop_blackhole_add (struct rib *rib)
+{
+  struct nexthop *nexthop;
+
+  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+  memset (nexthop, 0, sizeof (struct nexthop));
+  nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
+  SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE);
+
+  nexthop_add (rib, nexthop);
+
+  return nexthop;
+}
+
+/* If force flag is not set, do not modify falgs at all for uninstall
+   the route from FIB. */
+int
+nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
+                    struct route_node *top)
+{
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  if (nexthop->type == NEXTHOP_TYPE_IPV4)
+    nexthop->ifindex = 0;
+
+  if (set)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+  /* Make lookup prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = nexthop->gate.ipv4;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* If lookup self prefix return immidiately. */
+      if (rn == top)
+       return 0;
+
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+       if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+         break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match 
+         || match->type == ZEBRA_ROUTE_BGP)
+       {
+         do {
+           rn = rn->parent;
+         } while (rn && rn->info == NULL);
+         if (rn)
+           route_lock_node (rn);
+       }
+      else
+       {
+         if (match->type == ZEBRA_ROUTE_CONNECT)
+           {
+             /* Directly point connected route. */
+             newhop = match->nexthop;
+             if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4)
+               nexthop->ifindex = newhop->ifindex;
+             
+             return 1;
+           }
+         else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+           {
+             for (newhop = match->nexthop; newhop; newhop = newhop->next)
+               if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+                   && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+                 {
+                   if (set)
+                     {
+                       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+                       nexthop->rtype = newhop->type;
+                       if (newhop->type == NEXTHOP_TYPE_IPV4 ||
+                           newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+                         nexthop->rgate.ipv4 = newhop->gate.ipv4;
+                       if (newhop->type == NEXTHOP_TYPE_IFINDEX
+                           || newhop->type == NEXTHOP_TYPE_IFNAME
+                           || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+                         nexthop->rifindex = newhop->ifindex;
+                     }
+                   return 1;
+                 }
+             return 0;
+           }
+         else
+           {
+             return 0;
+           }
+       }
+    }
+  return 0;
+}
+
+#ifdef HAVE_IPV6
+/* If force flag is not set, do not modify falgs at all for uninstall
+   the route from FIB. */
+int
+nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
+                    struct route_node *top)
+{
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  if (nexthop->type == NEXTHOP_TYPE_IPV6)
+    nexthop->ifindex = 0;
+
+  if (set)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+  /* Make lookup prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  p.prefix = nexthop->gate.ipv6;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* If lookup self prefix return immidiately. */
+      if (rn == top)
+       return 0;
+
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+       if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+         break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match
+         || match->type == ZEBRA_ROUTE_BGP)
+       {
+         do {
+           rn = rn->parent;
+         } while (rn && rn->info == NULL);
+         if (rn)
+           route_lock_node (rn);
+       }
+      else
+       {
+         if (match->type == ZEBRA_ROUTE_CONNECT)
+           {
+             /* Directly point connected route. */
+             newhop = match->nexthop;
+
+             if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6)
+               nexthop->ifindex = newhop->ifindex;
+             
+             return 1;
+           }
+         else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+           {
+             for (newhop = match->nexthop; newhop; newhop = newhop->next)
+               if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+                   && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+                 {
+                   if (set)
+                     {
+                       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+                       nexthop->rtype = newhop->type;
+                       if (newhop->type == NEXTHOP_TYPE_IPV6
+                           || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+                           || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+                         nexthop->rgate.ipv6 = newhop->gate.ipv6;
+                       if (newhop->type == NEXTHOP_TYPE_IFINDEX
+                           || newhop->type == NEXTHOP_TYPE_IFNAME
+                           || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+                           || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+                         nexthop->rifindex = newhop->ifindex;
+                     }
+                   return 1;
+                 }
+             return 0;
+           }
+         else
+           {
+             return 0;
+           }
+       }
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+struct rib *
+rib_match_ipv4 (struct in_addr addr)
+{
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = addr;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+       if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+         break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match 
+         || match->type == ZEBRA_ROUTE_BGP)
+       {
+         do {
+           rn = rn->parent;
+         } while (rn && rn->info == NULL);
+         if (rn)
+           route_lock_node (rn);
+       }
+      else
+       {
+         if (match->type == ZEBRA_ROUTE_CONNECT)
+           /* Directly point connected route. */
+           return match;
+         else
+           {
+             for (newhop = match->nexthop; newhop; newhop = newhop->next)
+               if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+                 return match;
+             return NULL;
+           }
+       }
+    }
+  return NULL;
+}
+
+struct rib *
+rib_lookup_ipv4 (struct prefix_ipv4 *p)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_lookup (table, (struct prefix *) p);
+
+  /* No route for this prefix. */
+  if (! rn)
+    return NULL;
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+
+  /* Pick up selected route. */
+  for (match = rn->info; match; match = match->next)
+    if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+      break;
+
+  if (! match || match->type == ZEBRA_ROUTE_BGP)
+    return NULL;
+
+  if (match->type == ZEBRA_ROUTE_CONNECT)
+    return match;
+  
+  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+    if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+      return match;
+
+  return NULL;
+}
+
+#ifdef HAVE_IPV6
+struct rib *
+rib_match_ipv6 (struct in6_addr *addr)
+{
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  IPV6_ADDR_COPY (&p.prefix, addr);
+
+  rn = route_node_match (table, (struct prefix *) &p);
+
+  while (rn)
+    {
+      route_unlock_node (rn);
+      
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+       if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+         break;
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match 
+         || match->type == ZEBRA_ROUTE_BGP)
+       {
+         do {
+           rn = rn->parent;
+         } while (rn && rn->info == NULL);
+         if (rn)
+           route_lock_node (rn);
+       }
+      else
+       {
+         if (match->type == ZEBRA_ROUTE_CONNECT)
+           /* Directly point connected route. */
+           return match;
+         else
+           {
+             for (newhop = match->nexthop; newhop; newhop = newhop->next)
+               if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+                 return match;
+             return NULL;
+           }
+       }
+    }
+  return NULL;
+}
+#endif /* HAVE_IPV6 */
+
+int
+nexthop_active_check (struct route_node *rn, struct rib *rib,
+                     struct nexthop *nexthop, int set)
+{
+  struct interface *ifp;
+
+  switch (nexthop->type)
+    {
+    case NEXTHOP_TYPE_IFINDEX:
+      ifp = if_lookup_by_index (nexthop->ifindex);
+      if (ifp && if_is_up (ifp))
+       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      else
+       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+    case NEXTHOP_TYPE_IFNAME:
+    case NEXTHOP_TYPE_IPV6_IFNAME:
+      ifp = if_lookup_by_name (nexthop->ifname);
+      if (ifp && if_is_up (ifp))
+       {
+         if (set)
+           nexthop->ifindex = ifp->ifindex;
+         SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+       }
+      else
+       {
+         if (set)
+           nexthop->ifindex = 0;
+         UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+       }
+      break;
+    case NEXTHOP_TYPE_IPV4:
+    case NEXTHOP_TYPE_IPV4_IFINDEX:
+      if (nexthop_active_ipv4 (rib, nexthop, set, rn))
+       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      else
+       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+#ifdef HAVE_IPV6
+    case NEXTHOP_TYPE_IPV6:
+      if (nexthop_active_ipv6 (rib, nexthop, set, rn))
+       SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      else
+       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+    case NEXTHOP_TYPE_IPV6_IFINDEX:
+      if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
+       {
+         ifp = if_lookup_by_index (nexthop->ifindex);
+         if (ifp && if_is_up (ifp))
+           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+         else
+           UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+       }
+      else
+       {
+         if (nexthop_active_ipv6 (rib, nexthop, set, rn))
+           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+         else
+           UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+       }
+      break;
+#endif /* HAVE_IPV6 */
+    case NEXTHOP_TYPE_BLACKHOLE:
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      break;
+    default:
+      break;
+    }
+  return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+}
+
+int
+nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
+{
+  struct nexthop *nexthop;
+  int active;
+
+  rib->nexthop_active_num = 0;
+  UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      rib->nexthop_active_num += nexthop_active_check (rn, rib, nexthop, set);
+      if (active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+       SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+    }
+  return rib->nexthop_active_num;
+}
+\f
+#define RIB_SYSTEM_ROUTE(R) \
+        ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+
+void
+newrib_free (struct rib *rib)
+{
+  struct nexthop *nexthop;
+  struct nexthop *next;
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = next)
+    {
+      next = nexthop->next;
+      nexthop_free (nexthop);
+    }
+  XFREE (MTYPE_RIB, rib);
+}
+
+void
+rib_install_kernel (struct route_node *rn, struct rib *rib)
+{
+  int ret = 0;
+  struct nexthop *nexthop;
+
+  switch (PREFIX_FAMILY (&rn->p))
+    {
+    case AF_INET:
+      ret = kernel_add_ipv4 (&rn->p, rib);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = kernel_add_ipv6 (&rn->p, rib);
+      break;
+#endif /* HAVE_IPV6 */
+    }
+
+  if (ret < 0)
+    {
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+    }
+}
+
+/* Uninstall the route from kernel. */
+int
+rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
+{
+  int ret = 0;
+  struct nexthop *nexthop;
+
+  switch (PREFIX_FAMILY (&rn->p))
+    {
+    case AF_INET:
+      ret = kernel_delete_ipv4 (&rn->p, rib);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = kernel_delete_ipv6 (&rn->p, rib);
+      break;
+#endif /* HAVE_IPV6 */
+    }
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  return ret;
+}
+
+/* Uninstall the route from kernel. */
+void
+rib_uninstall (struct route_node *rn, struct rib *rib)
+{
+  if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+    {
+      redistribute_delete (&rn->p, rib);
+      if (! RIB_SYSTEM_ROUTE (rib))
+       rib_uninstall_kernel (rn, rib);
+      UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
+    }
+}
+
+/* Core function for processing routing information base. */
+void
+rib_process (struct route_node *rn, struct rib *del)
+{
+  struct rib *rib;
+  struct rib *next;
+  struct rib *fib = NULL;
+  struct rib *select = NULL;
+
+  for (rib = rn->info; rib; rib = next)
+    {
+      next = rib->next;
+
+      /* Currently installed rib. */
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+       fib = rib;
+
+      /* Skip unreachable nexthop. */
+      if (! nexthop_active_update (rn, rib, 0))
+       continue;
+
+      /* Infinit distance. */
+      if (rib->distance == DISTANCE_INFINITY)
+       continue;
+
+      /* Newly selected rib. */
+      if (! select || rib->distance < select->distance 
+         || rib->type == ZEBRA_ROUTE_CONNECT)
+       select = rib;
+    }
+
+  /* Deleted route check. */
+  if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED))
+    fib = del;
+
+  /* Same route is selected. */
+  if (select && select == fib)
+    {
+      if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED))
+       {
+         redistribute_delete (&rn->p, select);
+         if (! RIB_SYSTEM_ROUTE (select))
+           rib_uninstall_kernel (rn, select);
+
+         /* Set real nexthop. */
+         nexthop_active_update (rn, select, 1);
+  
+         if (! RIB_SYSTEM_ROUTE (select))
+           rib_install_kernel (rn, select);
+         redistribute_add (&rn->p, select);
+       }
+      return;
+    }
+
+  /* Uninstall old rib from forwarding table. */
+  if (fib)
+    {
+      redistribute_delete (&rn->p, fib);
+      if (! RIB_SYSTEM_ROUTE (fib))
+       rib_uninstall_kernel (rn, fib);
+      UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+
+      /* Set real nexthop. */
+      nexthop_active_update (rn, fib, 1);
+    }
+
+  /* Install new rib into forwarding table. */
+  if (select)
+    {
+      /* Set real nexthop. */
+      nexthop_active_update (rn, select, 1);
+
+      if (! RIB_SYSTEM_ROUTE (select))
+       rib_install_kernel (rn, select);
+      SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
+      redistribute_add (&rn->p, select);
+    }
+}
+
+/* Add RIB to head of the route node. */
+void
+rib_addnode (struct route_node *rn, struct rib *rib)
+{
+  struct rib *head;
+
+  head = rn->info;
+  if (head)
+    head->prev = rib;
+  rib->next = head;
+  rn->info = rib;
+}
+
+void
+rib_delnode (struct route_node *rn, struct rib *rib)
+{
+  if (rib->next)
+    rib->next->prev = rib->prev;
+  if (rib->prev)
+    rib->prev->next = rib->next;
+  else
+    rn->info = rib->next;
+}
+
+int
+rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
+             struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+             u_int32_t metric, u_char distance)
+{
+  struct rib *rib;
+  struct rib *same = NULL;
+  struct route_table *table;
+  struct route_node *rn;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Make it sure prefixlen is applied to the prefix. */
+  apply_mask_ipv4 (p);
+
+  /* Set default distance by route type. */
+  if (distance == 0)
+    {
+      distance = route_info[type].distance;
+
+      /* iBGP distance is 200. */
+      if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
+       distance = 200;
+    }
+
+  /* Lookup route node.*/
+  rn = route_node_get (table, (struct prefix *) p);
+
+  /* If same type of route are installed, treat it as a implicit
+     withdraw. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+       {
+         nexthop = rib->nexthop;
+
+         /* Duplicate connected route comes in. */
+         if (rib->type == type
+             && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+             && nexthop->ifindex == ifindex)
+           {
+             rib->refcnt++;
+             return 0 ;
+           }
+       }
+      else if (rib->type == type)
+       {
+         same = rib;
+         rib_delnode (rn, same);
+         route_unlock_node (rn);
+         break;
+       }
+    }
+
+  /* Allocate new rib structure. */
+  rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+  memset (rib, 0, sizeof (struct rib));
+  rib->type = type;
+  rib->distance = distance;
+  rib->flags = flags;
+  rib->metric = metric;
+  rib->nexthop_num = 0;
+  rib->uptime = time (NULL);
+
+  /* Nexthop settings. */
+  if (gate)
+    {
+      if (ifindex)
+       nexthop_ipv4_ifindex_add (rib, gate, ifindex);
+      else
+       nexthop_ipv4_add (rib, gate);
+    }
+  else
+    nexthop_ifindex_add (rib, ifindex);
+
+  /* If this route is kernel route, set FIB flag to the route. */
+  if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  /* Link new rib to node.*/
+  rib_addnode (rn, rib);
+
+  /* Process this route node. */
+  rib_process (rn, same);
+
+  /* Free implicit route.*/
+  if (same)
+    newrib_free (same);
+
+  return 0;
+}
+
+int
+rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *same;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Make it sure prefixlen is applied to the prefix. */
+  apply_mask_ipv4 (p);
+
+  /* Set default distance by route type. */
+  if (rib->distance == 0)
+    {
+      rib->distance = route_info[rib->type].distance;
+
+      /* iBGP distance is 200. */
+      if (rib->type == ZEBRA_ROUTE_BGP 
+         && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+       rib->distance = 200;
+    }
+
+  /* Lookup route node.*/
+  rn = route_node_get (table, (struct prefix *) p);
+
+  /* If same type of route are installed, treat it as a implicit
+     withdraw. */
+  for (same = rn->info; same; same = same->next)
+    {
+      if (same->type == rib->type && same->table == rib->table
+         && same->type != ZEBRA_ROUTE_CONNECT)
+       {
+         rib_delnode (rn, same);
+         route_unlock_node (rn);
+         break;
+       }
+    }
+
+  /* If this route is kernel route, set FIB flag to the route. */
+  if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT)
+    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  /* Link new rib to node.*/
+  rib_addnode (rn, rib);
+
+  /* Process this route node. */
+  rib_process (rn, same);
+
+  /* Free implicit route.*/
+  if (same)
+    newrib_free (same);
+
+  return 0;
+}
+
+int
+rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+                struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *fib = NULL;
+  struct rib *same = NULL;
+  struct nexthop *nexthop;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Apply mask. */
+  apply_mask_ipv4 (p);
+
+  /* Lookup route node. */
+  rn = route_node_lookup (table, (struct prefix *) p);
+  if (! rn)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       {
+         if (gate)
+           zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib",
+                      inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+                      p->prefixlen,
+                      inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+                      ifindex);
+         else
+           zlog_info ("route %s/%d ifindex %d doesn't exist in rib",
+                      inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+                      p->prefixlen,
+                      ifindex);
+       }
+      return ZEBRA_ERR_RTNOEXIST;
+    }
+
+  /* Lookup same type route. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+       fib = rib;
+
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+       {
+         nexthop = rib->nexthop;
+
+         if (rib->type == type
+             && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+             && nexthop->ifindex == ifindex)
+           {
+             if (rib->refcnt)
+               {
+                 rib->refcnt--;
+                 route_unlock_node (rn);
+                 route_unlock_node (rn);
+                 return 0;
+               }
+             same = rib;
+             break;
+           }
+       }
+      else
+       {
+         if (rib->type == type)
+           {
+             same = rib;
+             break;
+           }
+       }
+    }
+
+  /* If same type of route can't be found and this message is from
+     kernel. */
+  if (! same)
+    {
+      if (fib && type == ZEBRA_ROUTE_KERNEL)
+       {
+         /* Unset flags. */
+         for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+           UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+         UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+       }
+      else
+       {
+         if (IS_ZEBRA_DEBUG_KERNEL)
+           {
+             if (gate)
+               zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
+                          inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+                          p->prefixlen,
+                          inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+                          ifindex,
+                          type);
+             else
+               zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib",
+                          inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+                          p->prefixlen,
+                          ifindex,
+                          type);
+           }
+         route_unlock_node (rn);
+         return ZEBRA_ERR_RTNOEXIST;
+       }
+    }
+
+  if (same)
+    rib_delnode (rn, same);
+
+  /* Process changes. */
+  rib_process (rn, same);
+
+  if (same)
+    {
+      newrib_free (same);
+      route_unlock_node (rn);
+    }
+
+  route_unlock_node (rn);
+
+  return 0;
+}
+\f
+/* Install static route into rib. */
+void
+static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
+{
+  struct rib *rib;
+  struct route_node *rn;
+  struct route_table *table;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route */
+  rn = route_node_get (table, p);
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+
+  if (rib)
+    {
+      /* Same distance static route is there.  Update it with new
+         nexthop. */
+      rib_uninstall (rn, rib);
+      route_unlock_node (rn);
+
+      switch (si->type)
+       {
+       case STATIC_IPV4_GATEWAY:
+         nexthop_ipv4_add (rib, &si->gate.ipv4);
+         break;
+       case STATIC_IPV4_IFNAME:
+         nexthop_ifname_add (rib, si->gate.ifname);
+         break;
+       case STATIC_IPV4_BLACKHOLE:
+         nexthop_blackhole_add (rib);
+         break;
+       }
+      rib_process (rn, NULL);
+    }
+  else
+    {
+      /* This is new static route. */
+      rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+      memset (rib, 0, sizeof (struct rib));
+
+      rib->type = ZEBRA_ROUTE_STATIC;
+      rib->distance = si->distance;
+      rib->metric = 0;
+      rib->nexthop_num = 0;
+
+      switch (si->type)
+       {
+       case STATIC_IPV4_GATEWAY:
+         nexthop_ipv4_add (rib, &si->gate.ipv4);
+         break;
+       case STATIC_IPV4_IFNAME:
+         nexthop_ifname_add (rib, si->gate.ifname);
+         break;
+       case STATIC_IPV4_BLACKHOLE:
+         nexthop_blackhole_add (rib);
+         break;
+       }
+
+      /* Link this rib to the tree. */
+      rib_addnode (rn, rib);
+
+      /* Process this prefix. */
+      rib_process (rn, NULL);
+    }
+}
+
+int
+static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IPV4
+      && si->type == STATIC_IPV4_GATEWAY
+      && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4))
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IFNAME
+      && si->type == STATIC_IPV4_IFNAME
+      && strcmp (nexthop->ifname, si->gate.ifname) == 0)
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
+      && si->type == STATIC_IPV4_BLACKHOLE)
+    return 1;
+  return 0;;
+}
+
+/* Uninstall static route from RIB. */
+void
+static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+  struct route_table *table;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route with type and distance. */
+  rn = route_node_lookup (table, p);
+  if (! rn)
+    return;
+
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+
+  if (! rib)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  /* Lookup nexthop. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    if (static_ipv4_nexthop_same (nexthop, si))
+      break;
+
+  /* Can't find nexthop. */
+  if (! nexthop)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+  
+  /* Check nexthop. */
+  if (rib->nexthop_num == 1)
+    {
+      rib_delnode (rn, rib);
+      rib_process (rn, rib);
+      newrib_free (rib);
+      route_unlock_node (rn);
+    }
+  else
+    {
+      rib_uninstall (rn, rib);
+      nexthop_delete (rib, nexthop);
+      nexthop_free (nexthop);
+      rib_process (rn, rib);
+    }
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+}
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+                u_char distance, u_int32_t vrf_id)
+{
+  u_char type = 0;
+  struct route_node *rn;
+  struct static_ipv4 *si;
+  struct static_ipv4 *pp;
+  struct static_ipv4 *cp;
+  struct static_ipv4 *update = NULL;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+  
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Make flags. */
+  if (gate)
+    type = STATIC_IPV4_GATEWAY;
+  else if (ifname)
+    type = STATIC_IPV4_IFNAME;
+  else
+    type = STATIC_IPV4_BLACKHOLE;
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (type == si->type
+         && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
+         && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+       {
+         if (distance == si->distance)
+           {
+             route_unlock_node (rn);
+             return 0;
+           }
+         else
+           update = si;
+       }
+    }
+
+  /* Distance chaged.  */
+  if (update)
+    static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);
+
+  /* Make new static route structure. */
+  si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
+  memset (si, 0, sizeof (struct static_ipv4));
+
+  si->type = type;
+  si->distance = distance;
+
+  if (gate)
+    si->gate.ipv4 = *gate;
+  if (ifname)
+    si->gate.ifname = XSTRDUP (0, ifname);
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+    {
+      if (si->distance < cp->distance)
+       break;
+      if (si->distance > cp->distance)
+       continue;
+      if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
+       {
+         if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr))
+           break;
+         if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr))
+           continue;
+       }
+    }
+
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
+
+  /* Install into rib. */
+  static_install_ipv4 (p, si);
+
+  return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname,
+                   u_char distance, u_int32_t vrf_id)
+{
+  u_char type = 0;
+  struct route_node *rn;
+  struct static_ipv4 *si;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_lookup (stable, p);
+  if (! rn)
+    return 0;
+
+  /* Make flags. */
+  if (gate)
+    type = STATIC_IPV4_GATEWAY;
+  else if (ifname)
+    type = STATIC_IPV4_IFNAME;
+  else
+    type = STATIC_IPV4_BLACKHOLE;
+
+  /* Find same static route is the tree */
+  for (si = rn->info; si; si = si->next)
+    if (type == si->type
+       && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
+       && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+      break;
+
+  /* Can't find static route. */
+  if (! si)
+    {
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  /* Install into rib. */
+  static_uninstall_ipv4 (p, si);
+
+  /* Unlink static route from linked list. */
+  if (si->prev)
+    si->prev->next = si->next;
+  else
+    rn->info = si->next;
+  if (si->next)
+    si->next->prev = si->prev;
+  
+  /* Free static route configuration. */
+  XFREE (MTYPE_STATIC_IPV4, si);
+
+  return 1;
+}
+
+\f
+#ifdef HAVE_IPV6
+int
+rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
+               struct in6_addr *gate, unsigned int ifindex, int table)
+{
+  if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix))
+    return 1;
+  if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
+      && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
+    {
+      kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
+      return 1;
+    }
+  return 0;
+}
+
+int
+rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+             struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  struct rib *rib;
+  struct rib *same = NULL;
+  struct route_table *table;
+  struct route_node *rn;
+  struct nexthop *nexthop;
+
+  int distance;
+  u_int32_t metric = 0;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Make sure mask is applied. */
+  apply_mask_ipv6 (p);
+
+  /* Set default distance by route type. */
+  distance = route_info[type].distance;
+  
+  if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
+    distance = 200;
+
+  /* Filter bogus route. */
+  if (rib_bogus_ipv6 (type, p, gate, ifindex, 0))
+    return 0;
+
+  /* Lookup route node.*/
+  rn = route_node_get (table, (struct prefix *) p);
+
+  /* If same type of route are installed, treat it as a implicit
+     withdraw. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+       {
+         nexthop = rib->nexthop;
+
+         if (rib->type == type
+             && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+             && nexthop->ifindex == ifindex)
+         {
+           rib->refcnt++;
+           return 0;
+         }
+       }
+      else if (rib->type == type)
+       {
+         same = rib;
+         rib_delnode (rn, same);
+         route_unlock_node (rn);
+         break;
+       }
+    }
+
+  /* Allocate new rib structure. */
+  rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+  memset (rib, 0, sizeof (struct rib));
+  rib->type = type;
+  rib->distance = distance;
+  rib->flags = flags;
+  rib->metric = metric;
+  rib->nexthop_num = 0;
+  rib->uptime = time (NULL);
+
+  /* Nexthop settings. */
+  if (gate)
+    {
+      if (ifindex)
+       nexthop_ipv6_ifindex_add (rib, gate, ifindex);
+      else
+       nexthop_ipv6_add (rib, gate);
+    }
+  else
+    nexthop_ifindex_add (rib, ifindex);
+
+  /* If this route is kernel route, set FIB flag to the route. */
+  if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+  /* Link new rib to node.*/
+  rib_addnode (rn, rib);
+
+  /* Process this route node. */
+  rib_process (rn, same);
+
+  /* Free implicit route.*/
+  if (same)
+    newrib_free (same);
+
+  return 0;
+}
+
+int
+rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+                struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *fib = NULL;
+  struct rib *same = NULL;
+  struct nexthop *nexthop;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+
+  /* Apply mask. */
+  apply_mask_ipv6 (p);
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  /* Lookup route node. */
+  rn = route_node_lookup (table, (struct prefix *) p);
+  if (! rn)
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       {
+         if (gate)
+           zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib",
+                      inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+                      p->prefixlen,
+                      inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+                      ifindex);
+         else
+           zlog_info ("route %s/%d ifindex %d doesn't exist in rib",
+                      inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+                      p->prefixlen,
+                      ifindex);
+       }
+      return ZEBRA_ERR_RTNOEXIST;
+    }
+
+  /* Lookup same type route. */
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+       fib = rib;
+
+      if (rib->type == ZEBRA_ROUTE_CONNECT)
+       {
+         nexthop = rib->nexthop;
+
+         if (rib->type == type
+             && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+             && nexthop->ifindex == ifindex)
+           {
+             if (rib->refcnt)
+               {
+                 rib->refcnt--;
+                 route_unlock_node (rn);
+                 route_unlock_node (rn);
+                 return 0;
+               }
+             same = rib;
+             break;
+           }
+       }
+      else
+       {
+         if (rib->type == type)
+           {
+             same = rib;
+             break;
+           }
+       }
+    }
+
+  /* If same type of route can't be found and this message is from
+     kernel. */
+  if (! same)
+    {
+      if (fib && type == ZEBRA_ROUTE_KERNEL)
+       {
+         /* Unset flags. */
+         for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+           UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+         UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+       }
+      else
+       {
+         if (IS_ZEBRA_DEBUG_KERNEL)
+           {
+             if (gate)
+               zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
+                          inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+                          p->prefixlen,
+                          inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+                          ifindex,
+                          type);
+             else
+               zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib",
+                          inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+                          p->prefixlen,
+                          ifindex,
+                          type);
+           }
+         route_unlock_node (rn);
+         return ZEBRA_ERR_RTNOEXIST;
+       }
+    }
+
+  if (same)
+    rib_delnode (rn, same);
+
+  /* Process changes. */
+  rib_process (rn, same);
+
+  if (same)
+    {
+      newrib_free (same);
+      route_unlock_node (rn);
+    }
+
+  route_unlock_node (rn);
+
+  return 0;
+}
+\f
+/* Install static route into rib. */
+void
+static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)
+{
+  struct rib *rib;
+  struct route_table *table;
+  struct route_node *rn;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route */
+  rn = route_node_get (table, p);
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+
+  if (rib)
+    {
+      /* Same distance static route is there.  Update it with new
+         nexthop. */
+      rib_uninstall (rn, rib);
+      route_unlock_node (rn);
+
+      switch (si->type)
+       {
+       case STATIC_IPV6_GATEWAY:
+         nexthop_ipv6_add (rib, &si->ipv6);
+         break;
+       case STATIC_IPV6_IFNAME:
+         nexthop_ifname_add (rib, si->ifname);
+         break;
+       case STATIC_IPV6_GATEWAY_IFNAME:
+         nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+         break;
+       }
+      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_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return;
+
+  /* Lookup existing route with type and distance. */
+  rn = route_node_lookup (table, (struct prefix *) p);
+  if (! rn)
+    return;
+
+  for (rib = rn->info; rib; rib = rib->next)
+    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      break;
+  if (! rib)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  /* Lookup nexthop. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    if (static_ipv6_nexthop_same (nexthop, si))
+      break;
+
+  /* Can't find nexthop. */
+  if (! nexthop)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+  
+  /* Check nexthop. */
+  if (rib->nexthop_num == 1)
+    {
+      rib_delnode (rn, rib);
+      rib_process (rn, rib);
+      newrib_free (rib);
+      route_unlock_node (rn);
+    }
+  else
+    {
+      rib_uninstall (rn, rib);
+      nexthop_delete (rib, nexthop);
+      nexthop_free (nexthop);
+      rib_process (rn, rib);
+    }
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+}
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                char *ifname, u_char distance, u_int32_t vrf_id)
+{
+  struct route_node *rn;
+  struct static_ipv6 *si;
+  struct static_ipv6 *pp;
+  struct static_ipv6 *cp;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (distance == si->distance 
+         && type == si->type
+         && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
+         && (! ifname || strcmp (ifname, si->ifname) == 0))
+       {
+         route_unlock_node (rn);
+         return 0;
+       }
+    }
+
+  /* Make new static route structure. */
+  si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
+  memset (si, 0, sizeof (struct static_ipv6));
+
+  si->type = type;
+  si->distance = distance;
+
+  switch (type)
+    {
+    case STATIC_IPV6_GATEWAY:
+      si->ipv6 = *gate;
+      break;
+    case STATIC_IPV6_IFNAME:
+      si->ifname = XSTRDUP (0, ifname);
+      break;
+    case STATIC_IPV6_GATEWAY_IFNAME:
+      si->ipv6 = *gate;
+      si->ifname = XSTRDUP (0, ifname);
+      break;
+    }
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+    {
+      if (si->distance < cp->distance)
+       break;
+      if (si->distance > cp->distance)
+       continue;
+    }
+
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
+
+  /* Install into rib. */
+  static_install_ipv6 (p, si);
+
+  return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                   char *ifname, u_char distance, u_int32_t vrf_id)
+{
+  struct route_node *rn;
+  struct static_ipv6 *si;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_lookup (stable, p);
+  if (! rn)
+    return 0;
+
+  /* Find same static route is the tree */
+  for (si = rn->info; si; si = si->next)
+    if (distance == si->distance 
+       && type == si->type
+       && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
+       && (! ifname || strcmp (ifname, si->ifname) == 0))
+      break;
+
+  /* Can't find static route. */
+  if (! si)
+    {
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  /* Install into rib. */
+  static_uninstall_ipv6 (p, si);
+
+  /* Unlink static route from linked list. */
+  if (si->prev)
+    si->prev->next = si->next;
+  else
+    rn->info = si->next;
+  if (si->next)
+    si->next->prev = si->prev;
+  
+  /* Free static route configuration. */
+  XFREE (MTYPE_STATIC_IPV6, si);
+
+  return 1;
+}
+#endif /* HAVE_IPV6 */
+\f
+/* RIB update function. */
+void
+rib_update ()
+{
+  struct route_node *rn;
+  struct route_table *table;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      rib_process (rn, NULL);
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      rib_process (rn, NULL);
+}
+
+/* Interface goes up. */
+void
+rib_if_up (struct interface *ifp)
+{
+  rib_update ();
+}
+
+/* Interface goes down. */
+void
+rib_if_down (struct interface *ifp)
+{
+  rib_update ();
+}
+\f
+/* Remove all routes which comes from non main table.  */
+void
+rib_weed_table (struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *next;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = next)
+       {
+         next = rib->next;
+
+         if (rib->table != rtm_table_default &&
+             rib->table != RT_TABLE_MAIN)
+           {
+             rib_delnode (rn, rib);
+             newrib_free (rib);
+             route_unlock_node (rn);
+           }
+       }
+}
+
+/* Delete all routes from non main table. */
+void
+rib_weed_tables ()
+{
+  rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+\f
+/* Delete self installed routes after zebra is relaunched.  */
+void
+rib_sweep_table (struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *next;
+  int ret = 0;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = next)
+       {
+         next = rib->next;
+
+         if (rib->type == ZEBRA_ROUTE_KERNEL && 
+             CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE))
+           {
+             ret = rib_uninstall_kernel (rn, rib);
+             if (! ret)
+               {
+                 rib_delnode (rn, rib);
+                 newrib_free (rib);
+                 route_unlock_node (rn);
+               }
+           }
+       }
+}
+
+/* Sweep all RIB tables.  */
+void
+rib_sweep_route ()
+{
+  rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+\f
+/* Close RIB and clean up kernel routes. */
+void
+rib_close_table (struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = rib->next)
+       if (! RIB_SYSTEM_ROUTE (rib)
+           && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+         rib_uninstall_kernel (rn, rib);
+}
+
+/* Close all RIB tables.  */
+void
+rib_close ()
+{
+  rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+\f
+/* Routing information base initialize. */
+void
+rib_init ()
+{
+  /* VRF initialization.  */
+  vrf_init ();
+}
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
new file mode 100644 (file)
index 0000000..d160bfa
--- /dev/null
@@ -0,0 +1,550 @@
+/* BGP4 SNMP support
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "smux.h"
+#include "table.h"
+
+#include "zebra/rib.h"
+\f
+#define IPFWMIB 1,3,6,1,2,1,4,24
+#define ZEBRAOID 1,3,6,1,4,1,3317,1,2,1
+
+/* ipForwardTable */
+#define IPFORWARDDEST                         1
+#define IPFORWARDMASK                         2
+#define IPFORWARDPOLICY                       3
+#define IPFORWARDNEXTHOP                      4
+#define IPFORWARDIFINDEX                      5
+#define IPFORWARDTYPE                         6
+#define IPFORWARDPROTO                        7
+#define IPFORWARDAGE                          8
+#define IPFORWARDINFO                         9
+#define IPFORWARDNEXTHOPAS                   10
+#define IPFORWARDMETRIC1                     11
+#define IPFORWARDMETRIC2                     12
+#define IPFORWARDMETRIC3                     13
+#define IPFORWARDMETRIC4                     14
+#define IPFORWARDMETRIC5                     15
+
+/* ipCidrRouteTable */
+#define IPCIDRROUTEDEST                       1
+#define IPCIDRROUTEMASK                       2
+#define IPCIDRROUTETOS                        3
+#define IPCIDRROUTENEXTHOP                    4
+#define IPCIDRROUTEIFINDEX                    5
+#define IPCIDRROUTETYPE                       6
+#define IPCIDRROUTEPROTO                      7
+#define IPCIDRROUTEAGE                        8
+#define IPCIDRROUTEINFO                       9
+#define IPCIDRROUTENEXTHOPAS                 10
+#define IPCIDRROUTEMETRIC1                   11
+#define IPCIDRROUTEMETRIC2                   12
+#define IPCIDRROUTEMETRIC3                   13
+#define IPCIDRROUTEMETRIC4                   14
+#define IPCIDRROUTEMETRIC5                   15
+#define IPCIDRROUTESTATUS                    16
+
+#define INTEGER32 ASN_INTEGER
+#define GAUGE32 ASN_GAUGE
+#define ENUMERATION ASN_INTEGER
+#define ROWSTATUS ASN_INTEGER
+#define IPADDRESS ASN_IPADDRESS
+#define OBJECTIDENTIFIER ASN_OBJECT_ID
+\f
+oid ipfw_oid [] = { IPFWMIB };
+oid zebra_oid [] = { ZEBRAOID };
+
+/* Hook functions. */
+u_char * ipFwNumber ();
+u_char * ipFwTable ();
+u_char * ipCidrNumber ();
+u_char * ipCidrTable ();
+
+struct variable zebra_variables[] = 
+{
+  {0, GAUGE32, RONLY, ipFwNumber, 1, {1}},
+  {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}},
+  {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}},
+  {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}},
+  {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}},
+  {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}},
+  {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}},
+  {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}},
+  {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}},
+  {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}},
+  {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}},
+  {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}},
+  {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}},
+  {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}},
+  {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}},
+  {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}},
+  {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}},
+  {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}},
+  {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}},
+  {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}},
+  {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}},
+  {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}},
+  {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}},
+  {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}},
+  {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}},
+  {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}},
+  {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}},
+  {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}},
+  {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}},
+  {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}},
+  {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}},
+  {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}},
+  {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}}
+};
+
+\f
+u_char *
+ipFwNumber (struct variable *v, oid objid[], size_t *objid_len,
+           int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static int result;
+  struct route_node *np;
+  struct rib *rib;
+
+  if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED)
+    return NULL;
+
+  /* Return number of routing entries. */
+  result = 0;
+  for (np = route_top (rib_table_ipv4); np; np = route_next (np))
+    for (rib = np->info; rib; rib = rib->next)
+      result++;
+
+  return (u_char *)&result;
+}
+
+u_char *
+ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len,
+           int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static int result;
+  struct route_node *np;
+  struct rib *rib;
+
+  if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED)
+    return NULL;
+
+  /* Return number of routing entries. */
+  result = 0;
+  for (np = route_top (rib_table_ipv4); np; np = route_next (np))
+    for (rib = np->info; rib; rib = rib->next)
+      result++;
+
+  return (u_char *)&result;
+}
+
+int
+in_addr_cmp(u_char *p1, u_char *p2)
+{
+  int i;
+
+  for (i=0; i<4; i++)
+    {
+      if (*p1 < *p2)
+        return -1;
+      if (*p1 > *p2)
+        return 1;
+      p1++; p2++;
+    }
+  return 0;
+}
+
+int 
+in_addr_add(u_char *p, int num)
+{
+  int i, ip0;
+
+  ip0 = *p;
+  p += 4;
+  for (i = 3; 0 <= i; i--) {
+    p--;
+    if (*p + num > 255) {
+       *p += num;
+       num = 1;
+    } else {
+       *p += num;
+       return 1;
+    }
+  }
+  if (ip0 > *p) {
+       /* ip + num > 0xffffffff */
+       return 0;
+  }
+  
+  return 1;
+}
+
+int proto_trans(int type)
+{
+  switch (type)
+    {
+      case ZEBRA_ROUTE_SYSTEM:
+        return 1; /* other */
+      case ZEBRA_ROUTE_KERNEL:
+        return 1; /* other */
+      case ZEBRA_ROUTE_CONNECT:
+        return 2; /* local interface */
+      case ZEBRA_ROUTE_STATIC:
+        return 3; /* static route */
+      case ZEBRA_ROUTE_RIP:
+        return 8; /* rip */
+      case ZEBRA_ROUTE_RIPNG:
+        return 1; /* shouldn't happen */
+      case ZEBRA_ROUTE_OSPF:
+        return 13; /* ospf */
+      case ZEBRA_ROUTE_OSPF6:
+        return 1; /* shouldn't happen */
+      case ZEBRA_ROUTE_BGP:
+        return 14; /* bgp */
+      default:
+        return 1; /* other */
+    }
+}
+
+void
+check_replace(struct route_node *np2, struct rib *rib2, 
+              struct route_node **np, struct rib **rib)
+{
+  int proto, proto2;
+
+  if (!*np)
+    {
+      *np = np2;
+      *rib = rib2;
+      return;
+    }
+
+  if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0)
+    return;
+  if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0)
+    {
+      *np = np2;
+      *rib = rib2;
+      return;
+    }
+
+  proto = proto_trans((*rib)->type);
+  proto2 = proto_trans(rib2->type);
+
+  if (proto2 > proto)
+    return;
+  if (proto2 < proto)
+    {
+      *np = np2;
+      *rib = rib2;
+      return;
+    }
+
+  if (in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, 
+                  (u_char *)&rib2->nexthop->gate.ipv4) <= 0)
+    return;
+
+  *np = np2;
+  *rib = rib2;
+  return;
+}
+
+void
+get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, 
+                      int exact, struct route_node **np, struct rib **rib)
+{
+  struct in_addr dest;
+  struct route_node *np2;
+  struct rib *rib2;
+  int proto;
+  int policy;
+  struct in_addr nexthop;
+  u_char *pnt;
+  int i;
+
+/* Init index variables */
+
+  pnt = (u_char *) &dest;
+  for (i = 0; i < 4; i++)
+    *pnt++ = 0;
+
+  pnt = (u_char *) &nexthop;
+  for (i = 0; i < 4; i++)
+    *pnt++ = 0;
+
+  proto = 0;
+  policy = 0;
+/* Init return variables */
+
+  *np = NULL;
+  *rib = NULL;
+
+/* Short circuit exact matches of wrong length */
+
+  if (exact && (*objid_len != v->namelen + 10))
+    return;
+
+/* Get INDEX information out of OID.
+ * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop
+ */
+
+  if (*objid_len > v->namelen)
+    oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest);
+
+  if (*objid_len > v->namelen + 4)
+    proto = objid[v->namelen + 4];
+
+  if (*objid_len > v->namelen + 5)
+    policy = objid[v->namelen + 5];
+
+  if (*objid_len > v->namelen + 6)
+    oid2in_addr (objid + v->namelen + 6, MIN(4, *objid_len - v->namelen - 6),
+      &nexthop);
+
+  /* Apply GETNEXT on not exact search */
+
+  if (!exact && (*objid_len >= v->namelen + 10))
+    {
+      if (! in_addr_add((u_char *) &nexthop, 1)) 
+        return;
+    }
+
+  /* For exact: search matching entry in rib table. */
+
+  if (exact)
+    {
+      if (policy) /* Not supported (yet?) */
+        return;
+      for (*np = route_top (rib_table_ipv4); *np; *np = route_next (*np))
+       {
+         if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest))
+           {
+             for (*rib = (*np)->info; *rib; *rib = (*rib)->next)
+               {
+                 if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4,
+                   (u_char *)&nexthop))
+                   if (proto == proto_trans((*rib)->type))
+                     return;
+               }
+           }
+       }
+      return;
+    }
+
+/* Search next best entry */
+
+  for (np2 = route_top (rib_table_ipv4); np2; np2 = route_next (np2))
+    {
+
+      /* Check destination first */
+      if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0)
+        for (rib2 = np2->info; rib2; rib2 = rib2->next)
+         check_replace(np2, rib2, np, rib);
+
+      if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0)
+        { /* have to look at each rib individually */
+          for (rib2 = np2->info; rib2; rib2 = rib2->next)
+           {
+             int proto2, policy2;
+
+             proto2 = proto_trans(rib2->type);
+             policy2 = 0;
+
+             if ((policy < policy2)
+                 || ((policy == policy2) && (proto < proto2))
+                 || ((policy == policy2) && (proto == proto2)
+                     && (in_addr_cmp((u_char *)&rib2->nexthop->gate.ipv4,
+                                     (u_char *) &nexthop) >= 0)
+                     ))
+               check_replace(np2, rib2, np, rib);
+           }
+       }
+    }
+
+  if (!*rib)
+    return;
+
+  policy = 0;
+  proto = proto_trans((*rib)->type);
+
+  *objid_len = v->namelen + 10;
+  pnt = (u_char *) &(*np)->p.u.prefix;
+  for (i = 0; i < 4; i++)
+    objid[v->namelen + i] = *pnt++;
+
+  objid[v->namelen + 4] = proto;
+  objid[v->namelen + 5] = policy;
+
+  {
+    struct nexthop *nexthop;
+
+    nexthop = (*rib)->nexthop;
+    if (nexthop)
+      {
+       pnt = (u_char *) &nexthop->gate.ipv4;
+       for (i = 0; i < 4; i++)
+         objid[i + v->namelen + 6] = *pnt++;
+      }
+  }
+
+  return;
+}
+
+u_char *
+ipFwTable (struct variable *v, oid objid[], size_t *objid_len,
+          int exact, size_t *val_len, WriteMethod **write_method)
+{
+  struct route_node *np;
+  struct rib *rib;
+  static int result;
+  static int resarr[2];
+  static struct in_addr netmask;
+  struct nexthop *nexthop;
+
+  get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib);
+  if (!np)
+    return NULL;
+
+  nexthop = rib->nexthop;
+  if (! nexthop)
+    return NULL;
+
+  switch (v->magic)
+    {
+    case IPFORWARDDEST:
+      *val_len = 4;
+      return &np->p.u.prefix;
+      break;
+    case IPFORWARDMASK:
+      masklen2ip(np->p.prefixlen, &netmask);
+      *val_len = 4;
+      return (u_char *)&netmask;
+      break;
+    case IPFORWARDPOLICY:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDNEXTHOP:
+      *val_len = 4;
+      return (u_char *)&nexthop->gate.ipv4;
+      break;
+    case IPFORWARDIFINDEX:
+      *val_len = sizeof(int);
+      return (u_char *)&nexthop->ifindex;
+      break;
+    case IPFORWARDTYPE:
+      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+         || nexthop->type == NEXTHOP_TYPE_IFNAME)
+        result = 3;
+      else
+        result = 4;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDPROTO:
+      result = proto_trans(rib->type);
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDAGE:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDINFO:
+      resarr[0] = 0;
+      resarr[1] = 0;
+      *val_len  = 2 * sizeof(int);
+      return (u_char *)resarr;
+      break;
+    case IPFORWARDNEXTHOPAS:
+      result = -1;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC1:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC2:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC3:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC4:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    case IPFORWARDMETRIC5:
+      result = 0;
+      *val_len  = sizeof(int);
+      return (u_char *)&result;
+      break;
+    default:
+      return NULL;
+      break;
+    }  
+  return NULL;
+}
+
+u_char *
+ipCidrTable (struct variable *v, oid objid[], size_t *objid_len,
+          int exact, size_t *val_len, WriteMethod **write_method)
+{
+  switch (v->magic)
+    {
+    case IPCIDRROUTEDEST:
+      break;
+    default:
+      return NULL;
+      break;
+    }  
+  return NULL;
+}
+
+void
+zebra_snmp_init ()
+{
+  smux_init (zebra_oid, sizeof (zebra_oid) / sizeof (oid));
+  REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid);
+  smux_start ();
+}
+#endif /* HAVE_SNMP */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
new file mode 100644 (file)
index 0000000..f6e7f51
--- /dev/null
@@ -0,0 +1,1554 @@
+/* Zebra VTY functions
+ * Copyright (C) 2002 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "table.h"
+#include "rib.h"
+
+/* Return route type string for VTY output.  */
+const char *
+route_type_str (u_char type)
+{
+  switch (type)
+    {
+    case ZEBRA_ROUTE_SYSTEM:
+      return "system";
+    case ZEBRA_ROUTE_KERNEL:
+      return "kernel";
+    case ZEBRA_ROUTE_CONNECT:
+      return "connected";
+    case ZEBRA_ROUTE_STATIC:
+      return "static";
+    case ZEBRA_ROUTE_RIP:
+      return "rip";
+    case ZEBRA_ROUTE_RIPNG:
+      return "rip";
+    case ZEBRA_ROUTE_OSPF:
+      return "ospf";
+    case ZEBRA_ROUTE_OSPF6:
+      return "ospf";
+    case ZEBRA_ROUTE_BGP:
+      return "bgp";
+    default:
+      return "unknown";
+    }
+};
+
+/* Return route type string for VTY output.  */
+const char
+route_type_char (u_char type)
+{
+  switch (type)
+    {
+    case ZEBRA_ROUTE_SYSTEM:
+      return 'S';
+    case ZEBRA_ROUTE_KERNEL:
+      return 'K';
+    case ZEBRA_ROUTE_CONNECT:
+      return 'C';
+    case ZEBRA_ROUTE_STATIC:
+      return 'S';
+    case ZEBRA_ROUTE_RIP:
+      return 'R';
+    case ZEBRA_ROUTE_RIPNG:
+      return 'R';
+    case ZEBRA_ROUTE_OSPF:
+      return 'O';
+    case ZEBRA_ROUTE_OSPF6:
+      return 'O';
+    case ZEBRA_ROUTE_BGP:
+      return 'B';
+    default:
+      return '?';
+    }
+};
+\f
+/* General fucntion for static route. */
+int
+zebra_static_ipv4 (struct vty *vty, int add_cmd,
+                  char *dest_str, char *mask_str, char *gate_str,
+                  char *distance_str)
+{
+  int ret;
+  u_char distance;
+  struct prefix p;
+  struct in_addr gate;
+  struct in_addr mask;
+  char *ifname;
+  
+  ret = str2prefix (dest_str, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Cisco like mask notation. */
+  if (mask_str)
+    {
+      ret = inet_aton (mask_str, &mask);
+      if (ret == 0)
+       {
+         vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      p.prefixlen = ip_masklen (mask);
+    }
+
+  /* Apply mask for given prefix. */
+  apply_mask (&p);
+
+  /* Administrative distance. */
+  if (distance_str)
+    distance = atoi (distance_str);
+  else
+    distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+  /* Null0 static route.  */
+  if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)
+    {
+      if (add_cmd)
+       static_add_ipv4 (&p, NULL, NULL, distance, 0);
+      else
+       static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+      return CMD_SUCCESS;
+    }
+
+  /* When gateway is A.B.C.D format, gate is treated as nexthop
+     address other case gate is treated as interface name. */
+  ret = inet_aton (gate_str, &gate);
+  if (ret)
+    ifname = NULL;
+  else
+    ifname = gate_str;
+
+  if (add_cmd)
+    static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+  else
+    static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+
+  return CMD_SUCCESS;
+}
+
+/* Static route configuration.  */
+DEFUN (ip_route, 
+       ip_route_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL);
+}
+
+/* Mask as A.B.C.D format.  */
+DEFUN (ip_route_mask,
+       ip_route_mask_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+/* Distance option value.  */
+DEFUN (ip_route_distance,
+       ip_route_distance_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (ip_route_mask_distance,
+       ip_route_mask_distance_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ip_route, 
+       no_ip_route_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL);
+}
+
+DEFUN (no_ip_route_mask,
+       no_ip_route_mask_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ip_route_distance,
+       no_ip_route_distance_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (no_ip_route_mask_distance,
+       no_ip_route_mask_distance_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3]);
+}
+
+/* New RIB.  Detailed information for IPv4 route. */
+void
+vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
+{
+  struct rib *rib;
+  struct nexthop *nexthop;
+
+  for (rib = rn->info; rib; rib = rib->next)
+    {
+      vty_out (vty, "Routing entry for %s/%d%s", 
+              inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+              VTY_NEWLINE);
+      vty_out (vty, "  Known via \"%s\"", route_type_str (rib->type));
+      vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+       vty_out (vty, ", best");
+      if (rib->refcnt)
+       vty_out (vty, ", refcnt %ld", rib->refcnt);
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+      if (rib->type == ZEBRA_ROUTE_RIP
+         || rib->type == ZEBRA_ROUTE_OSPF
+         || rib->type == ZEBRA_ROUTE_BGP)
+       {
+         time_t uptime;
+         struct tm *tm;
+
+         uptime = time (NULL);
+         uptime -= rib->uptime;
+         tm = gmtime (&uptime);
+
+         vty_out (vty, "  Last update ");
+
+         if (uptime < ONE_DAY_SECOND)
+           vty_out (vty,  "%02d:%02d:%02d", 
+                    tm->tm_hour, tm->tm_min, tm->tm_sec);
+         else if (uptime < ONE_WEEK_SECOND)
+           vty_out (vty, "%dd%02dh%02dm", 
+                    tm->tm_yday, tm->tm_hour, tm->tm_min);
+         else
+           vty_out (vty, "%02dw%dd%02dh", 
+                    tm->tm_yday/7,
+                    tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+         vty_out (vty, " ago%s", VTY_NEWLINE);
+       }
+
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       {
+         vty_out (vty, "  %c",
+                  CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+         switch (nexthop->type)
+           {
+           case NEXTHOP_TYPE_IPV4:
+           case NEXTHOP_TYPE_IPV4_IFINDEX:
+             vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4));
+             if (nexthop->ifindex)
+               vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+             break;
+           case NEXTHOP_TYPE_IFINDEX:
+             vty_out (vty, " directly connected, %s",
+                      ifindex2ifname (nexthop->ifindex));
+             break;
+           case NEXTHOP_TYPE_IFNAME:
+             vty_out (vty, " directly connected, %s", nexthop->ifname);
+             break;
+           case NEXTHOP_TYPE_BLACKHOLE:
+             vty_out (vty, " directly connected, via Null0");
+             break;
+           default:
+             break;
+           }
+         if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+           vty_out (vty, " inactive");
+
+         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+           {
+             vty_out (vty, " (recursive");
+               
+             switch (nexthop->rtype)
+               {
+               case NEXTHOP_TYPE_IPV4:
+               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                 vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+                 break;
+               case NEXTHOP_TYPE_IFINDEX:
+               case NEXTHOP_TYPE_IFNAME:
+                 vty_out (vty, " is directly connected, %s)",
+                          ifindex2ifname (nexthop->rifindex));
+                 break;
+               default:
+                 break;
+               }
+           }
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+void
+vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
+{
+  struct nexthop *nexthop;
+  int len = 0;
+  char buf[BUFSIZ];
+
+  /* Nexthop information. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (nexthop == rib->nexthop)
+       {
+         /* Prefix information. */
+         len = vty_out (vty, "%c%c%c %s/%d",
+                        route_type_char (rib->type),
+                        CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+                        ? '>' : ' ',
+                        CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+                        ? '*' : ' ',
+                        inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ),
+                        rn->p.prefixlen);
+               
+         /* Distance and metric display. */
+         if (rib->type != ZEBRA_ROUTE_CONNECT 
+             && rib->type != ZEBRA_ROUTE_KERNEL)
+           len += vty_out (vty, " [%d/%d]", rib->distance,
+                           rib->metric);
+       }
+      else
+       vty_out (vty, "  %c%*c",
+                CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+                ? '*' : ' ',
+                len - 3, ' ');
+
+      switch (nexthop->type)
+       {
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+         vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
+         if (nexthop->ifindex)
+           vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+         break;
+       case NEXTHOP_TYPE_IFINDEX:
+         vty_out (vty, " is directly connected, %s",
+                  ifindex2ifname (nexthop->ifindex));
+         break;
+       case NEXTHOP_TYPE_IFNAME:
+         vty_out (vty, " is directly connected, %s", nexthop->ifname);
+         break;
+       case NEXTHOP_TYPE_BLACKHOLE:
+         vty_out (vty, " is directly connected, Null0");
+       default:
+         break;
+       }
+      if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+       vty_out (vty, " inactive");
+
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+       {
+         vty_out (vty, " (recursive");
+               
+         switch (nexthop->rtype)
+           {
+           case NEXTHOP_TYPE_IPV4:
+           case NEXTHOP_TYPE_IPV4_IFINDEX:
+             vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+             break;
+           case NEXTHOP_TYPE_IFINDEX:
+           case NEXTHOP_TYPE_IFNAME:
+             vty_out (vty, " is directly connected, %s)",
+                      ifindex2ifname (nexthop->rifindex));
+             break;
+           default:
+             break;
+           }
+       }
+
+      if (rib->type == ZEBRA_ROUTE_RIP
+         || rib->type == ZEBRA_ROUTE_OSPF
+         || rib->type == ZEBRA_ROUTE_BGP)
+       {
+         time_t uptime;
+         struct tm *tm;
+
+         uptime = time (NULL);
+         uptime -= rib->uptime;
+         tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+         if (uptime < ONE_DAY_SECOND)
+           vty_out (vty,  ", %02d:%02d:%02d", 
+                    tm->tm_hour, tm->tm_min, tm->tm_sec);
+         else if (uptime < ONE_WEEK_SECOND)
+           vty_out (vty, ", %dd%02dh%02dm", 
+                    tm->tm_yday, tm->tm_hour, tm->tm_min);
+         else
+           vty_out (vty, ", %02dw%dd%02dh", 
+                    tm->tm_yday/7,
+                    tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s       B - BGP, > - selected route, * - FIB route%s%s"
+
+DEFUN (show_ip_route,
+       show_ip_route_cmd,
+       "show ip route",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+       if (first)
+         {
+           vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
+                    VTY_NEWLINE);
+           first = 0;
+         }
+       vty_show_ip_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix_longer,
+       show_ip_route_prefix_longer_cmd,
+       "show ip route A.B.C.D/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Show route matching the specified Network/Mask pair only\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct prefix p;
+  int ret;
+  int first = 1;
+
+  ret = str2prefix (argv[0], &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (prefix_match (&p, &rn->p))
+       {
+         if (first)
+           {
+             vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
+                      VTY_NEWLINE, VTY_NEWLINE);
+             first = 0;
+           }
+         vty_show_ip_route (vty, rn, rib);
+       }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_supernets,
+       show_ip_route_supernets_cmd,
+       "show ip route supernets-only",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Show supernet entries only\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  u_int32_t addr; 
+  int first = 1;
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+       addr = ntohl (rn->p.u.prefix4.s_addr);
+
+       if ((IN_CLASSC (addr) && rn->p.prefixlen < 24)
+          || (IN_CLASSB (addr) && rn->p.prefixlen < 16)
+          || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) 
+         {
+           if (first)
+             {
+               vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
+                        VTY_NEWLINE, VTY_NEWLINE);
+               first = 0;
+             }
+           vty_show_ip_route (vty, rn, rib);
+         }
+      }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_protocol,
+       show_ip_route_protocol_cmd,
+       "show ip route (bgp|connected|kernel|ospf|rip|static)",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Connected\n"
+       "Kernel\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Routing Information Protocol (RIP)\n"
+       "Static routes\n")
+{
+  int type;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  if (strncmp (argv[0], "b", 1) == 0)
+    type = ZEBRA_ROUTE_BGP;
+  else if (strncmp (argv[0], "c", 1) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "k", 1) ==0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "o", 1) == 0)
+    type = ZEBRA_ROUTE_OSPF;
+  else if (strncmp (argv[0], "r", 1) == 0)
+    type = ZEBRA_ROUTE_RIP;
+  else if (strncmp (argv[0], "s", 1) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else 
+    {
+      vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (rib->type == type)
+       {
+         if (first)
+           {
+             vty_out (vty, SHOW_ROUTE_V4_HEADER,
+                      VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+             first = 0;
+           }
+         vty_show_ip_route (vty, rn, rib);
+       }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_addr,
+       show_ip_route_addr_cmd,
+       "show ip route A.B.C.D",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Network in the IP routing table to display\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ip_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix,
+       show_ip_route_prefix_cmd,
+       "show ip route A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn || rn->p.prefixlen != p.prefixlen)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ip_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+zebra_show_ip_route (struct vty *vty, struct vrf *vrf)
+{
+  vty_out (vty, "IP routing table name is %s(%d)%s",
+          vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE);
+
+  vty_out (vty, "Route Source    Networks%s", VTY_NEWLINE);
+  vty_out (vty, "connected       %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, "static          %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, "rip             %d%s", 0, VTY_NEWLINE);
+
+  vty_out (vty, "bgp             %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, " External: %d Internal: %d Local: %d%s",
+          0, 0, 0, VTY_NEWLINE);
+
+  vty_out (vty, "ospf            %d%s", 0, VTY_NEWLINE);
+  vty_out (vty,
+          "  Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s",
+          0, 0, 0, 0, VTY_NEWLINE);
+  vty_out (vty, "  NSSA External-1: %d NSSA External-2: %d%s",
+          0, 0, VTY_NEWLINE);
+
+  vty_out (vty, "internal        %d%s", 0, VTY_NEWLINE);
+  vty_out (vty, "Total           %d%s", 0, VTY_NEWLINE);
+}
+
+/* Show route summary.  */
+DEFUN (show_ip_route_summary,
+       show_ip_route_summary_cmd,
+       "show ip route summary",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Summary of all routes\n")
+{
+  struct vrf *vrf;
+
+  /* Default table id is zero.  */
+  vrf = vrf_lookup (0);
+  if (! vrf)
+    {
+      vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zebra_show_ip_route (vty, vrf);
+
+  return CMD_SUCCESS;
+}
+
+/* Write IPv4 static route configuration. */
+int
+static_config_ipv4 (struct vty *vty)
+{
+  struct route_node *rn;
+  struct static_ipv4 *si;  
+  struct route_table *stable;
+  int write;
+
+  write = 0;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! stable)
+    return -1;
+
+  for (rn = route_top (stable); rn; rn = route_next (rn))
+    for (si = rn->info; si; si = si->next)
+      {
+       vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4),
+                rn->p.prefixlen);
+
+       switch (si->type)
+         {
+         case STATIC_IPV4_GATEWAY:
+           vty_out (vty, " %s", inet_ntoa (si->gate.ipv4));
+           break;
+         case STATIC_IPV4_IFNAME:
+           vty_out (vty, " %s", si->gate.ifname);
+           break;
+         case STATIC_IPV4_BLACKHOLE:
+           vty_out (vty, " Null0");
+           break;
+         }
+
+       if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+         vty_out (vty, " %d", si->distance);
+       vty_out (vty, "%s", VTY_NEWLINE);
+
+       write = 1;
+      }
+  return write;
+}
+\f
+#ifdef HAVE_IPV6
+/* General fucntion for IPv6 static route. */
+int
+static_ipv6_func (struct vty *vty, int add_cmd, char *dest_str,
+                 char *gate_str, char *ifname, char *distance_str)
+{
+  int ret;
+  u_char distance;
+  struct prefix p;
+  struct in6_addr *gate = NULL;
+  struct in6_addr gate_addr;
+  u_char type = 0;
+  int table = 0;
+  
+  ret = str2prefix (dest_str, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Apply mask for given prefix. */
+  apply_mask (&p);
+
+  /* Administrative distance. */
+  if (distance_str)
+    distance = atoi (distance_str);
+  else
+    distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+  /* When gateway is valid IPv6 addrees, then gate is treated as
+     nexthop address other case gate is treated as interface name. */
+  ret = inet_pton (AF_INET6, gate_str, &gate_addr);
+
+  if (ifname)
+    {
+      /* When ifname is specified.  It must be come with gateway
+         address. */
+      if (ret != 1)
+       {
+         vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      type = STATIC_IPV6_GATEWAY_IFNAME;
+      gate = &gate_addr;
+    }
+  else
+    {
+      if (ret == 1)
+       {
+         type = STATIC_IPV6_GATEWAY;
+         gate = &gate_addr;
+       }
+      else
+       {
+         type = STATIC_IPV6_IFNAME;
+         ifname = gate_str;
+       }
+    }
+
+  if (add_cmd)
+    static_add_ipv6 (&p, type, gate, ifname, distance, table);
+  else
+    static_delete_ipv6 (&p, type, gate, ifname, distance, table);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_route,
+       ipv6_route_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+       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_type_str (rib->type));
+      vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+       vty_out (vty, ", best");
+      if (rib->refcnt)
+       vty_out (vty, ", refcnt %ld", rib->refcnt);
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+      if (rib->type == ZEBRA_ROUTE_RIPNG
+         || rib->type == ZEBRA_ROUTE_OSPF6
+         || rib->type == ZEBRA_ROUTE_BGP)
+       {
+         time_t uptime;
+         struct tm *tm;
+
+         uptime = time (NULL);
+         uptime -= rib->uptime;
+         tm = gmtime (&uptime);
+
+         vty_out (vty, "  Last update ");
+
+         if (uptime < ONE_DAY_SECOND)
+           vty_out (vty,  "%02d:%02d:%02d", 
+                    tm->tm_hour, tm->tm_min, tm->tm_sec);
+         else if (uptime < ONE_WEEK_SECOND)
+           vty_out (vty, "%dd%02dh%02dm", 
+                    tm->tm_yday, tm->tm_hour, tm->tm_min);
+         else
+           vty_out (vty, "%02dw%dd%02dh", 
+                    tm->tm_yday/7,
+                    tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+         vty_out (vty, " ago%s", VTY_NEWLINE);
+       }
+
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       {
+         vty_out (vty, "  %c",
+                  CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+         switch (nexthop->type)
+           {
+           case NEXTHOP_TYPE_IPV6:
+           case NEXTHOP_TYPE_IPV6_IFINDEX:
+           case NEXTHOP_TYPE_IPV6_IFNAME:
+             vty_out (vty, " %s",
+                      inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+             if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+               vty_out (vty, ", %s", nexthop->ifname);
+             else if (nexthop->ifindex)
+               vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+             break;
+           case NEXTHOP_TYPE_IFINDEX:
+             vty_out (vty, " directly connected, %s",
+                      ifindex2ifname (nexthop->ifindex));
+             break;
+           case NEXTHOP_TYPE_IFNAME:
+             vty_out (vty, " directly connected, %s",
+                      nexthop->ifname);
+             break;
+           default:
+             break;
+           }
+         if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+           vty_out (vty, " inactive");
+
+         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+           {
+             vty_out (vty, " (recursive");
+               
+             switch (nexthop->rtype)
+               {
+               case NEXTHOP_TYPE_IPV6:
+               case NEXTHOP_TYPE_IPV6_IFINDEX:
+               case NEXTHOP_TYPE_IPV6_IFNAME:
+                 vty_out (vty, " via %s)",
+                          inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
+                                     buf, BUFSIZ));
+                 if (nexthop->rifindex)
+                   vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
+                 break;
+               case NEXTHOP_TYPE_IFINDEX:
+               case NEXTHOP_TYPE_IFNAME:
+                 vty_out (vty, " is directly connected, %s)",
+                          ifindex2ifname (nexthop->rifindex));
+                 break;
+               default:
+                 break;
+               }
+           }
+         vty_out (vty, "%s", VTY_NEWLINE);
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+void
+vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
+                    struct rib *rib)
+{
+  struct nexthop *nexthop;
+  int len = 0;
+  char buf[BUFSIZ];
+
+  /* Nexthop information. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (nexthop == rib->nexthop)
+       {
+         /* Prefix information. */
+         len = vty_out (vty, "%c%c%c %s/%d",
+                        route_type_char (rib->type),
+                        CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+                        ? '>' : ' ',
+                        CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+                        ? '*' : ' ',
+                        inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+                        rn->p.prefixlen);
+
+         /* Distance and metric display. */
+         if (rib->type != ZEBRA_ROUTE_CONNECT 
+             && rib->type != ZEBRA_ROUTE_KERNEL)
+           len += vty_out (vty, " [%d/%d]", rib->distance,
+                           rib->metric);
+       }
+      else
+       vty_out (vty, "  %c%*c",
+                CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+                ? '*' : ' ',
+                len - 3, ' ');
+
+      switch (nexthop->type)
+       {
+       case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+       case NEXTHOP_TYPE_IPV6_IFNAME:
+         vty_out (vty, " via %s",
+                  inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+         if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+           vty_out (vty, ", %s", nexthop->ifname);
+         else if (nexthop->ifindex)
+           vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+         break;
+       case NEXTHOP_TYPE_IFINDEX:
+         vty_out (vty, " is directly connected, %s",
+                  ifindex2ifname (nexthop->ifindex));
+         break;
+       case NEXTHOP_TYPE_IFNAME:
+         vty_out (vty, " is directly connected, %s",
+                  nexthop->ifname);
+         break;
+       default:
+         break;
+       }
+      if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+       vty_out (vty, " inactive");
+
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+       {
+         vty_out (vty, " (recursive");
+               
+         switch (nexthop->rtype)
+           {
+           case NEXTHOP_TYPE_IPV6:
+           case NEXTHOP_TYPE_IPV6_IFINDEX:
+           case NEXTHOP_TYPE_IPV6_IFNAME:
+             vty_out (vty, " via %s)",
+                      inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
+                                 buf, BUFSIZ));
+             if (nexthop->rifindex)
+               vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
+             break;
+           case NEXTHOP_TYPE_IFINDEX:
+           case NEXTHOP_TYPE_IFNAME:
+             vty_out (vty, " is directly connected, %s)",
+                      ifindex2ifname (nexthop->rifindex));
+             break;
+           default:
+             break;
+           }
+       }
+
+      if (rib->type == ZEBRA_ROUTE_RIPNG
+         || rib->type == ZEBRA_ROUTE_OSPF6
+         || rib->type == ZEBRA_ROUTE_BGP)
+       {
+         time_t uptime;
+         struct tm *tm;
+
+         uptime = time (NULL);
+         uptime -= rib->uptime;
+         tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+         if (uptime < ONE_DAY_SECOND)
+           vty_out (vty,  ", %02d:%02d:%02d", 
+                    tm->tm_hour, tm->tm_min, tm->tm_sec);
+         else if (uptime < ONE_WEEK_SECOND)
+           vty_out (vty, ", %dd%02dh%02dm", 
+                    tm->tm_yday, tm->tm_hour, tm->tm_min);
+         else
+           vty_out (vty, ", %02dw%dd%02dh", 
+                    tm->tm_yday/7,
+                    tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+       }
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+}
+
+#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3,%s       B - BGP, * - FIB route.%s%s"
+
+DEFUN (show_ipv6_route,
+       show_ipv6_route_cmd,
+       "show ipv6 route",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv6 route. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+       if (first)
+         {
+           vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+           first = 0;
+         }
+       vty_show_ipv6_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_prefix_longer,
+       show_ipv6_route_prefix_longer_cmd,
+       "show ipv6 route X:X::X:X/M longer-prefixes",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "IPv6 prefix\n"
+       "Show route matching the specified Network/Mask pair only\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct prefix p;
+  int ret;
+  int first = 1;
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  ret = str2prefix (argv[0], &p);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Show matched type IPv6 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (prefix_match (&p, &rn->p))
+       {
+         if (first)
+           {
+             vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+             first = 0;
+           }
+         vty_show_ipv6_route (vty, rn, rib);
+       }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_protocol,
+       show_ipv6_route_protocol_cmd,
+       "show ipv6 route (bgp|connected|kernel|ospf6|ripng|static)",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Connected\n"
+       "Kernel\n"
+       "Open Shortest Path First (OSPFv3)\n"
+       "Routing Information Protocol (RIPng)\n"
+       "Static routes\n")
+{
+  int type;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  if (strncmp (argv[0], "b", 1) == 0)
+    type = ZEBRA_ROUTE_BGP;
+  else if (strncmp (argv[0], "c", 1) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "k", 1) ==0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "o", 1) == 0)
+    type = ZEBRA_ROUTE_OSPF6;
+  else if (strncmp (argv[0], "r", 1) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "s", 1) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else 
+    {
+      vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show matched type IPv6 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      if (rib->type == type)
+       {
+         if (first)
+           {
+             vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+             first = 0;
+           }
+         vty_show_ipv6_route (vty, rn, rib);
+       }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_addr,
+       show_ipv6_route_addr_cmd,
+       "show ipv6 route X:X::X:X",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "IPv6 Address\n")
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv6 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ipv6_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_prefix,
+       show_ipv6_route_prefix_cmd,
+       "show ipv6 route X:X::X:X/M",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "IPv6 prefix\n")
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_table *table;
+  struct route_node *rn;
+
+  ret = str2prefix_ipv6 (argv[0], &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (! rn || rn->p.prefixlen != p.prefixlen)
+    {
+      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vty_show_ipv6_route_detail (vty, rn);
+
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+
+/* Write IPv6 static route configuration. */
+int
+static_config_ipv6 (struct vty *vty)
+{
+  struct route_node *rn;
+  struct static_ipv6 *si;  
+  int write;
+  char buf[BUFSIZ];
+  struct route_table *stable;
+
+  write = 0;
+
+  /* Lookup table.  */
+  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! stable)
+    return -1;
+
+  for (rn = route_top (stable); rn; rn = route_next (rn))
+    for (si = rn->info; si; si = si->next)
+      {
+       vty_out (vty, "ipv6 route %s/%d",
+                inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+                rn->p.prefixlen);
+
+       switch (si->type)
+         {
+         case STATIC_IPV6_GATEWAY:
+           vty_out (vty, " %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ));
+           break;
+         case STATIC_IPV6_IFNAME:
+           vty_out (vty, " %s", si->ifname);
+           break;
+         case STATIC_IPV6_GATEWAY_IFNAME:
+           vty_out (vty, " %s %s",
+                    inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname);
+           break;
+         }
+
+       if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+         vty_out (vty, " %d", si->distance);
+       vty_out (vty, "%s", VTY_NEWLINE);
+
+       write = 1;
+      }
+  return write;
+}
+#endif /* HAVE_IPV6 */
+
+/* Static ip route configuration write function. */
+int
+zebra_ip_config (struct vty *vty)
+{
+  int write = 0;
+
+  write += static_config_ipv4 (vty);
+#ifdef HAVE_IPV6
+  write += static_config_ipv6 (vty);
+#endif /* HAVE_IPV6 */
+
+  return write;
+}
+
+/* IP node for static routes. */
+struct cmd_node ip_node = { IP_NODE,  "",  1 };
+
+/* Route VTY.  */
+void
+zebra_vty_route_init ()
+{
+  install_node (&ip_node, zebra_ip_config);
+
+  install_element (CONFIG_NODE, &ip_route_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_cmd);
+  install_element (CONFIG_NODE, &ip_route_distance_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd);
+
+  install_element (VIEW_NODE, &show_ip_route_cmd);
+  install_element (VIEW_NODE, &show_ip_route_addr_cmd);
+  install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_route_protocol_cmd);
+  install_element (VIEW_NODE, &show_ip_route_supernets_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_protocol_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_supernets_cmd);
+
+#if 0
+  install_element (VIEW_NODE, &show_ip_route_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_summary_cmd);
+#endif /* 0 */
+
+#ifdef HAVE_IPV6
+  install_element (CONFIG_NODE, &ipv6_route_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_pref_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_addr_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd);
+#endif /* HAVE_IPV6 */
+}
+
+void
+zebra_vty_init ()
+{
+  zebra_vty_route_init ();
+}
diff --git a/zebra/zserv.c b/zebra/zserv.c
new file mode 100644 (file)
index 0000000..47114ab
--- /dev/null
@@ -0,0 +1,1806 @@
+/* Zebra daemon server routine.
+ * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "command.h"
+#include "if.h"
+#include "thread.h"
+#include "stream.h"
+#include "memory.h"
+#include "table.h"
+#include "rib.h"
+#include "network.h"
+#include "sockunion.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+#include "zebra/ipforward.h"
+\f
+/* Event list of zebra. */
+enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
+
+/* Zebra client list. */
+list client_list;
+
+/* Default rtm_table for all clients */
+int rtm_table_default = 0;
+
+void zebra_event (enum event event, int sock, struct zserv *client);
+\f
+/* For logging of zebra meesages. */
+char *zebra_command_str [] =
+{
+  "NULL",
+  "ZEBRA_INTERFACE_ADD",
+  "ZEBRA_INTERFACE_DELETE",
+  "ZEBRA_INTERFACE_ADDRESS_ADD",
+  "ZEBRA_INTERFACE_ADDRESS_DELETE",
+  "ZEBRA_INTERFACE_UP",
+  "ZEBRA_INTERFACE_DOWN",
+  "ZEBRA_IPV4_ROUTE_ADD",
+  "ZEBRA_IPV4_ROUTE_DELETE",
+  "ZEBRA_IPV6_ROUTE_ADD",
+  "ZEBRA_IPV6_ROUTE_DELETE",
+  "ZEBRA_REDISTRIBUTE_ADD",
+  "ZEBRA_REDISTRIBUTE_DELETE",
+  "ZEBRA_REDISTRIBUTE_DEFAULT_ADD",
+  "ZEBRA_REDISTRIBUTE_DEFAULT_DELETE",
+  "ZEBRA_IPV4_NEXTHOP_LOOKUP",
+  "ZEBRA_IPV6_NEXTHOP_LOOKUP",
+  "ZEBRA_IPV4_IMPORT_LOOKUP",
+  "ZEBRA_IPV6_IMPORT_LOOKUP"
+};
+\f
+/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
+int
+zsend_interface_add (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Message type. */
+  stream_putc (s, ZEBRA_INTERFACE_ADD);
+
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+#ifdef HAVE_SOCKADDR_DL
+  stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
+#else
+  stream_putl (s, ifp->hw_addr_len);
+  if (ifp->hw_addr_len)
+    stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
+#endif /* HAVE_SOCKADDR_DL */
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Interface deletion from zebra daemon. */
+int
+zsend_interface_delete (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Packet length placeholder. */
+  stream_putw (s, 0);
+
+  /* Interface information. */
+  stream_putc (s, ZEBRA_INTERFACE_DELETE);
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+
+  /* Write packet length. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Interface address is added. Send ZEBRA_INTERFACE_ADDRESS_ADD to the
+   client. */
+int
+zsend_interface_address_add (struct zserv *client, struct interface *ifp, 
+                            struct connected *ifc)
+{
+  int blen;
+  struct stream *s;
+  struct prefix *p;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  stream_putc (s, ZEBRA_INTERFACE_ADDRESS_ADD);
+  stream_putl (s, ifp->ifindex);
+
+  /* Interface address flag. */
+  stream_putc (s, ifc->flags);
+
+  /* Prefix information. */
+  p = ifc->address;
+  stream_putc (s, p->family);
+  blen = prefix_blen (p);
+  stream_put (s, &p->u.prefix, blen);
+  stream_putc (s, p->prefixlen);
+
+  /* Destination. */
+  p = ifc->destination;
+  if (p)
+    stream_put (s, &p->u.prefix, blen);
+  else
+    stream_put (s, NULL, blen);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+/* Interface address is deleted. Send ZEBRA_INTERFACE_ADDRESS_DELETE
+   to the client. */
+int
+zsend_interface_address_delete (struct zserv *client, struct interface *ifp,
+                               struct connected *ifc)
+{
+  int blen;
+  struct stream *s;
+  struct prefix *p;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  stream_putc (s, ZEBRA_INTERFACE_ADDRESS_DELETE);
+  stream_putl (s, ifp->ifindex);
+
+  /* Interface address flag. */
+  stream_putc (s, ifc->flags);
+
+  /* Prefix information. */
+  p = ifc->address;
+  stream_putc (s, p->family);
+  blen = prefix_blen (p);
+  stream_put (s, &p->u.prefix, blen);
+
+  p = ifc->destination;
+  if (p)
+    stream_put (s, &p->u.prefix, blen);
+  else
+    stream_put (s, NULL, blen);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_interface_up (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Zebra command. */
+  stream_putc (s, ZEBRA_INTERFACE_UP);
+
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_interface_down (struct zserv *client, struct interface *ifp)
+{
+  struct stream *s;
+
+  /* Check this client need interface information. */
+  if (! client->ifinfo)
+    return -1;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Zebra command. */
+  stream_putc (s, ZEBRA_INTERFACE_DOWN);
+
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->bandwidth);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_add_multipath (struct zserv *client, struct prefix *p, 
+                         struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in_addr empty;
+
+  empty.s_addr = 0;
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_METRIC);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+       {
+         stream_putc (s, 1);
+
+         if (nexthop->type == NEXTHOP_TYPE_IPV4
+             || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+           stream_put_in_addr (s, &nexthop->gate.ipv4);
+         else
+           stream_put_in_addr (s, &empty);
+
+         /* Interface index. */
+         stream_putc (s, 1);
+         stream_putl (s, nexthop->ifindex);
+
+         break;
+       }
+    }
+
+  /* Metric */
+  stream_putl (s, rib->metric);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_delete_multipath (struct zserv *client, struct prefix *p,
+                            struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in_addr empty;
+
+  empty.s_addr = 0;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+       {
+         stream_putc (s, 1);
+
+         if (nexthop->type == NEXTHOP_TYPE_IPV4)
+           stream_put_in_addr (s, &nexthop->gate.ipv4);
+         else
+           stream_put_in_addr (s, &empty);
+
+         /* Interface index. */
+         stream_putc (s, 1);
+         stream_putl (s, nexthop->ifindex);
+
+         break;
+       }
+    }
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_add (struct zserv *client, int type, int flags,
+               struct prefix_ipv4 *p, struct in_addr *nexthop,
+               unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_put_in_addr (s, nexthop);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_delete (struct zserv *client, int type, int flags,
+                  struct prefix_ipv4 *p, struct in_addr *nexthop,
+                  unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_put_in_addr (s, nexthop);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+#ifdef HAVE_IPV6
+int
+zsend_ipv6_add (struct zserv *client, int type, int flags,
+               struct prefix_ipv6 *p, struct in6_addr *nexthop,
+               unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_ADD);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_write (s, (u_char *)nexthop, 16);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_add_multipath (struct zserv *client, struct prefix *p,
+                         struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in6_addr empty;
+
+  memset (&empty, 0, sizeof (struct in6_addr));
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_ADD);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_METRIC);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *) &p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+       {
+         stream_putc (s, 1);
+
+         if (nexthop->type == NEXTHOP_TYPE_IPV6)
+           stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
+         else
+           stream_write (s, (u_char *) &empty, 16);
+
+         /* Interface index. */
+         stream_putc (s, 1);
+         stream_putl (s, nexthop->ifindex);
+
+         break;
+       }
+    }
+
+  /* Metric */
+  stream_putl (s, rib->metric);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_delete (struct zserv *client, int type, int flags,
+                  struct prefix_ipv6 *p, struct in6_addr *nexthop,
+                  unsigned int ifindex)
+{
+  int psize;
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE);
+  stream_putc (s, type);
+  stream_putc (s, flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop */
+  stream_putc (s, 1);
+  stream_write (s, (u_char *)nexthop, 16);
+
+  /* Interface index. */
+  stream_putc (s, 1);
+  stream_putl (s, ifindex);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_delete_multipath (struct zserv *client, struct prefix *p,
+                            struct rib *rib)
+{
+  int psize;
+  struct stream *s;
+  struct nexthop *nexthop;
+  struct in6_addr empty;
+
+  memset (&empty, 0, sizeof (struct in6_addr));
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Place holder for size. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE);
+  stream_putc (s, rib->type);
+  stream_putc (s, rib->flags);
+  stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX);
+
+  /* Prefix. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->u.prefix, psize);
+
+  /* Nexthop */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+       {
+         stream_putc (s, 1);
+
+         if (nexthop->type == NEXTHOP_TYPE_IPV6)
+           stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
+         else
+           stream_write (s, (u_char *) &empty, 16);
+
+         /* Interface index. */
+         stream_putc (s, 1);
+         stream_putl (s, nexthop->ifindex);
+
+         break;
+       }
+    }
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_match_ipv6 (addr);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
+  stream_put (s, &addr, 16);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = s->putp;
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+         {
+           stream_putc (s, nexthop->type);
+           switch (nexthop->type)
+             {
+             case ZEBRA_NEXTHOP_IPV6:
+               stream_put (s, &nexthop->gate.ipv6, 16);
+               break;
+             case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+             case ZEBRA_NEXTHOP_IPV6_IFNAME:
+               stream_put (s, &nexthop->gate.ipv6, 16);
+               stream_putl (s, nexthop->ifindex);
+               break;
+             case ZEBRA_NEXTHOP_IFINDEX:
+             case ZEBRA_NEXTHOP_IFNAME:
+               stream_putl (s, nexthop->ifindex);
+               break;
+             }
+           num++;
+         }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+#endif /* HAVE_IPV6 */
+
+int
+zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_match_ipv4 (addr);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
+  stream_put_in_addr (s, &addr);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = s->putp;
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+         {
+           stream_putc (s, nexthop->type);
+           switch (nexthop->type)
+             {
+             case ZEBRA_NEXTHOP_IPV4:
+               stream_put_in_addr (s, &nexthop->gate.ipv4);
+               break;
+             case ZEBRA_NEXTHOP_IFINDEX:
+             case ZEBRA_NEXTHOP_IFNAME:
+               stream_putl (s, nexthop->ifindex);
+               break;
+             }
+           num++;
+         }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+int
+zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_lookup_ipv4 (p);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP);
+  stream_put_in_addr (s, &p->prefix);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = s->putp;
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+       if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+         {
+           stream_putc (s, nexthop->type);
+           switch (nexthop->type)
+             {
+             case ZEBRA_NEXTHOP_IPV4:
+               stream_put_in_addr (s, &nexthop->gate.ipv4);
+               break;
+             case ZEBRA_NEXTHOP_IFINDEX:
+             case ZEBRA_NEXTHOP_IFNAME:
+               stream_putl (s, nexthop->ifindex);
+               break;
+             }
+           num++;
+         }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+\f
+/* Register zebra server interface information.  Send current all
+   interface and address information. */
+void
+zread_interface_add (struct zserv *client, u_short length)
+{
+  listnode ifnode;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *c;
+
+  /* Interface information is needed. */
+  client->ifinfo = 1;
+
+  for (ifnode = listhead (iflist); ifnode; ifnode = nextnode (ifnode))
+    {
+      ifp = getdata (ifnode);
+
+      /* Skip pseudo interface. */
+      if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+       continue;
+
+      zsend_interface_add (client, ifp);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+       {
+         c = getdata (cnode);
+         if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL))
+           zsend_interface_address_add (client, ifp, c);
+       }
+    }
+}
+
+/* Unregister zebra server interface information. */
+void
+zread_interface_delete (struct zserv *client, u_short length)
+{
+  client->ifinfo = 0;
+}
+
+/* This function support multiple nexthop. */
+void
+zread_ipv4_add (struct zserv *client, u_short length)
+{
+  int i;
+  struct rib *rib;
+  struct prefix_ipv4 p;
+  u_char message;
+  struct in_addr nexthop;
+  u_char nexthop_num;
+  u_char nexthop_type;
+  struct stream *s;
+  unsigned int ifindex;
+  u_char ifname_len;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  /* Allocate new rib. */
+  rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+  memset (rib, 0, sizeof (struct rib));
+
+  /* Type, flags, message. */
+  rib->type = stream_getc (s);
+  rib->flags = stream_getc (s);
+  message = stream_getc (s);
+  rib->uptime = time (NULL);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop parse. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      nexthop_num = stream_getc (s);
+
+      for (i = 0; i < nexthop_num; i++)
+       {
+         nexthop_type = stream_getc (s);
+
+         switch (nexthop_type)
+           {
+           case ZEBRA_NEXTHOP_IFINDEX:
+             ifindex = stream_getl (s);
+             nexthop_ifindex_add (rib, ifindex);
+             break;
+           case ZEBRA_NEXTHOP_IFNAME:
+             ifname_len = stream_getc (s);
+             stream_forward (s, ifname_len);
+             break;
+           case ZEBRA_NEXTHOP_IPV4:
+             nexthop.s_addr = stream_get_ipv4 (s);
+             nexthop_ipv4_add (rib, &nexthop);
+             break;
+           case ZEBRA_NEXTHOP_IPV6:
+             stream_forward (s, IPV6_MAX_BYTELEN);
+             break;
+           case ZEBRA_NEXTHOP_BLACKHOLE:
+             nexthop_blackhole_add (rib);
+             break;
+           }
+       }
+    }
+
+  /* Distance. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+    rib->distance = stream_getc (s);
+
+  /* Metric. */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+    rib->metric = stream_getl (s);
+    
+  rib_add_ipv4_multipath (&p, rib);
+}
+
+/* Zebra server IPv4 prefix delete function. */
+void
+zread_ipv4_delete (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct zapi_ipv4 api;
+  struct in_addr nexthop;
+  unsigned long ifindex;
+  struct prefix_ipv4 p;
+  u_char nexthop_num;
+  u_char nexthop_type;
+  u_char ifname_len;
+  
+  s = client->ibuf;
+  ifindex = 0;
+  nexthop.s_addr = 0;
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      nexthop_num = stream_getc (s);
+
+      for (i = 0; i < nexthop_num; i++)
+       {
+         nexthop_type = stream_getc (s);
+
+         switch (nexthop_type)
+           {
+           case ZEBRA_NEXTHOP_IFINDEX:
+             ifindex = stream_getl (s);
+             break;
+           case ZEBRA_NEXTHOP_IFNAME:
+             ifname_len = stream_getc (s);
+             stream_forward (s, ifname_len);
+             break;
+           case ZEBRA_NEXTHOP_IPV4:
+             nexthop.s_addr = stream_get_ipv4 (s);
+             break;
+           case ZEBRA_NEXTHOP_IPV6:
+             stream_forward (s, IPV6_MAX_BYTELEN);
+             break;
+           }
+       }
+    }
+
+  /* Distance. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+
+  /* Metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+    
+  rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
+                  client->rtm_table);
+}
+
+/* Nexthop lookup for IPv4. */
+void
+zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
+{
+  struct in_addr addr;
+
+  addr.s_addr = stream_get_ipv4 (client->ibuf);
+  zsend_ipv4_nexthop_lookup (client, addr);
+}
+
+/* Nexthop lookup for IPv4. */
+void
+zread_ipv4_import_lookup (struct zserv *client, u_short length)
+{
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (client->ibuf);
+  p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
+
+  zsend_ipv4_import_lookup (client, &p);
+}
+
+#ifdef HAVE_IPV6
+/* Zebra server IPv6 prefix add function. */
+void
+zread_ipv6_add (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct zapi_ipv6 api;
+  struct in6_addr nexthop;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  
+  s = client->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      u_char nexthop_type;
+
+      api.nexthop_num = stream_getc (s);
+      for (i = 0; i < api.nexthop_num; i++)
+       {
+         nexthop_type = stream_getc (s);
+
+         switch (nexthop_type)
+           {
+           case ZEBRA_NEXTHOP_IPV6:
+             stream_get (&nexthop, s, 16);
+             break;
+           case ZEBRA_NEXTHOP_IFINDEX:
+             ifindex = stream_getl (s);
+             break;
+           }
+       }
+    }
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+    
+  if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
+    rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
+  else
+    rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+}
+
+/* Zebra server IPv6 prefix delete function. */
+void
+zread_ipv6_delete (struct zserv *client, u_short length)
+{
+  int i;
+  struct stream *s;
+  struct zapi_ipv6 api;
+  struct in6_addr nexthop;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  
+  s = client->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      u_char nexthop_type;
+
+      api.nexthop_num = stream_getc (s);
+      for (i = 0; i < api.nexthop_num; i++)
+       {
+         nexthop_type = stream_getc (s);
+
+         switch (nexthop_type)
+           {
+           case ZEBRA_NEXTHOP_IPV6:
+             stream_get (&nexthop, s, 16);
+             break;
+           case ZEBRA_NEXTHOP_IFINDEX:
+             ifindex = stream_getl (s);
+             break;
+           }
+       }
+    }
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+    
+  if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
+    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
+  else
+    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+}
+
+void
+zebra_read_ipv6 (int command, struct zserv *client, u_short length)
+{
+  u_char type;
+  u_char flags;
+  struct in6_addr nexthop, *gate;
+  u_char *lim;
+  u_char *pnt;
+  unsigned int ifindex;
+
+  pnt = stream_pnt (client->ibuf);
+  lim = pnt + length;
+
+  type = stream_getc (client->ibuf);
+  flags = stream_getc (client->ibuf);
+  stream_get (&nexthop, client->ibuf, sizeof (struct in6_addr));
+  
+  while (stream_pnt (client->ibuf) < lim)
+    {
+      int size;
+      struct prefix_ipv6 p;
+      
+      ifindex = stream_getl (client->ibuf);
+
+      memset (&p, 0, sizeof (struct prefix_ipv6));
+      p.family = AF_INET6;
+      p.prefixlen = stream_getc (client->ibuf);
+      size = PSIZE(p.prefixlen);
+      stream_get (&p.prefix, client->ibuf, size);
+
+      if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
+        gate = NULL;
+      else
+        gate = &nexthop;
+
+      if (command == ZEBRA_IPV6_ROUTE_ADD)
+       rib_add_ipv6 (type, flags, &p, gate, ifindex, 0);
+      else
+       rib_delete_ipv6 (type, flags, &p, gate, ifindex, 0);
+    }
+}
+
+void
+zread_ipv6_nexthop_lookup (struct zserv *client, u_short length)
+{
+  struct in6_addr addr;
+  char buf[BUFSIZ];
+
+  stream_get (&addr, client->ibuf, 16);
+  printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ));
+
+  zsend_ipv6_nexthop_lookup (client, &addr);
+}
+#endif /* HAVE_IPV6 */
+
+/* Close zebra client. */
+void
+zebra_client_close (struct zserv *client)
+{
+  /* Close file descriptor. */
+  if (client->sock)
+    {
+      close (client->sock);
+      client->sock = -1;
+    }
+
+  /* Free stream buffers. */
+  if (client->ibuf)
+    stream_free (client->ibuf);
+  if (client->obuf)
+    stream_free (client->obuf);
+
+  /* Release threads. */
+  if (client->t_read)
+    thread_cancel (client->t_read);
+  if (client->t_write)
+    thread_cancel (client->t_write);
+
+  /* Free client structure. */
+  listnode_delete (client_list, client);
+  XFREE (0, client);
+}
+
+/* Make new client. */
+void
+zebra_client_create (int sock)
+{
+  struct zserv *client;
+
+  client = XCALLOC (0, sizeof (struct zserv));
+
+  /* Make client input/output buffer. */
+  client->sock = sock;
+  client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+  client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+
+  /* Set table number. */
+  client->rtm_table = rtm_table_default;
+
+  /* Add this client to linked list. */
+  listnode_add (client_list, client);
+  
+  /* Make new read thread. */
+  zebra_event (ZEBRA_READ, sock, client);
+}
+
+/* Handler of zebra service request. */
+int
+zebra_client_read (struct thread *thread)
+{
+  int sock;
+  struct zserv *client;
+  int nbyte;
+  u_short length;
+  u_char command;
+
+  /* Get thread data.  Reset reading thread because I'm running. */
+  sock = THREAD_FD (thread);
+  client = THREAD_ARG (thread);
+  client->t_read = NULL;
+
+  /* Read length and command. */
+  nbyte = stream_read (client->ibuf, sock, 3);
+  if (nbyte <= 0) 
+    {
+      if (IS_ZEBRA_DEBUG_EVENT)
+       zlog_info ("connection closed socket [%d]", sock);
+      zebra_client_close (client);
+      return -1;
+    }
+  length = stream_getw (client->ibuf);
+  command = stream_getc (client->ibuf);
+
+  if (length < 3) 
+    {
+      if (IS_ZEBRA_DEBUG_EVENT)
+       zlog_info ("length %d is less than 3 ", length);
+      zebra_client_close (client);
+      return -1;
+    }
+
+  length -= 3;
+
+  /* Read rest of data. */
+  if (length)
+    {
+      nbyte = stream_read (client->ibuf, sock, length);
+      if (nbyte <= 0) 
+       {
+         if (IS_ZEBRA_DEBUG_EVENT)
+           zlog_info ("connection closed [%d] when reading zebra data", sock);
+         zebra_client_close (client);
+         return -1;
+       }
+    }
+
+  /* Debug packet information. */
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_info ("zebra message comes from socket [%d]", sock);
+
+  if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+    zlog_info ("zebra message received [%s] %d", 
+              zebra_command_str[command], length);
+
+  switch (command) 
+    {
+    case ZEBRA_INTERFACE_ADD:
+      zread_interface_add (client, length);
+      break;
+    case ZEBRA_INTERFACE_DELETE:
+      zread_interface_delete (client, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_ADD:
+      zread_ipv4_add (client, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_DELETE:
+      zread_ipv4_delete (client, length);
+      break;
+#ifdef HAVE_IPV6
+    case ZEBRA_IPV6_ROUTE_ADD:
+      zread_ipv6_add (client, length);
+      break;
+    case ZEBRA_IPV6_ROUTE_DELETE:
+      zread_ipv6_delete (client, length);
+      break;
+#endif /* HAVE_IPV6 */
+    case ZEBRA_REDISTRIBUTE_ADD:
+      zebra_redistribute_add (command, client, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_DELETE:
+      zebra_redistribute_delete (command, client, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_DEFAULT_ADD:
+      zebra_redistribute_default_add (command, client, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE:
+      zebra_redistribute_default_delete (command, client, length);
+      break;
+    case ZEBRA_IPV4_NEXTHOP_LOOKUP:
+      zread_ipv4_nexthop_lookup (client, length);
+      break;
+#ifdef HAVE_IPV6
+    case ZEBRA_IPV6_NEXTHOP_LOOKUP:
+      zread_ipv6_nexthop_lookup (client, length);
+      break;
+#endif /* HAVE_IPV6 */
+    case ZEBRA_IPV4_IMPORT_LOOKUP:
+      zread_ipv4_import_lookup (client, length);
+      break;
+    default:
+      zlog_info ("Zebra received unknown command %d", command);
+      break;
+    }
+
+  stream_reset (client->ibuf);
+  zebra_event (ZEBRA_READ, sock, client);
+
+  return 0;
+}
+
+/* Write output buffer to the socket. */
+void
+zebra_write (struct thread *thread)
+{
+  int sock;
+  struct zserv *client;
+
+  /* Thread treatment. */
+  sock = THREAD_FD (thread);
+  client = THREAD_ARG (thread);
+  client->t_write = NULL;
+
+  stream_flush (client->obuf, sock);
+}
+
+/* Accept code of zebra server socket. */
+int
+zebra_accept (struct thread *thread)
+{
+  int accept_sock;
+  int client_sock;
+  struct sockaddr_in client;
+  socklen_t len;
+
+  accept_sock = THREAD_FD (thread);
+
+  len = sizeof (struct sockaddr_in);
+  client_sock = accept (accept_sock, (struct sockaddr *) &client, &len);
+
+  if (client_sock < 0)
+    {
+      zlog_warn ("Can't accept zebra socket: %s", strerror (errno));
+      return -1;
+    }
+
+  /* Create new zebra client. */
+  zebra_client_create (client_sock);
+
+  /* Register myself. */
+  zebra_event (ZEBRA_SERV, accept_sock, NULL);
+
+  return 0;
+}
+
+/* Make zebra's server socket. */
+void
+zebra_serv ()
+{
+  int ret;
+  int accept_sock;
+  struct sockaddr_in addr;
+
+  accept_sock = socket (AF_INET, SOCK_STREAM, 0);
+
+  if (accept_sock < 0) 
+    {
+      zlog_warn ("Can't bind to socket: %s", strerror (errno));
+      zlog_warn ("zebra can't provice full functionality due to above error");
+      return;
+    }
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (ZEBRA_PORT);
+#ifdef HAVE_SIN_LEN
+  addr.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  sockopt_reuseaddr (accept_sock);
+  sockopt_reuseport (accept_sock);
+
+  ret  = bind (accept_sock, (struct sockaddr *)&addr, 
+              sizeof (struct sockaddr_in));
+  if (ret < 0)
+    {
+      zlog_warn ("Can't bind to socket: %s", strerror (errno));
+      zlog_warn ("zebra can't provice full functionality due to above error");
+      close (accept_sock);      /* Avoid sd leak. */
+      return;
+    }
+
+  ret = listen (accept_sock, 1);
+  if (ret < 0)
+    {
+      zlog_warn ("Can't listen to socket: %s", strerror (errno));
+      zlog_warn ("zebra can't provice full functionality due to above error");
+      close (accept_sock);     /* Avoid sd leak. */
+      return;
+    }
+
+  zebra_event (ZEBRA_SERV, accept_sock, NULL);
+}
+
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+/* zebra server UNIX domain socket. */
+void
+zebra_serv_un (char *path)
+{
+  int ret;
+  int sock, len;
+  struct sockaddr_un serv;
+  mode_t old_mask;
+
+  /* First of all, unlink existing socket */
+  unlink (path);
+
+  /* Set umask */
+  old_mask = umask (0077);
+
+  /* Make UNIX domain socket. */
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      perror ("sock");
+      return;
+    }
+
+  /* Make server socket. */
+  memset (&serv, 0, sizeof (struct sockaddr_un));
+  serv.sun_family = AF_UNIX;
+  strncpy (serv.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+  len = serv.sun_len = SUN_LEN(&serv);
+#else
+  len = sizeof (serv.sun_family) + strlen (serv.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+  ret = bind (sock, (struct sockaddr *) &serv, len);
+  if (ret < 0)
+    {
+      perror ("bind");
+      close (sock);
+      return;
+    }
+
+  ret = listen (sock, 5);
+  if (ret < 0)
+    {
+      perror ("listen");
+      close (sock);
+      return;
+    }
+
+  umask (old_mask);
+
+  zebra_event (ZEBRA_SERV, sock, NULL);
+}
+\f
+/* Zebra's event management function. */
+extern struct thread_master *master;
+
+void
+zebra_event (enum event event, int sock, struct zserv *client)
+{
+  switch (event)
+    {
+    case ZEBRA_SERV:
+      thread_add_read (master, zebra_accept, client, sock);
+      break;
+    case ZEBRA_READ:
+      client->t_read = 
+       thread_add_read (master, zebra_client_read, client, sock);
+      break;
+    case ZEBRA_WRITE:
+      /**/
+      break;
+    }
+}
+\f
+/* Display default rtm_table for all clients. */
+DEFUN (show_table,
+       show_table_cmd,
+       "show table",
+       SHOW_STR
+       "default routing table to use for all clients\n")
+{
+  vty_out (vty, "table %d%s", rtm_table_default,
+          VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_table, 
+       config_table_cmd,
+       "table TABLENO",
+       "Configure target kernel routing table\n"
+       "TABLE integer\n")
+{
+  rtm_table_default = strtol (argv[0], (char**)0, 10);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_forwarding,
+       no_ip_forwarding_cmd,
+       "no ip forwarding",
+       NO_STR
+       IP_STR
+       "Turn off IP forwarding")
+{
+  int ret;
+
+  ret = ipforward ();
+
+  if (ret == 0)
+    {
+      vty_out (vty, "IP forwarding is already off%s", VTY_NEWLINE); 
+      return CMD_ERR_NOTHING_TODO;
+    }
+
+  ret = ipforward_off ();
+  if (ret != 0)
+    {
+      vty_out (vty, "Can't turn off IP forwarding%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* This command is for debugging purpose. */
+DEFUN (show_zebra_client,
+       show_zebra_client_cmd,
+       "show zebra client",
+       SHOW_STR
+       "Zebra information"
+       "Client information")
+{
+  listnode node;
+  struct zserv *client;
+
+  for (node = listhead (client_list); node; nextnode (node))
+    {
+      client = getdata (node);
+      vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+/* Table configuration write function. */
+int
+config_write_table (struct vty *vty)
+{
+  if (rtm_table_default)
+    vty_out (vty, "table %d%s", rtm_table_default,
+            VTY_NEWLINE);
+  return 0;
+}
+
+/* table node for routing tables. */
+struct cmd_node table_node =
+{
+  TABLE_NODE,
+  "",                          /* This node has no interface. */
+  1
+};
+\f
+/* Only display ip forwarding is enabled or not. */
+DEFUN (show_ip_forwarding,
+       show_ip_forwarding_cmd,
+       "show ip forwarding",
+       SHOW_STR
+       IP_STR
+       "IP forwarding status\n")
+{
+  int ret;
+
+  ret = ipforward ();
+
+  if (ret == 0)
+    vty_out (vty, "IP forwarding is off%s", VTY_NEWLINE);
+  else
+    vty_out (vty, "IP forwarding is on%s", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Only display ipv6 forwarding is enabled or not. */
+DEFUN (show_ipv6_forwarding,
+       show_ipv6_forwarding_cmd,
+       "show ipv6 forwarding",
+       SHOW_STR
+       "IPv6 information\n"
+       "Forwarding status\n")
+{
+  int ret;
+
+  ret = ipforward_ipv6 ();
+
+  switch (ret)
+    {
+    case -1:
+      vty_out (vty, "ipv6 forwarding is unknown%s", VTY_NEWLINE);
+      break;
+    case 0:
+      vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE);
+      break;
+    case 1:
+      vty_out (vty, "ipv6 forwarding is %s%s", "on", VTY_NEWLINE);
+      break;
+    default:
+      vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE);
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_forwarding,
+       no_ipv6_forwarding_cmd,
+       "no ipv6 forwarding",
+       NO_STR
+       IP_STR
+       "Doesn't forward IPv6 protocol packet")
+{
+  int ret;
+
+  ret = ipforward_ipv6_off ();
+  if (ret != 0)
+    {
+      vty_out (vty, "Can't turn off IPv6 forwarding%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+#endif /* HAVE_IPV6 */
+
+/* IPForwarding configuration write function. */
+int
+config_write_forwarding (struct vty *vty)
+{
+  if (! ipforward ())
+    vty_out (vty, "no ip forwarding%s", VTY_NEWLINE);
+#ifdef HAVE_IPV6
+  if (! ipforward_ipv6 ())
+    vty_out (vty, "no ipv6 forwarding%s", VTY_NEWLINE);
+#endif /* HAVE_IPV6 */
+  vty_out (vty, "!%s", VTY_NEWLINE);
+  return 0;
+}
+
+/* table node for routing tables. */
+struct cmd_node forwarding_node =
+{
+  FORWARDING_NODE,
+  "",                          /* This node has no interface. */
+  1
+};
+
+\f
+/* Initialisation of zebra and installation of commands. */
+void
+zebra_init ()
+{
+  /* Client list init. */
+  client_list = list_new ();
+
+  /* Forwarding is on by default. */
+  ipforward_on ();
+#ifdef HAVE_IPV6
+  ipforward_ipv6_on ();
+#endif /* HAVE_IPV6 */
+
+  /* Make zebra server socket. */
+#ifdef HAVE_TCP_ZEBRA
+  zebra_serv ();
+#else
+  zebra_serv_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+
+  /* Install configuration write function. */
+  install_node (&table_node, config_write_table);
+  install_node (&forwarding_node, config_write_forwarding);
+
+  install_element (VIEW_NODE, &show_ip_forwarding_cmd);
+  install_element (ENABLE_NODE, &show_ip_forwarding_cmd);
+  install_element (CONFIG_NODE, &no_ip_forwarding_cmd);
+  install_element (ENABLE_NODE, &show_zebra_client_cmd);
+
+#ifdef HAVE_NETLINK
+  install_element (VIEW_NODE, &show_table_cmd);
+  install_element (ENABLE_NODE, &show_table_cmd);
+  install_element (CONFIG_NODE, &config_table_cmd);
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_IPV6
+  install_element (VIEW_NODE, &show_ipv6_forwarding_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd);
+#endif /* HAVE_IPV6 */
+}
diff --git a/zebra/zserv.h b/zebra/zserv.h
new file mode 100644 (file)
index 0000000..c762280
--- /dev/null
@@ -0,0 +1,132 @@
+/* Zebra daemon server header.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef _ZEBRA_ZSERV_H
+#define _ZEBRA_ZSERV_H
+
+/* Default port information. */
+#define ZEBRA_PORT                    2600
+#define ZEBRA_VTY_PORT                2601
+#define ZEBRA_VTYSH_PATH              "/tmp/.zebra"
+#define ZEBRA_SERV_PATH               "/tmp/.zserv"
+
+/* Default configuration filename. */
+#define DEFAULT_CONFIG_FILE "zebra.conf"
+
+/* Client structure. */
+struct zserv
+{
+  /* Client file descriptor. */
+  int sock;
+
+  /* Input/output buffer to the client. */
+  struct stream *ibuf;
+  struct stream *obuf;
+
+  /* Threads for read/write. */
+  struct thread *t_read;
+  struct thread *t_write;
+
+  /* default routing table this client munges */
+  int rtm_table;
+
+  /* This client's redistribute flag. */
+  u_char redist[ZEBRA_ROUTE_MAX];
+
+  /* Redistribute default route flag. */
+  u_char redist_default;
+
+  /* Interface information. */
+  u_char ifinfo;
+};
+
+/* Count prefix size from mask length */
+#define PSIZE(a) (((a) + 7) / (8))
+
+/* Prototypes. */
+void zebra_init ();
+void zebra_if_init ();
+void hostinfo_get ();
+void rib_init ();
+void interface_list ();
+void kernel_init ();
+void route_read ();
+void rtadv_init ();
+void zebra_snmp_init ();
+
+int
+zsend_interface_add (struct zserv *, struct interface *);
+int
+zsend_interface_delete (struct zserv *, struct interface *);
+
+int
+zsend_interface_address_add (struct zserv *, struct interface *,
+                            struct connected *);
+
+int
+zsend_interface_address_delete (struct zserv *, struct interface *,
+                               struct connected *);
+
+int
+zsend_interface_up (struct zserv *, struct interface *);
+
+int
+zsend_interface_down (struct zserv *, struct interface *);
+
+int
+zsend_ipv4_add (struct zserv *client, int type, int flags,
+               struct prefix_ipv4 *p, struct in_addr *nexthop,
+               unsigned int ifindex);
+
+int
+zsend_ipv4_delete (struct zserv *client, int type, int flags,
+                  struct prefix_ipv4 *p, struct in_addr *nexthop,
+                  unsigned int ifindex);
+
+int
+zsend_ipv4_add_multipath (struct zserv *, struct prefix *, struct rib *);
+
+int
+zsend_ipv4_delete_multipath (struct zserv *, struct prefix *, struct rib *);
+
+#ifdef HAVE_IPV6
+int
+zsend_ipv6_add (struct zserv *client, int type, int flags,
+               struct prefix_ipv6 *p, struct in6_addr *nexthop,
+               unsigned int ifindex);
+
+int
+zsend_ipv6_delete (struct zserv *client, int type, int flags,
+                  struct prefix_ipv6 *p, struct in6_addr *nexthop,
+                  unsigned int ifindex);
+
+int
+zsend_ipv6_add_multipath (struct zserv *, struct prefix *, struct rib *);
+
+int
+zsend_ipv6_delete_multipath (struct zserv *, struct prefix *, struct rib *);
+
+#endif /* HAVE_IPV6 */
+
+extern pid_t pid;
+extern pid_t old_pid;
+
+#endif /* _ZEBRA_ZEBRA_H */